From webhook-mailer at python.org Mon May 1 00:36:28 2023 From: webhook-mailer at python.org (terryjreedy) Date: Mon, 01 May 2023 04:36:28 -0000 Subject: [Python-checkins] [3.11] gh-88496: Fix IDLE test hang on macOS (GH-104025) (#104027) Message-ID: https://github.com/python/cpython/commit/2e5f1a12597faba0fc24243ee384a7c6fe8fecbf commit: 2e5f1a12597faba0fc24243ee384a7c6fe8fecbf branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy date: 2023-05-01T00:36:21-04:00 summary: [3.11] gh-88496: Fix IDLE test hang on macOS (GH-104025) (#104027) gh-88496: Fix IDLE test hang on macOS (GH-104025) Replace widget.update() with widget.update_idletasks in two places. (cherry picked from commit 4b27972f5fe816d3616f97f8643d8ad922473ab5) Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst M Lib/idlelib/colorizer.py M Lib/idlelib/outwin.py diff --git a/Lib/idlelib/colorizer.py b/Lib/idlelib/colorizer.py index e9f19c145c86..b4df353012b7 100644 --- a/Lib/idlelib/colorizer.py +++ b/Lib/idlelib/colorizer.py @@ -310,7 +310,7 @@ def recolorize_main(self): # crumb telling the next invocation to resume here # in case update tells us to leave. self.tag_add("TODO", next) - self.update() + self.update_idletasks() if self.stop_colorizing: if DEBUG: print("colorizing stopped") return diff --git a/Lib/idlelib/outwin.py b/Lib/idlelib/outwin.py index ac67c904ab97..610031e26f1d 100644 --- a/Lib/idlelib/outwin.py +++ b/Lib/idlelib/outwin.py @@ -112,7 +112,7 @@ def write(self, s, tags=(), mark="insert"): assert isinstance(s, str) self.text.insert(mark, s, tags) self.text.see(mark) - self.text.update() + self.text.update_idletasks() return len(s) def writelines(self, lines): diff --git a/Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst b/Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst new file mode 100644 index 000000000000..4f390d189d23 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst @@ -0,0 +1 @@ +Fix IDLE test hang on macOS. From webhook-mailer at python.org Mon May 1 01:47:41 2023 From: webhook-mailer at python.org (vsajip) Date: Mon, 01 May 2023 05:47:41 -0000 Subject: [Python-checkins] Adjust expression from `==` to `!=` in alignment with the meaning of the paragraph. (GH-104021) Message-ID: https://github.com/python/cpython/commit/93107aa2a49a9354ffb10b3cd263dc3e99ebdeff commit: 93107aa2a49a9354ffb10b3cd263dc3e99ebdeff branch: main author: Ben Faulhaber <111227622+faulhaberben at users.noreply.github.com> committer: vsajip date: 2023-05-01T06:47:34+01:00 summary: Adjust expression from `==` to `!=` in alignment with the meaning of the paragraph. (GH-104021) files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 52bf99e5bb0f..9e5672545dea 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -55,7 +55,7 @@ point to the directories of the virtual environment, whereas :data:`sys.base_prefix` and :data:`sys.base_exec_prefix` point to those of the base Python used to create the environment. It is sufficient to check -``sys.prefix == sys.base_prefix`` to determine if the current interpreter is +``sys.prefix != sys.base_prefix`` to determine if the current interpreter is running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory From webhook-mailer at python.org Mon May 1 01:58:40 2023 From: webhook-mailer at python.org (vsajip) Date: Mon, 01 May 2023 05:58:40 -0000 Subject: [Python-checkins] [3.11] Adjust expression from `==` to `!=` in alignment with the meaning of the paragraph. (GH-104021) (GH-104031) Message-ID: https://github.com/python/cpython/commit/d8055b889ca2a931af1288d140c7e471700a41d2 commit: d8055b889ca2a931af1288d140c7e471700a41d2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2023-05-01T06:58:33+01:00 summary: [3.11] Adjust expression from `==` to `!=` in alignment with the meaning of the paragraph. (GH-104021) (GH-104031) (cherry picked from commit 93107aa2a49a9354ffb10b3cd263dc3e99ebdeff) files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index ff3c4b514b59..07a6f5f8920f 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -55,7 +55,7 @@ point to the directories of the virtual environment, whereas :data:`sys.base_prefix` and :data:`sys.base_exec_prefix` point to those of the base Python used to create the environment. It is sufficient to check -``sys.prefix == sys.base_prefix`` to determine if the current interpreter is +``sys.prefix != sys.base_prefix`` to determine if the current interpreter is running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory From webhook-mailer at python.org Mon May 1 03:32:36 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 01 May 2023 07:32:36 -0000 Subject: [Python-checkins] gh-103895: Improve how invalid `Exception.__notes__` are displayed (#103897) Message-ID: https://github.com/python/cpython/commit/487f55d5801a9ae7d79d37e259e8c377c9acd39b commit: 487f55d5801a9ae7d79d37e259e8c377c9acd39b branch: main author: Carey Metcalfe committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-01T08:32:04+01:00 summary: gh-103895: Improve how invalid `Exception.__notes__` are displayed (#103897) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst M Lib/test/test_traceback.py M Lib/traceback.py M Python/pythonrun.c diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 5e2b35378299..19a2be88d2c1 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1539,11 +1539,11 @@ def __repr__(self): e.__notes__ = BadThing() notes_repr = 'bad repr' - self.assertEqual(self.get_report(e), vanilla + notes_repr) + self.assertEqual(self.get_report(e), vanilla + notes_repr + '\n') e.__notes__ = Unprintable() err_msg = '<__notes__ repr() failed>' - self.assertEqual(self.get_report(e), vanilla + err_msg) + self.assertEqual(self.get_report(e), vanilla + err_msg + '\n') # non-string item in the __notes__ sequence e.__notes__ = [BadThing(), 'Final Note'] @@ -1555,6 +1555,14 @@ def __repr__(self): err_msg = '' self.assertEqual(self.get_report(e), vanilla + err_msg + '\nFinal Note\n') + e.__notes__ = "please do not explode me" + err_msg = "'please do not explode me'" + self.assertEqual(self.get_report(e), vanilla + err_msg + '\n') + + e.__notes__ = b"please do not show me as numbers" + err_msg = "b'please do not show me as numbers'" + self.assertEqual(self.get_report(e), vanilla + err_msg + '\n') + def test_exception_with_note_with_multiple_notes(self): e = ValueError(42) vanilla = self.get_report(e) diff --git a/Lib/traceback.py b/Lib/traceback.py index 9e720ac9948f..ba4a9ffd001b 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -852,12 +852,16 @@ def format_exception_only(self): yield _format_final_exc_line(stype, self._str) else: yield from self._format_syntax_error(stype) - if isinstance(self.__notes__, collections.abc.Sequence): + + if ( + isinstance(self.__notes__, collections.abc.Sequence) + and not isinstance(self.__notes__, (str, bytes)) + ): for note in self.__notes__: note = _safe_string(note, 'note') yield from [l + '\n' for l in note.split('\n')] elif self.__notes__ is not None: - yield _safe_string(self.__notes__, '__notes__', func=repr) + yield "{}\n".format(_safe_string(self.__notes__, '__notes__', func=repr)) def _format_syntax_error(self, stype): """Format SyntaxError exceptions (internal helper).""" diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst new file mode 100644 index 000000000000..6fed304c9132 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst @@ -0,0 +1,3 @@ +Improve handling of edge cases in showing ``Exception.__notes__``. Ensures +that the messages always end with a newline and that string/bytes are not +exploded over multiple lines. Patch by Carey Metcalfe. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index b16d3f53f89f..05e7b4370869 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1107,7 +1107,7 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) if (notes == NULL) { return -1; } - if (!PySequence_Check(notes)) { + if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) { int res = 0; if (write_indented_margin(ctx, f) < 0) { res = -1; @@ -1122,6 +1122,9 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) Py_DECREF(s); } Py_DECREF(notes); + if (PyFile_WriteString("\n", f) < 0) { + res = -1; + } return res; } Py_ssize_t num_notes = PySequence_Length(notes); From webhook-mailer at python.org Mon May 1 06:10:59 2023 From: webhook-mailer at python.org (Fidget-Spinner) Date: Mon, 01 May 2023 10:10:59 -0000 Subject: [Python-checkins] gh-102213: Optimize the performance of `__getattr__` (GH-103761) Message-ID: https://github.com/python/cpython/commit/59c27fa5cb95e2d608747a50fc675bbe2fc96beb commit: 59c27fa5cb95e2d608747a50fc675bbe2fc96beb branch: main author: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> committer: Fidget-Spinner date: 2023-05-01T18:10:35+08:00 summary: gh-102213: Optimize the performance of `__getattr__` (GH-103761) Co-authored-by: Kirill <80244920+Eclips4 at users.noreply.github.com> Co-authored-by: ?ukasz Langa Co-authored-by: Xiang Wang <34048878+wangxiang-hz at users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst M Lib/test/test_descr.py M Objects/typeobject.c diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index f17bb1813b9d..ad3eefba3658 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -5004,7 +5004,7 @@ class Child(Parent): self.assertEqual(Parent.__subclasses__(), []) def test_attr_raise_through_property(self): - # add test case for gh-103272 + # test case for gh-103272 class A: def __getattr__(self, name): raise ValueError("FOO") @@ -5016,6 +5016,19 @@ def foo(self): with self.assertRaisesRegex(ValueError, "FOO"): A().foo + # test case for gh-103551 + class B: + @property + def __getattr__(self, name): + raise ValueError("FOO") + + @property + def foo(self): + raise NotImplementedError("BAR") + + with self.assertRaisesRegex(NotImplementedError, "BAR"): + B().foo + class DictProxyTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst new file mode 100644 index 000000000000..997bef226e71 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst @@ -0,0 +1 @@ +Fix performance loss when accessing an object's attributes with ``__getattr__`` defined. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 38b99315457a..e807cc90faa1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8306,17 +8306,23 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) if (getattribute == NULL || (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && ((PyWrapperDescrObject *)getattribute)->d_wrapped == - (void *)PyObject_GenericGetAttr)) - res = PyObject_GenericGetAttr(self, name); - else { + (void *)PyObject_GenericGetAttr)) { + res = _PyObject_GenericGetAttrWithDict(self, name, NULL, 1); + /* if res == NULL with no exception set, then it must be an + AttributeError suppressed by us. */ + if (res == NULL && !PyErr_Occurred()) { + res = call_attribute(self, getattr, name); + } + } else { Py_INCREF(getattribute); res = call_attribute(self, getattribute, name); Py_DECREF(getattribute); + if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + res = call_attribute(self, getattr, name); + } } - if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - res = call_attribute(self, getattr, name); - } + Py_DECREF(getattr); return res; } From webhook-mailer at python.org Mon May 1 09:43:06 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 01 May 2023 13:43:06 -0000 Subject: [Python-checkins] gh-104036: Fix direct invocation of test_typing (#104037) Message-ID: https://github.com/python/cpython/commit/4181d078fc945313568eb39965cb9190881606b5 commit: 4181d078fc945313568eb39965cb9190881606b5 branch: main author: Kirill Podoprigora <80244920+Eclips4 at users.noreply.github.com> committer: AlexWaygood date: 2023-05-01T13:42:59Z summary: gh-104036: Fix direct invocation of test_typing (#104037) Previously, `python -m test test_typing` worked, but `python Lib/test/test_typing.py` did not. files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f36bb958c88e..7c6a521c3c48 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -117,7 +117,7 @@ def test_repr(self): class Sub(Any): pass self.assertEqual( repr(Sub), - ".Sub'>", + f".Sub'>", ) def test_errors(self): From webhook-mailer at python.org Mon May 1 10:03:31 2023 From: webhook-mailer at python.org (corona10) Date: Mon, 01 May 2023 14:03:31 -0000 Subject: [Python-checkins] gh-104028: Reduce object creation while calling callback function from gc (gh-104030) Message-ID: https://github.com/python/cpython/commit/e1476942525ae847875dab55541bef4a8a99dd3d commit: e1476942525ae847875dab55541bef4a8a99dd3d branch: main author: Dong-hee Na committer: corona10 date: 2023-05-01T14:03:24Z summary: gh-104028: Reduce object creation while calling callback function from gc (gh-104030) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst M Modules/gcmodule.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst new file mode 100644 index 000000000000..9c35ea88499d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst @@ -0,0 +1,2 @@ +Reduce object creation while calling callback function from gc. +Patch by Dong-hee Na. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 966c1e615502..3fd5f4cd70e8 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1388,10 +1388,19 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, return; } } + + PyObject *phase_obj = PyUnicode_FromString(phase); + if (phase_obj == NULL) { + Py_XDECREF(info); + PyErr_WriteUnraisable(NULL); + return; + } + + PyObject *stack[] = {phase_obj, info}; for (Py_ssize_t i=0; icallbacks); i++) { PyObject *r, *cb = PyList_GET_ITEM(gcstate->callbacks, i); Py_INCREF(cb); /* make sure cb doesn't go away */ - r = PyObject_CallFunction(cb, "sO", phase, info); + r = PyObject_Vectorcall(cb, stack, 2, NULL); if (r == NULL) { PyErr_WriteUnraisable(cb); } @@ -1400,6 +1409,7 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, } Py_DECREF(cb); } + Py_DECREF(phase_obj); Py_XDECREF(info); assert(!_PyErr_Occurred(tstate)); } From webhook-mailer at python.org Mon May 1 10:17:19 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 01 May 2023 14:17:19 -0000 Subject: [Python-checkins] [3.11] gh-104036: Fix direct invocation of test_typing (GH-104037) (#104039) Message-ID: https://github.com/python/cpython/commit/1be8bed236e841f33e10092aa2e774dd90d74c9b commit: 1be8bed236e841f33e10092aa2e774dd90d74c9b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2023-05-01T14:17:12Z summary: [3.11] gh-104036: Fix direct invocation of test_typing (GH-104037) (#104039) gh-104036: Fix direct invocation of test_typing (GH-104037) Previously, `python -m test test_typing` worked, but `python Lib/test/test_typing.py` did not. (cherry picked from commit 4181d078fc945313568eb39965cb9190881606b5) Co-authored-by: Kirill Podoprigora <80244920+Eclips4 at users.noreply.github.com> files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 79fba267b4bc..e46a6ca06200 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -114,7 +114,7 @@ def test_repr(self): class Sub(Any): pass self.assertEqual( repr(Sub), - ".Sub'>", + f".Sub'>", ) def test_errors(self): From webhook-mailer at python.org Mon May 1 11:19:16 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 01 May 2023 15:19:16 -0000 Subject: [Python-checkins] gh-104035: Do not ignore user-defined `__{get, set}state__` in slotted frozen dataclasses (#104041) Message-ID: https://github.com/python/cpython/commit/99aab610622fc4b4c4fe56b77c0760cf77066a53 commit: 99aab610622fc4b4c4fe56b77c0760cf77066a53 branch: main author: Nikita Sobolev committer: carljm date: 2023-05-01T09:19:06-06:00 summary: gh-104035: Do not ignore user-defined `__{get,set}state__` in slotted frozen dataclasses (#104041) files: A Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index a73cdc22a5f4..b0b8a773b759 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1227,8 +1227,10 @@ def _add_slots(cls, is_frozen, weakref_slot): if is_frozen: # Need this for pickling frozen classes with slots. - cls.__getstate__ = _dataclass_getstate - cls.__setstate__ = _dataclass_setstate + if '__getstate__' not in cls_dict: + cls.__getstate__ = _dataclass_getstate + if '__setstate__' not in cls_dict: + cls.__setstate__ = _dataclass_setstate return cls diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 7b48b26f9e77..6669f1c57e2e 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3184,6 +3184,74 @@ def test_frozen_pickle(self): self.assertIsNot(obj, p) self.assertEqual(obj, p) + @dataclass(frozen=True, slots=True) + class FrozenSlotsGetStateClass: + foo: str + bar: int + + getstate_called: bool = field(default=False, compare=False) + + def __getstate__(self): + object.__setattr__(self, 'getstate_called', True) + return [self.foo, self.bar] + + @dataclass(frozen=True, slots=True) + class FrozenSlotsSetStateClass: + foo: str + bar: int + + setstate_called: bool = field(default=False, compare=False) + + def __setstate__(self, state): + object.__setattr__(self, 'setstate_called', True) + object.__setattr__(self, 'foo', state[0]) + object.__setattr__(self, 'bar', state[1]) + + @dataclass(frozen=True, slots=True) + class FrozenSlotsAllStateClass: + foo: str + bar: int + + getstate_called: bool = field(default=False, compare=False) + setstate_called: bool = field(default=False, compare=False) + + def __getstate__(self): + object.__setattr__(self, 'getstate_called', True) + return [self.foo, self.bar] + + def __setstate__(self, state): + object.__setattr__(self, 'setstate_called', True) + object.__setattr__(self, 'foo', state[0]) + object.__setattr__(self, 'bar', state[1]) + + def test_frozen_slots_pickle_custom_state(self): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + obj = self.FrozenSlotsGetStateClass('a', 1) + dumped = pickle.dumps(obj, protocol=proto) + + self.assertTrue(obj.getstate_called) + self.assertEqual(obj, pickle.loads(dumped)) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + obj = self.FrozenSlotsSetStateClass('a', 1) + obj2 = pickle.loads(pickle.dumps(obj, protocol=proto)) + + self.assertTrue(obj2.setstate_called) + self.assertEqual(obj, obj2) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + obj = self.FrozenSlotsAllStateClass('a', 1) + dumped = pickle.dumps(obj, protocol=proto) + + self.assertTrue(obj.getstate_called) + + obj2 = pickle.loads(dumped) + self.assertTrue(obj2.setstate_called) + self.assertEqual(obj, obj2) + def test_slots_with_default_no_init(self): # Originally reported in bpo-44649. @dataclass(slots=True) diff --git a/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst b/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst new file mode 100644 index 000000000000..8c8e3d6ba5fb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst @@ -0,0 +1,2 @@ +Do not ignore user-defined ``__getstate__`` and ``__setstate__`` methods for +slotted frozen dataclasses. From webhook-mailer at python.org Mon May 1 11:26:50 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 01 May 2023 15:26:50 -0000 Subject: [Python-checkins] gh-103824: fix use-after-free error in Parser/tokenizer.c (#103993) Message-ID: https://github.com/python/cpython/commit/d5a97074d24cd14cb2a35a2b1ad3074863cde264 commit: d5a97074d24cd14cb2a35a2b1ad3074863cde264 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: pablogsal date: 2023-05-01T15:26:43Z summary: gh-103824: fix use-after-free error in Parser/tokenizer.c (#103993) files: M Lib/test/test_tokenize.py M Parser/tokenizer.c diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 283a7c23609e..911b53e58165 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -11,7 +11,7 @@ from test.test_grammar import (VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS) from test.support import os_helper -from test.support.script_helper import run_test_script, make_script +from test.support.script_helper import run_test_script, make_script, run_python_until_end import os import token @@ -1470,6 +1470,19 @@ def test_comment_at_the_end_of_the_source_without_newline(self): self.assertEqual(tok_name[tokens[i + 1].exact_type], tok_name[expected_tokens[i]]) self.assertEqual(tok_name[tokens[-1].exact_type], tok_name[token.ENDMARKER]) + def test_invalid_character_in_fstring_middle(self): + # See gh-103824 + script = b'''F""" + \xe5"""''' + + with os_helper.temp_dir() as temp_dir: + filename = os.path.join(temp_dir, "script.py") + with open(filename, 'wb') as file: + file.write(script) + rs, _ = run_python_until_end(filename) + self.assertIn(b"SyntaxError", rs.err) + + class UntokenizeTest(TestCase): def test_bad_input_order(self): diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 8de0572a1fc4..8fb9be7bfd01 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2552,6 +2552,10 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct 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')) { + if (tok->decoding_erred) { + return MAKE_TOKEN(ERRORTOKEN); + } + assert(tok->multi_line_start != NULL); // shift the tok_state's location into // the start of string, and report the error From webhook-mailer at python.org Mon May 1 11:46:19 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 01 May 2023 15:46:19 -0000 Subject: [Python-checkins] Fix typo in "expected" word in few source files (#104034) Message-ID: https://github.com/python/cpython/commit/2a884ceb36e799c900129d4b5b6248262004efb5 commit: 2a884ceb36e799c900129d4b5b6248262004efb5 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: carljm date: 2023-05-01T09:45:50-06:00 summary: Fix typo in "expected" word in few source files (#104034) files: M Include/unicodeobject.h M Modules/_ctypes/callproc.c diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h index 74474f5bb8f9..5839c747a292 100644 --- a/Include/unicodeobject.h +++ b/Include/unicodeobject.h @@ -626,7 +626,7 @@ PyAPI_FUNC(PyObject*) PyUnicode_AsLatin1String( /* --- ASCII Codecs ------------------------------------------------------- - Only 7-bit ASCII data is excepted. All other codes generate errors. + Only 7-bit ASCII data is expected. All other codes generate errors. */ diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 93bc784df538..f10cf58216ac 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1823,7 +1823,7 @@ resize(PyObject *self, PyObject *args) dict = PyObject_stgdict((PyObject *)obj); if (dict == NULL) { PyErr_SetString(PyExc_TypeError, - "excepted ctypes instance"); + "expected ctypes instance"); return NULL; } if (size < dict->size) { From webhook-mailer at python.org Mon May 1 12:02:49 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 01 May 2023 16:02:49 -0000 Subject: [Python-checkins] [3.11] gh-104035: Do not ignore user-defined `__{get, set}state__` in slotted frozen dataclasses (GH-104041) (#104044) Message-ID: https://github.com/python/cpython/commit/0df7c3a466c4d5b65ce619952009477fba1e91e9 commit: 0df7c3a466c4d5b65ce619952009477fba1e91e9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-05-01T10:02:41-06:00 summary: [3.11] gh-104035: Do not ignore user-defined `__{get,set}state__` in slotted frozen dataclasses (GH-104041) (#104044) gh-104035: Do not ignore user-defined `__{get,set}state__` in slotted frozen dataclasses (GH-104041) (cherry picked from commit 99aab610622fc4b4c4fe56b77c0760cf77066a53) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index a7e0547705ca..148daf45330c 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1191,8 +1191,10 @@ def _add_slots(cls, is_frozen, weakref_slot): if is_frozen: # Need this for pickling frozen classes with slots. - cls.__getstate__ = _dataclass_getstate - cls.__setstate__ = _dataclass_setstate + if '__getstate__' not in cls_dict: + cls.__getstate__ = _dataclass_getstate + if '__setstate__' not in cls_dict: + cls.__setstate__ = _dataclass_setstate return cls diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 1aaa78db4b0a..4714d0bca861 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3068,6 +3068,74 @@ def test_frozen_pickle(self): self.assertIsNot(obj, p) self.assertEqual(obj, p) + @dataclass(frozen=True, slots=True) + class FrozenSlotsGetStateClass: + foo: str + bar: int + + getstate_called: bool = field(default=False, compare=False) + + def __getstate__(self): + object.__setattr__(self, 'getstate_called', True) + return [self.foo, self.bar] + + @dataclass(frozen=True, slots=True) + class FrozenSlotsSetStateClass: + foo: str + bar: int + + setstate_called: bool = field(default=False, compare=False) + + def __setstate__(self, state): + object.__setattr__(self, 'setstate_called', True) + object.__setattr__(self, 'foo', state[0]) + object.__setattr__(self, 'bar', state[1]) + + @dataclass(frozen=True, slots=True) + class FrozenSlotsAllStateClass: + foo: str + bar: int + + getstate_called: bool = field(default=False, compare=False) + setstate_called: bool = field(default=False, compare=False) + + def __getstate__(self): + object.__setattr__(self, 'getstate_called', True) + return [self.foo, self.bar] + + def __setstate__(self, state): + object.__setattr__(self, 'setstate_called', True) + object.__setattr__(self, 'foo', state[0]) + object.__setattr__(self, 'bar', state[1]) + + def test_frozen_slots_pickle_custom_state(self): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + obj = self.FrozenSlotsGetStateClass('a', 1) + dumped = pickle.dumps(obj, protocol=proto) + + self.assertTrue(obj.getstate_called) + self.assertEqual(obj, pickle.loads(dumped)) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + obj = self.FrozenSlotsSetStateClass('a', 1) + obj2 = pickle.loads(pickle.dumps(obj, protocol=proto)) + + self.assertTrue(obj2.setstate_called) + self.assertEqual(obj, obj2) + + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + obj = self.FrozenSlotsAllStateClass('a', 1) + dumped = pickle.dumps(obj, protocol=proto) + + self.assertTrue(obj.getstate_called) + + obj2 = pickle.loads(dumped) + self.assertTrue(obj2.setstate_called) + self.assertEqual(obj, obj2) + def test_slots_with_default_no_init(self): # Originally reported in bpo-44649. @dataclass(slots=True) diff --git a/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst b/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst new file mode 100644 index 000000000000..8c8e3d6ba5fb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst @@ -0,0 +1,2 @@ +Do not ignore user-defined ``__getstate__`` and ``__setstate__`` methods for +slotted frozen dataclasses. From webhook-mailer at python.org Mon May 1 13:20:05 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 01 May 2023 17:20:05 -0000 Subject: [Python-checkins] gh-102799: replace sys.exc_info by sys.exception in inspect and traceback modules (#104032) Message-ID: https://github.com/python/cpython/commit/a679c3d58d10aafd9ac9355fdd16151607e37d65 commit: a679c3d58d10aafd9ac9355fdd16151607e37d65 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-01T18:19:47+01:00 summary: gh-102799: replace sys.exc_info by sys.exception in inspect and traceback modules (#104032) files: M Lib/inspect.py M Lib/traceback.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 6d1d7b766cb3..92c2675cfd7d 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1766,7 +1766,9 @@ def stack(context=1): def trace(context=1): """Return a list of records for the stack below the current exception.""" - return getinnerframes(sys.exc_info()[2], context) + exc = sys.exception() + tb = None if exc is None else exc.__traceback__ + return getinnerframes(tb, context) # ------------------------------------------------ static version of getattr diff --git a/Lib/traceback.py b/Lib/traceback.py index ba4a9ffd001b..419f6e81b5e1 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -179,12 +179,12 @@ def _safe_string(value, what, func=str): # -- def print_exc(limit=None, file=None, chain=True): - """Shorthand for 'print_exception(*sys.exc_info(), limit, file, chain)'.""" - print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) + """Shorthand for 'print_exception(sys.exception(), limit, file, chain)'.""" + print_exception(sys.exception(), limit=limit, file=file, chain=chain) def format_exc(limit=None, chain=True): """Like print_exc() but return a string.""" - return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) + return "".join(format_exception(sys.exception(), limit=limit, chain=chain)) def print_last(limit=None, file=None, chain=True): """This is a shorthand for 'print_exception(sys.last_exc, limit, file, chain)'.""" From webhook-mailer at python.org Mon May 1 13:58:58 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 01 May 2023 17:58:58 -0000 Subject: [Python-checkins] GH-103629: Update Unpack's repr in compliance with PEP 692 (#104048) Message-ID: https://github.com/python/cpython/commit/2d526cd32fe8b286aae38956648e508070729f8f commit: 2d526cd32fe8b286aae38956648e508070729f8f branch: main author: Franek Magiera committer: AlexWaygood date: 2023-05-01T17:58:50Z summary: GH-103629: Update Unpack's repr in compliance with PEP 692 (#104048) files: A Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.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 7c6a521c3c48..f162e587810a 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -880,6 +880,11 @@ def test_cannot_be_called(self): with self.assertRaises(TypeError): Unpack() + def test_usage_with_kwargs(self): + Movie = TypedDict('Movie', {'name': str, 'year': int}) + def foo(**kwargs: Unpack[Movie]): ... + self.assertEqual(repr(foo.__annotations__['kwargs']), + f"typing.Unpack[{__name__}.Movie]") class TypeVarTupleTests(BaseTestCase): @@ -1050,14 +1055,14 @@ class G2(Generic[Unpack[Ts]]): pass self.assertEqual(repr(Ts), 'Ts') - self.assertEqual(repr((*Ts,)[0]), '*Ts') - self.assertEqual(repr(Unpack[Ts]), '*Ts') + self.assertEqual(repr((*Ts,)[0]), 'typing.Unpack[Ts]') + self.assertEqual(repr(Unpack[Ts]), 'typing.Unpack[Ts]') - self.assertEqual(repr(tuple[*Ts]), 'tuple[*Ts]') - self.assertEqual(repr(Tuple[Unpack[Ts]]), 'typing.Tuple[*Ts]') + self.assertEqual(repr(tuple[*Ts]), 'tuple[typing.Unpack[Ts]]') + self.assertEqual(repr(Tuple[Unpack[Ts]]), 'typing.Tuple[typing.Unpack[Ts]]') - self.assertEqual(repr(*tuple[*Ts]), '*tuple[*Ts]') - self.assertEqual(repr(Unpack[Tuple[Unpack[Ts]]]), '*typing.Tuple[*Ts]') + self.assertEqual(repr(*tuple[*Ts]), '*tuple[typing.Unpack[Ts]]') + self.assertEqual(repr(Unpack[Tuple[Unpack[Ts]]]), 'typing.Unpack[typing.Tuple[typing.Unpack[Ts]]]') def test_variadic_class_repr_is_correct(self): Ts = TypeVarTuple('Ts') @@ -1074,86 +1079,86 @@ class B(Generic[Unpack[Ts]]): pass self.assertEndsWith(repr(A[*tuple[int, ...]]), 'A[*tuple[int, ...]]') self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]]]), - 'B[*typing.Tuple[int, ...]]') + 'B[typing.Unpack[typing.Tuple[int, ...]]]') self.assertEndsWith(repr(A[float, *tuple[int, ...]]), 'A[float, *tuple[int, ...]]') self.assertEndsWith(repr(A[float, Unpack[Tuple[int, ...]]]), - 'A[float, *typing.Tuple[int, ...]]') + 'A[float, typing.Unpack[typing.Tuple[int, ...]]]') self.assertEndsWith(repr(A[*tuple[int, ...], str]), 'A[*tuple[int, ...], str]') self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]], str]), - 'B[*typing.Tuple[int, ...], str]') + 'B[typing.Unpack[typing.Tuple[int, ...]], str]') self.assertEndsWith(repr(A[float, *tuple[int, ...], str]), 'A[float, *tuple[int, ...], str]') self.assertEndsWith(repr(B[float, Unpack[Tuple[int, ...]], str]), - 'B[float, *typing.Tuple[int, ...], str]') + 'B[float, typing.Unpack[typing.Tuple[int, ...]], str]') def test_variadic_class_alias_repr_is_correct(self): Ts = TypeVarTuple('Ts') class A(Generic[Unpack[Ts]]): pass B = A[*Ts] - self.assertEndsWith(repr(B), 'A[*Ts]') + self.assertEndsWith(repr(B), 'A[typing.Unpack[Ts]]') self.assertEndsWith(repr(B[()]), 'A[()]') self.assertEndsWith(repr(B[float]), 'A[float]') self.assertEndsWith(repr(B[float, str]), 'A[float, str]') C = A[Unpack[Ts]] - self.assertEndsWith(repr(C), 'A[*Ts]') + self.assertEndsWith(repr(C), 'A[typing.Unpack[Ts]]') self.assertEndsWith(repr(C[()]), 'A[()]') self.assertEndsWith(repr(C[float]), 'A[float]') self.assertEndsWith(repr(C[float, str]), 'A[float, str]') D = A[*Ts, int] - self.assertEndsWith(repr(D), 'A[*Ts, int]') + self.assertEndsWith(repr(D), 'A[typing.Unpack[Ts], int]') self.assertEndsWith(repr(D[()]), 'A[int]') self.assertEndsWith(repr(D[float]), 'A[float, int]') self.assertEndsWith(repr(D[float, str]), 'A[float, str, int]') E = A[Unpack[Ts], int] - self.assertEndsWith(repr(E), 'A[*Ts, int]') + self.assertEndsWith(repr(E), 'A[typing.Unpack[Ts], int]') self.assertEndsWith(repr(E[()]), 'A[int]') self.assertEndsWith(repr(E[float]), 'A[float, int]') self.assertEndsWith(repr(E[float, str]), 'A[float, str, int]') F = A[int, *Ts] - self.assertEndsWith(repr(F), 'A[int, *Ts]') + self.assertEndsWith(repr(F), 'A[int, typing.Unpack[Ts]]') self.assertEndsWith(repr(F[()]), 'A[int]') self.assertEndsWith(repr(F[float]), 'A[int, float]') self.assertEndsWith(repr(F[float, str]), 'A[int, float, str]') G = A[int, Unpack[Ts]] - self.assertEndsWith(repr(G), 'A[int, *Ts]') + self.assertEndsWith(repr(G), 'A[int, typing.Unpack[Ts]]') self.assertEndsWith(repr(G[()]), 'A[int]') self.assertEndsWith(repr(G[float]), 'A[int, float]') self.assertEndsWith(repr(G[float, str]), 'A[int, float, str]') H = A[int, *Ts, str] - self.assertEndsWith(repr(H), 'A[int, *Ts, str]') + self.assertEndsWith(repr(H), 'A[int, typing.Unpack[Ts], str]') self.assertEndsWith(repr(H[()]), 'A[int, str]') self.assertEndsWith(repr(H[float]), 'A[int, float, str]') self.assertEndsWith(repr(H[float, str]), 'A[int, float, str, str]') I = A[int, Unpack[Ts], str] - self.assertEndsWith(repr(I), 'A[int, *Ts, str]') + self.assertEndsWith(repr(I), 'A[int, typing.Unpack[Ts], str]') self.assertEndsWith(repr(I[()]), 'A[int, str]') self.assertEndsWith(repr(I[float]), 'A[int, float, str]') self.assertEndsWith(repr(I[float, str]), 'A[int, float, str, str]') J = A[*Ts, *tuple[str, ...]] - self.assertEndsWith(repr(J), 'A[*Ts, *tuple[str, ...]]') + self.assertEndsWith(repr(J), 'A[typing.Unpack[Ts], *tuple[str, ...]]') self.assertEndsWith(repr(J[()]), 'A[*tuple[str, ...]]') self.assertEndsWith(repr(J[float]), 'A[float, *tuple[str, ...]]') self.assertEndsWith(repr(J[float, str]), 'A[float, str, *tuple[str, ...]]') K = A[Unpack[Ts], Unpack[Tuple[str, ...]]] - self.assertEndsWith(repr(K), 'A[*Ts, *typing.Tuple[str, ...]]') - self.assertEndsWith(repr(K[()]), 'A[*typing.Tuple[str, ...]]') - self.assertEndsWith(repr(K[float]), 'A[float, *typing.Tuple[str, ...]]') - self.assertEndsWith(repr(K[float, str]), 'A[float, str, *typing.Tuple[str, ...]]') + self.assertEndsWith(repr(K), 'A[typing.Unpack[Ts], typing.Unpack[typing.Tuple[str, ...]]]') + self.assertEndsWith(repr(K[()]), 'A[typing.Unpack[typing.Tuple[str, ...]]]') + self.assertEndsWith(repr(K[float]), 'A[float, typing.Unpack[typing.Tuple[str, ...]]]') + self.assertEndsWith(repr(K[float, str]), 'A[float, str, typing.Unpack[typing.Tuple[str, ...]]]') def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): @@ -1171,9 +1176,9 @@ class C(type(Unpack[Ts])): pass with self.assertRaisesRegex(TypeError, r'Cannot subclass typing\.Unpack'): class C(Unpack): pass - with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): + with self.assertRaisesRegex(TypeError, r'Cannot subclass typing.Unpack\[Ts\]'): class C(*Ts): pass - with self.assertRaisesRegex(TypeError, r'Cannot subclass \*Ts'): + with self.assertRaisesRegex(TypeError, r'Cannot subclass typing.Unpack\[Ts\]'): class C(Unpack[Ts]): pass def test_variadic_class_args_are_correct(self): @@ -4108,13 +4113,13 @@ class TsP(Generic[*Ts, P]): MyCallable[[int], bool]: "MyCallable[[int], bool]", MyCallable[[int, str], bool]: "MyCallable[[int, str], bool]", MyCallable[[int, list[int]], bool]: "MyCallable[[int, list[int]], bool]", - MyCallable[Concatenate[*Ts, P], T]: "MyCallable[typing.Concatenate[*Ts, ~P], ~T]", + MyCallable[Concatenate[*Ts, P], T]: "MyCallable[typing.Concatenate[typing.Unpack[Ts], ~P], ~T]", DoubleSpec[P2, P, T]: "DoubleSpec[~P2, ~P, ~T]", DoubleSpec[[int], [str], bool]: "DoubleSpec[[int], [str], bool]", DoubleSpec[[int, int], [str, str], bool]: "DoubleSpec[[int, int], [str, str], bool]", - TsP[*Ts, P]: "TsP[*Ts, ~P]", + TsP[*Ts, P]: "TsP[typing.Unpack[Ts], ~P]", TsP[int, str, list[int], []]: "TsP[int, str, list[int], []]", TsP[int, [str, list[int]]]: "TsP[int, [str, list[int]]]", diff --git a/Lib/typing.py b/Lib/typing.py index 354bc80eb3ab..1a1c989dbaf3 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1753,6 +1753,17 @@ class Bar(Generic[Unpack[Ts]]): ... Foo[*tuple[int, str]] class Bar(Generic[*Ts]): ... + The operator can also be used along with a `TypedDict` to annotate + `**kwargs` in a function signature. For instance: + + class Movie(TypedDict): + name: str + year: int + + # This function expects two keyword arguments - *name* of type `str` and + # *year* of type `int`. + def foo(**kwargs: Unpack[Movie]): ... + Note that there is only some runtime checking of this operator. Not everything the runtime allows may be accepted by static type checkers. @@ -1767,7 +1778,7 @@ class _UnpackGenericAlias(_GenericAlias, _root=True): def __repr__(self): # `Unpack` only takes one argument, so __args__ should contain only # a single item. - return '*' + repr(self.__args__[0]) + return f'typing.Unpack[{_type_repr(self.__args__[0])}]' def __getitem__(self, args): if self.__typing_is_unpacked_typevartuple__: diff --git a/Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst b/Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst new file mode 100644 index 000000000000..7971ab66359c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst @@ -0,0 +1 @@ +Update the ``repr`` of :class:`typing.Unpack` according to :pep:`692`. From webhook-mailer at python.org Mon May 1 15:16:06 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 01 May 2023 19:16:06 -0000 Subject: [Python-checkins] gh-104016: Fixed off by 1 error in f string tokenizer (#104047) Message-ID: https://github.com/python/cpython/commit/5078eedc5b18f0d208af6e30f60b33419132d1b6 commit: 5078eedc5b18f0d208af6e30f60b33419132d1b6 branch: main author: jx124 <64946984+jx124 at users.noreply.github.com> committer: pablogsal date: 2023-05-01T19:15:47Z summary: gh-104016: Fixed off by 1 error in f string tokenizer (#104047) Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> Co-authored-by: Ken Jin Co-authored-by: Pablo Galindo 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 5e94c99ae65a..5c5176dc54a6 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -565,7 +565,23 @@ 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 create_nested_fstring(n): + if n == 0: + return "1+1" + prev = create_nested_fstring(n-1) + return f'f"{{{prev}}}"' + self.assertAllRaise(SyntaxError, + "too many nested f-strings", + [create_nested_fstring(160)]) + + def test_syntax_error_in_nested_fstring(self): + # See gh-104016 for more information on this crash + self.assertAllRaise(SyntaxError, + "invalid syntax", + ['f"{1 1:' + ('{f"1:' * 199)]) + def test_double_braces(self): self.assertEqual(f'{{', '{') self.assertEqual(f'a{{', 'a{') diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 8fb9be7bfd01..d2f9fee110eb 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -43,12 +43,12 @@ #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); + assert(tok->tok_mode_stack_index < MAXFSTRINGLEVEL); 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); + assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL); return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]); } #else @@ -2235,6 +2235,9 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t p_start = tok->start; p_end = tok->cur; + if (tok->tok_mode_stack_index + 1 >= MAXFSTRINGLEVEL) { + return MAKE_TOKEN(syntaxerror(tok, "too many nested f-strings")); + } tokenizer_mode *the_current_tok = TOK_NEXT_MODE(tok); the_current_tok->kind = TOK_FSTRING_MODE; the_current_tok->f_string_quote = quote; diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 8b4213c4ce3b..5e2171885ac7 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -10,8 +10,9 @@ extern "C" { #include "pycore_token.h" /* For token types */ -#define MAXINDENT 100 /* Max indentation level */ -#define MAXLEVEL 200 /* Max parentheses level */ +#define MAXINDENT 100 /* Max indentation level */ +#define MAXLEVEL 200 /* Max parentheses level */ +#define MAXFSTRINGLEVEL 150 /* Max f-string nesting level */ enum decoding_state { STATE_INIT, @@ -123,7 +124,7 @@ struct tok_state { enum interactive_underflow_t interactive_underflow; int report_warnings; // TODO: Factor this into its own thing - tokenizer_mode tok_mode_stack[MAXLEVEL]; + tokenizer_mode tok_mode_stack[MAXFSTRINGLEVEL]; int tok_mode_stack_index; int tok_report_warnings; #ifdef Py_DEBUG From webhook-mailer at python.org Mon May 1 15:47:25 2023 From: webhook-mailer at python.org (mdickinson) Date: Mon, 01 May 2023 19:47:25 -0000 Subject: [Python-checkins] gh-104018: disallow "z" format specifier in %-format of byte strings (GH-104033) Message-ID: https://github.com/python/cpython/commit/3ed8c882902a6982fd67e898a5b8a2d619fb5ddf commit: 3ed8c882902a6982fd67e898a5b8a2d619fb5ddf branch: main author: John Belmonte committer: mdickinson date: 2023-05-01T20:47:14+01:00 summary: gh-104018: disallow "z" format specifier in %-format of byte strings (GH-104033) PEP-0682 specified that %-formatting would not support the "z" specifier, but it was unintentionally allowed for bytes. This PR makes use of the "z" flag an error for %-formatting in a bytestring. Issue: #104018 --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst M Lib/test/test_format.py M Objects/bytesobject.c diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 69b0d5f1c5a5..6fa49dbc0b73 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -619,6 +619,8 @@ def test_specifier_z_error(self): error_msg = re.escape("unsupported format character 'z'") with self.assertRaisesRegex(ValueError, error_msg): "%z.1f" % 0 # not allowed in old style string interpolation + with self.assertRaisesRegex(ValueError, error_msg): + b"%z.1f" % 0 if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst new file mode 100644 index 000000000000..f3cadaee0e32 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst @@ -0,0 +1 @@ +Disallow the "z" format specifier in %-format of bytes objects. diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 27b2ad4f2cb3..e7e85cc19cda 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -705,7 +705,6 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, case ' ': flags |= F_BLANK; continue; case '#': flags |= F_ALT; continue; case '0': flags |= F_ZERO; continue; - case 'z': flags |= F_NO_NEG_0; continue; } break; } From webhook-mailer at python.org Mon May 1 15:50:01 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 01 May 2023 19:50:01 -0000 Subject: [Python-checkins] gh-100458: Clarify Enum.__format__() change of mixed-in types in the whatsnew/3.11.rst (GH-100387) Message-ID: https://github.com/python/cpython/commit/e665563f8301d0db5cb0847d75fc879f074aa100 commit: e665563f8301d0db5cb0847d75fc879f074aa100 branch: main author: An?e Pe?ar committer: ethanfurman date: 2023-05-01T12:49:54-07:00 summary: gh-100458: Clarify Enum.__format__() change of mixed-in types in the whatsnew/3.11.rst (GH-100387) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> Co-authored-by: Ethan Furman files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 10fcfb6a0b56..687719a260a6 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -666,19 +666,11 @@ enum for :meth:`~object.__str__` and :meth:`~object.__format__` (used by :func:`str`, :func:`format` and :term:`f-string`\s). -* Changed :class:`~enum.IntEnum`, :class:`~enum.IntFlag` and :class:`~enum.StrEnum` - to now inherit from :class:`~enum.ReprEnum`, - so their :func:`str` output now matches :func:`format` - (both ``str(AnIntEnum.ONE)`` and ``format(AnIntEnum.ONE)`` return ``'1'``, - whereas before ``str(AnIntEnum.ONE)`` returned ``'AnIntEnum.ONE'``. - -* Changed :meth:`Enum.__format__() ` - (the default for :func:`format`, :meth:`str.format` and :term:`f-string`\s) - of enums with mixed-in types (e.g. :class:`int`, :class:`str`) - to also include the class name in the output, not just the member's key. - This matches the existing behavior of :meth:`enum.Enum.__str__`, - returning e.g. ``'AnEnum.MEMBER'`` for an enum ``AnEnum(str, Enum)`` - instead of just ``'MEMBER'``. +* Changed :meth:`Enum.__format__() ` (the default for + :func:`format`, :meth:`str.format` and :term:`f-string`\s) to always produce + the same result as :meth:`Enum.__str__()`: for enums inheriting from + :class:`~enum.ReprEnum` it will be the member's value; for all other enums + it will be the enum and member name (e.g. ``Color.RED``). * Added a new *boundary* class parameter to :class:`~enum.Flag` enums and the :class:`~enum.FlagBoundary` enum with its options, From webhook-mailer at python.org Mon May 1 16:06:17 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 01 May 2023 20:06:17 -0000 Subject: [Python-checkins] [3.11] gh-100458: Clarify Enum.__format__() change of mixed-in types in the whatsnew/3.11.rst (GH-100387) (GH-104060) Message-ID: https://github.com/python/cpython/commit/723aacb7d5cf03b36c053c1f27fcfb3efdc9ae45 commit: 723aacb7d5cf03b36c053c1f27fcfb3efdc9ae45 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ethanfurman date: 2023-05-01T13:06:09-07:00 summary: [3.11] gh-100458: Clarify Enum.__format__() change of mixed-in types in the whatsnew/3.11.rst (GH-100387) (GH-104060) Co-authored-by: An?e Pe?ar Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> Co-authored-by: Ethan Furman files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 75963175042d..378315b36c6e 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -668,19 +668,11 @@ enum for :meth:`~object.__str__` and :meth:`~object.__format__` (used by :func:`str`, :func:`format` and :term:`f-string`\s). -* Changed :class:`~enum.IntEnum`, :class:`~enum.IntFlag` and :class:`~enum.StrEnum` - to now inherit from :class:`~enum.ReprEnum`, - so their :func:`str` output now matches :func:`format` - (both ``str(AnIntEnum.ONE)`` and ``format(AnIntEnum.ONE)`` return ``'1'``, - whereas before ``str(AnIntEnum.ONE)`` returned ``'AnIntEnum.ONE'``. - -* Changed :meth:`Enum.__format__() ` - (the default for :func:`format`, :meth:`str.format` and :term:`f-string`\s) - of enums with mixed-in types (e.g. :class:`int`, :class:`str`) - to also include the class name in the output, not just the member's key. - This matches the existing behavior of :meth:`enum.Enum.__str__`, - returning e.g. ``'AnEnum.MEMBER'`` for an enum ``AnEnum(str, Enum)`` - instead of just ``'MEMBER'``. +* Changed :meth:`Enum.__format__() ` (the default for + :func:`format`, :meth:`str.format` and :term:`f-string`\s) to always produce + the same result as :meth:`Enum.__str__()`: for enums inheriting from + :class:`~enum.ReprEnum` it will be the member's value; for all other enums + it will be the enum and member name (e.g. ``Color.RED``). * Added a new *boundary* class parameter to :class:`~enum.Flag` enums and the :class:`~enum.FlagBoundary` enum with its options, From webhook-mailer at python.org Mon May 1 16:17:54 2023 From: webhook-mailer at python.org (zware) Date: Mon, 01 May 2023 20:17:54 -0000 Subject: [Python-checkins] gh-104057: Fix direct invocation of test_module (GH-104059) Message-ID: https://github.com/python/cpython/commit/d448fcb0323bf00cb4ff4a1e65e8424a73b5f0d4 commit: d448fcb0323bf00cb4ff4a1e65e8424a73b5f0d4 branch: main author: Kirill Podoprigora <80244920+Eclips4 at users.noreply.github.com> committer: zware date: 2023-05-01T20:17:47Z summary: gh-104057: Fix direct invocation of test_module (GH-104059) files: M Lib/test/test_module.py diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py index 70e4efea6935..c7eb92290e1b 100644 --- a/Lib/test/test_module.py +++ b/Lib/test/test_module.py @@ -236,7 +236,7 @@ def test_module_repr_with_full_loader(self): # Yes, a class not an instance. m.__loader__ = FullLoader self.assertEqual( - repr(m), ")>") + repr(m), f")>") def test_module_repr_with_bare_loader_and_filename(self): m = ModuleType('foo') From webhook-mailer at python.org Mon May 1 16:18:36 2023 From: webhook-mailer at python.org (mdickinson) Date: Mon, 01 May 2023 20:18:36 -0000 Subject: [Python-checkins] [3.11] gh-104018: disallow "z" format specifier in %-format of byte strings (GH-104033) (#104058) Message-ID: https://github.com/python/cpython/commit/10db28bfcf2b949e13312d0d2f1b3dd3c9585e69 commit: 10db28bfcf2b949e13312d0d2f1b3dd3c9585e69 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: mdickinson date: 2023-05-01T20:18:29Z summary: [3.11] gh-104018: disallow "z" format specifier in %-format of byte strings (GH-104033) (#104058) gh-104018: disallow "z" format specifier in %-format of byte strings (GH-104033) PEP-0682 specified that %-formatting would not support the "z" specifier, but it was unintentionally allowed for bytes. This PR makes use of the "z" flag an error for %-formatting in a bytestring. Issue: GH-104018 --------- (cherry picked from commit 3ed8c882902a6982fd67e898a5b8a2d619fb5ddf) Co-authored-by: John Belmonte Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst M Lib/test/test_format.py M Objects/bytesobject.c diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 69b0d5f1c5a5..6fa49dbc0b73 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -619,6 +619,8 @@ def test_specifier_z_error(self): error_msg = re.escape("unsupported format character 'z'") with self.assertRaisesRegex(ValueError, error_msg): "%z.1f" % 0 # not allowed in old style string interpolation + with self.assertRaisesRegex(ValueError, error_msg): + b"%z.1f" % 0 if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst new file mode 100644 index 000000000000..f3cadaee0e32 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst @@ -0,0 +1 @@ +Disallow the "z" format specifier in %-format of bytes objects. diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 8dd1a2d52467..61cde0ef34bf 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -714,7 +714,6 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, case ' ': flags |= F_BLANK; continue; case '#': flags |= F_ALT; continue; case '0': flags |= F_ZERO; continue; - case 'z': flags |= F_NO_NEG_0; continue; } break; } From webhook-mailer at python.org Mon May 1 17:08:41 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 01 May 2023 21:08:41 -0000 Subject: [Python-checkins] gh-84436: Immortalize in _PyStructSequence_InitBuiltinWithFlags() (gh-104054) Message-ID: https://github.com/python/cpython/commit/59bc36aacddd5a3acd32c80c0dfd0726135a7817 commit: 59bc36aacddd5a3acd32c80c0dfd0726135a7817 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-05-01T15:08:34-06:00 summary: gh-84436: Immortalize in _PyStructSequence_InitBuiltinWithFlags() (gh-104054) This also does some cleanup. files: M Include/internal/pycore_structseq.h M Objects/floatobject.c M Objects/longobject.c M Objects/structseq.c M Objects/typeobject.c M Python/errors.c M Python/sysmodule.c M Python/thread.c diff --git a/Include/internal/pycore_structseq.h b/Include/internal/pycore_structseq.h index d10a921c55ff..bd1e85c6883f 100644 --- a/Include/internal/pycore_structseq.h +++ b/Include/internal/pycore_structseq.h @@ -15,7 +15,7 @@ PyAPI_FUNC(PyTypeObject *) _PyStructSequence_NewType( PyStructSequence_Desc *desc, unsigned long tp_flags); -PyAPI_FUNC(int) _PyStructSequence_InitBuiltinWithFlags( +extern int _PyStructSequence_InitBuiltinWithFlags( PyTypeObject *type, PyStructSequence_Desc *desc, unsigned long tp_flags); @@ -27,7 +27,7 @@ _PyStructSequence_InitBuiltin(PyTypeObject *type, return _PyStructSequence_InitBuiltinWithFlags(type, desc, 0); } -extern void _PyStructSequence_FiniType(PyTypeObject *type); +extern void _PyStructSequence_FiniBuiltin(PyTypeObject *type); #ifdef __cplusplus } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 9c2315781bed..a694ddcd019e 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -12,7 +12,7 @@ #include "pycore_object.h" // _PyObject_Init() #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_structseq.h" // _PyStructSequence_FiniType() +#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include #include @@ -2029,7 +2029,7 @@ void _PyFloat_FiniType(PyInterpreterState *interp) { if (_Py_IsMainInterpreter(interp)) { - _PyStructSequence_FiniType(&FloatInfoType); + _PyStructSequence_FiniBuiltin(&FloatInfoType); } } diff --git a/Objects/longobject.c b/Objects/longobject.c index f84809b8a898..de043488d7a1 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -9,7 +9,7 @@ #include "pycore_object.h" // _PyObject_Init() #include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS -#include "pycore_structseq.h" // _PyStructSequence_FiniType() +#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include #include @@ -6367,5 +6367,5 @@ _PyLong_FiniTypes(PyInterpreterState *interp) return; } - _PyStructSequence_FiniType(&Int_InfoType); + _PyStructSequence_FiniBuiltin(&Int_InfoType); } diff --git a/Objects/structseq.c b/Objects/structseq.c index 88a71bc52958..d8f55dc1eae5 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -433,12 +433,10 @@ initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict, static PyMemberDef * initialize_members(PyStructSequence_Desc *desc, - Py_ssize_t *pn_members, Py_ssize_t *pn_unnamed_members) + Py_ssize_t n_members, Py_ssize_t n_unnamed_members) { PyMemberDef *members; - Py_ssize_t n_members, n_unnamed_members; - n_members = count_members(desc, &n_unnamed_members); members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1); if (members == NULL) { PyErr_NoMemory(); @@ -463,8 +461,6 @@ initialize_members(PyStructSequence_Desc *desc, } members[k].name = NULL; - *pn_members = n_members; - *pn_unnamed_members = n_unnamed_members; return members; } @@ -510,39 +506,58 @@ _PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type, PyStructSequence_Desc *desc, unsigned long tp_flags) { - if (type->tp_flags & Py_TPFLAGS_READY) { - if (_PyStaticType_InitBuiltin(type) < 0) { - goto failed_init_builtin; + Py_ssize_t n_unnamed_members; + Py_ssize_t n_members = count_members(desc, &n_unnamed_members); + PyMemberDef *members = NULL; + + int initialized = 1; + if ((type->tp_flags & Py_TPFLAGS_READY) == 0) { + assert(type->tp_name == NULL); + assert(type->tp_members == NULL); + assert(type->tp_base == NULL); + + members = initialize_members(desc, n_members, n_unnamed_members); + if (members == NULL) { + goto error; } - return 0; - } + initialize_static_fields(type, desc, members, tp_flags); - PyMemberDef *members; - Py_ssize_t n_members, n_unnamed_members; - - members = initialize_members(desc, &n_members, &n_unnamed_members); - if (members == NULL) { - return -1; + _Py_SetImmortal(type); + initialized = 0; + } +#ifndef NDEBUG + else { + // Ensure that the type was initialized. + assert(type->tp_name != NULL); + assert(type->tp_members != NULL); + assert(type->tp_base == &PyTuple_Type); + assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); + assert(_Py_IsImmortal(type)); } - initialize_static_fields(type, desc, members, tp_flags); +#endif - Py_INCREF(type); // XXX It should be immortal. if (_PyStaticType_InitBuiltin(type) < 0) { - PyMem_Free(members); - goto failed_init_builtin; + PyErr_Format(PyExc_RuntimeError, + "Can't initialize builtin type %s", + desc->name); + goto error; + } + // This should be dropped if tp_dict is made per-interpreter. + if (initialized) { + return 0; } if (initialize_structseq_dict( desc, type->tp_dict, n_members, n_unnamed_members) < 0) { - PyMem_Free(members); - return -1; + goto error; } + return 0; -failed_init_builtin: - PyErr_Format(PyExc_RuntimeError, - "Can't initialize builtin type %s", - desc->name); +error: + if (members != NULL) { + PyMem_Free(members); + } return -1; } @@ -566,7 +581,8 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) return -1; } - members = initialize_members(desc, &n_members, &n_unnamed_members); + n_members = count_members(desc, &n_unnamed_members); + members = initialize_members(desc, n_members, n_unnamed_members); if (members == NULL) { return -1; } @@ -585,35 +601,32 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) } +/* This is exposed in the internal API, not the public API. + It is only called on builtin static types, which are all + initialized via _PyStructSequence_InitBuiltinWithFlags(). */ + void -_PyStructSequence_FiniType(PyTypeObject *type) +_PyStructSequence_FiniBuiltin(PyTypeObject *type) { // Ensure that the type is initialized assert(type->tp_name != NULL); assert(type->tp_base == &PyTuple_Type); + assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); + assert(_Py_IsImmortal(type)); // Cannot delete a type if it still has subclasses if (_PyType_HasSubclasses(type)) { + // XXX Shouldn't this be an error? return; } - // Undo PyStructSequence_NewType() - type->tp_name = NULL; - PyMem_Free(type->tp_members); - _PyStaticType_Dealloc(type); - assert(Py_REFCNT(type) == 1); - // Undo Py_INCREF(type) of _PyStructSequence_InitType(). - // Don't use Py_DECREF(): static type must not be deallocated - Py_SET_REFCNT(type, 0); -#ifdef Py_REF_DEBUG - _Py_DecRefTotal(_PyInterpreterState_GET()); -#endif - // Make sure that _PyStructSequence_InitType() will initialize - // the type again - assert(Py_REFCNT(type) == 0); - assert(type->tp_name == NULL); + // Undo _PyStructSequence_InitBuiltinWithFlags(). + type->tp_name = NULL; + PyMem_Free(type->tp_members); + type->tp_members = NULL; + type->tp_base = NULL; } @@ -627,7 +640,8 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags) Py_ssize_t n_members, n_unnamed_members; /* Initialize MemberDefs */ - members = initialize_members(desc, &n_members, &n_unnamed_members); + n_members = count_members(desc, &n_unnamed_members); + members = initialize_members(desc, n_members, n_unnamed_members); if (members == NULL) { return NULL; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e807cc90faa1..060d14e254ab 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7031,6 +7031,7 @@ PyType_Ready(PyTypeObject *type) int _PyStaticType_InitBuiltin(PyTypeObject *self) { + assert(_Py_IsImmortal((PyObject *)self)); assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE)); if (self->tp_flags & Py_TPFLAGS_READY) { diff --git a/Python/errors.c b/Python/errors.c index 7fc267385c56..ce72049b92de 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -6,7 +6,7 @@ #include "pycore_initconfig.h" // _PyStatus_ERR() #include "pycore_pyerrors.h" // _PyErr_Format() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_structseq.h" // _PyStructSequence_FiniType() +#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_traceback.h" // _PyTraceBack_FromFrame() @@ -1357,7 +1357,7 @@ _PyErr_FiniTypes(PyInterpreterState *interp) return; } - _PyStructSequence_FiniType(&UnraisableHookArgsType); + _PyStructSequence_FiniBuiltin(&UnraisableHookArgsType); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index d673e40af5e1..81dabe6102f1 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3492,13 +3492,13 @@ void _PySys_Fini(PyInterpreterState *interp) { if (_Py_IsMainInterpreter(interp)) { - _PyStructSequence_FiniType(&VersionInfoType); - _PyStructSequence_FiniType(&FlagsType); + _PyStructSequence_FiniBuiltin(&VersionInfoType); + _PyStructSequence_FiniBuiltin(&FlagsType); #if defined(MS_WINDOWS) - _PyStructSequence_FiniType(&WindowsVersionType); + _PyStructSequence_FiniBuiltin(&WindowsVersionType); #endif - _PyStructSequence_FiniType(&Hash_InfoType); - _PyStructSequence_FiniType(&AsyncGenHooksType); + _PyStructSequence_FiniBuiltin(&Hash_InfoType); + _PyStructSequence_FiniBuiltin(&AsyncGenHooksType); #ifdef __EMSCRIPTEN__ Py_CLEAR(EmscriptenInfoType); #endif diff --git a/Python/thread.c b/Python/thread.c index 7fdedb0b9b7e..f90cd34a0735 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -7,7 +7,7 @@ #include "Python.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_structseq.h" // _PyStructSequence_FiniType() +#include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() #include "pycore_pythread.h" #ifndef DONT_HAVE_STDIO_H @@ -195,5 +195,5 @@ _PyThread_FiniType(PyInterpreterState *interp) return; } - _PyStructSequence_FiniType(&ThreadInfoType); + _PyStructSequence_FiniBuiltin(&ThreadInfoType); } From webhook-mailer at python.org Mon May 1 17:10:21 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 01 May 2023 21:10:21 -0000 Subject: [Python-checkins] gh-97696: asyncio eager tasks factory (#102853) Message-ID: https://github.com/python/cpython/commit/a474e04388c2ef6aca75c26cb70a1b6200235feb commit: a474e04388c2ef6aca75c26cb70a1b6200235feb branch: main author: Itamar Ostricher committer: carljm date: 2023-05-01T15:10:13-06:00 summary: gh-97696: asyncio eager tasks factory (#102853) Co-authored-by: Jacob Bower Co-authored-by: Carol Willing files: A Lib/test/test_asyncio/test_eager_task_factory.py A Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst M Doc/library/asyncio-task.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/asyncio/base_tasks.py M Lib/asyncio/tasks.py M Modules/_asynciomodule.c M Modules/clinic/_asynciomodule.c.h diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index ba0f909c405a..f8727b980669 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -527,6 +527,42 @@ Running Tasks Concurrently and there is no running event loop. +Eager Task Factory +================== + +.. function:: eager_task_factory(loop, coro, *, name=None, context=None) + + A task factory for eager task execution. + + When using this factory (via :meth:`loop.set_task_factory(asyncio.eager_task_factory) `), + coroutines begin execution synchronously during :class:`Task` construction. + Tasks are only scheduled on the event loop if they block. + This can be a performance improvement as the overhead of loop scheduling + is avoided for coroutines that complete synchronously. + + A common example where this is beneficial is coroutines which employ + caching or memoization to avoid actual I/O when possible. + + .. note:: + + Immediate execution of the coroutine is a semantic change. + If the coroutine returns or raises, the task is never scheduled + to the event loop. If the coroutine execution blocks, the task is + scheduled to the event loop. This change may introduce behavior + changes to existing applications. For example, + the application's task execution order is likely to change. + + .. versionadded:: 3.12 + +.. function:: create_eager_task_factory(custom_task_constructor) + + Create an eager task factory, similar to :func:`eager_task_factory`, + using the provided *custom_task_constructor* when creating a new task instead + of the default :class:`Task`. + + .. versionadded:: 3.12 + + Shielding From Cancellation =========================== diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f4ee30b0d4d9..a3fce7ccacf7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -613,6 +613,11 @@ Optimizations * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting. (Contributed by Itamar O in :gh:`103793`.) +* Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory` + functions to allow opting an event loop in to eager task execution, + speeding up some use-cases by up to 50%. + (Contributed by Jacob Bower & Itamar O in :gh:`102853`) + CPython bytecode changes ======================== diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4fa15d74b3ad..5e8a8d784127 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -882,6 +882,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(dst_dir_fd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(duration)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(e)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eager_start)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(effective_ids)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(element_factory)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(encode)); @@ -972,6 +973,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(instructions)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(intern)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(intersection)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(is_running)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isatty)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isinstance)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(isoformat)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index e19d8ff1b504..28e82203d8f6 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -370,6 +370,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(dst_dir_fd) STRUCT_FOR_ID(duration) STRUCT_FOR_ID(e) + STRUCT_FOR_ID(eager_start) STRUCT_FOR_ID(effective_ids) STRUCT_FOR_ID(element_factory) STRUCT_FOR_ID(encode) @@ -460,6 +461,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(instructions) STRUCT_FOR_ID(intern) STRUCT_FOR_ID(intersection) + STRUCT_FOR_ID(is_running) STRUCT_FOR_ID(isatty) STRUCT_FOR_ID(isinstance) STRUCT_FOR_ID(isoformat) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 42c4874d9466..dd4471160a4a 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -876,6 +876,7 @@ extern "C" { INIT_ID(dst_dir_fd), \ INIT_ID(duration), \ INIT_ID(e), \ + INIT_ID(eager_start), \ INIT_ID(effective_ids), \ INIT_ID(element_factory), \ INIT_ID(encode), \ @@ -966,6 +967,7 @@ extern "C" { INIT_ID(instructions), \ INIT_ID(intern), \ INIT_ID(intersection), \ + INIT_ID(is_running), \ INIT_ID(isatty), \ INIT_ID(isinstance), \ INIT_ID(isoformat), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 6d9cd24d9f3a..1a8338b341fd 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -963,6 +963,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(e); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(eager_start); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(effective_ids); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1233,6 +1236,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(intersection); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(is_running); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(isatty); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py index 26298e638cbf..c907b6834137 100644 --- a/Lib/asyncio/base_tasks.py +++ b/Lib/asyncio/base_tasks.py @@ -15,11 +15,13 @@ def _task_repr_info(task): info.insert(1, 'name=%r' % task.get_name()) - coro = coroutines._format_coroutine(task._coro) - info.insert(2, f'coro=<{coro}>') - if task._fut_waiter is not None: - info.insert(3, f'wait_for={task._fut_waiter!r}') + info.insert(2, f'wait_for={task._fut_waiter!r}') + + if task._coro: + coro = coroutines._format_coroutine(task._coro) + info.insert(2, f'coro=<{coro}>') + return info diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index c90d32c97add..aa5269ade19a 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -6,6 +6,7 @@ 'wait', 'wait_for', 'as_completed', 'sleep', 'gather', 'shield', 'ensure_future', 'run_coroutine_threadsafe', 'current_task', 'all_tasks', + 'create_eager_task_factory', 'eager_task_factory', '_register_task', '_unregister_task', '_enter_task', '_leave_task', ) @@ -43,22 +44,26 @@ def all_tasks(loop=None): """Return a set of all tasks for the loop.""" if loop is None: loop = events.get_running_loop() - # Looping over a WeakSet (_all_tasks) isn't safe as it can be updated from another - # thread while we do so. Therefore we cast it to list prior to filtering. The list - # cast itself requires iteration, so we repeat it several times ignoring - # RuntimeErrors (which are not very likely to occur). See issues 34970 and 36607 for - # details. + # capturing the set of eager tasks first, so if an eager task "graduates" + # to a regular task in another thread, we don't risk missing it. + eager_tasks = list(_eager_tasks) + # Looping over the WeakSet isn't safe as it can be updated from another + # thread, therefore we cast it to list prior to filtering. The list cast + # itself requires iteration, so we repeat it several times ignoring + # RuntimeErrors (which are not very likely to occur). + # See issues 34970 and 36607 for details. + scheduled_tasks = None i = 0 while True: try: - tasks = list(_all_tasks) + scheduled_tasks = list(_scheduled_tasks) except RuntimeError: i += 1 if i >= 1000: raise else: break - return {t for t in tasks + return {t for t in itertools.chain(scheduled_tasks, eager_tasks) if futures._get_loop(t) is loop and not t.done()} @@ -93,7 +98,8 @@ class Task(futures._PyFuture): # Inherit Python Task implementation # status is still pending _log_destroy_pending = True - def __init__(self, coro, *, loop=None, name=None, context=None): + def __init__(self, coro, *, loop=None, name=None, context=None, + eager_start=False): super().__init__(loop=loop) if self._source_traceback: del self._source_traceback[-1] @@ -117,8 +123,11 @@ def __init__(self, coro, *, loop=None, name=None, context=None): else: self._context = context - self._loop.call_soon(self.__step, context=self._context) - _register_task(self) + if eager_start and self._loop.is_running(): + self.__eager_start() + else: + self._loop.call_soon(self.__step, context=self._context) + _register_task(self) def __del__(self): if self._state == futures._PENDING and self._log_destroy_pending: @@ -250,6 +259,25 @@ def uncancel(self): self._num_cancels_requested -= 1 return self._num_cancels_requested + def __eager_start(self): + prev_task = _swap_current_task(self._loop, self) + try: + _register_eager_task(self) + try: + self._context.run(self.__step_run_and_handle_result, None) + finally: + _unregister_eager_task(self) + finally: + try: + curtask = _swap_current_task(self._loop, prev_task) + assert curtask is self + finally: + if self.done(): + self._coro = None + self = None # Needed to break cycles when an exception occurs. + else: + _register_task(self) + def __step(self, exc=None): if self.done(): raise exceptions.InvalidStateError( @@ -258,11 +286,17 @@ def __step(self, exc=None): if not isinstance(exc, exceptions.CancelledError): exc = self._make_cancelled_error() self._must_cancel = False - coro = self._coro self._fut_waiter = None _enter_task(self._loop, self) - # Call either coro.throw(exc) or coro.send(None). + try: + self.__step_run_and_handle_result(exc) + finally: + _leave_task(self._loop, self) + self = None # Needed to break cycles when an exception occurs. + + def __step_run_and_handle_result(self, exc): + coro = self._coro try: if exc is None: # We use the `send` method directly, because coroutines @@ -334,7 +368,6 @@ def __step(self, exc=None): self._loop.call_soon( self.__step, new_exc, context=self._context) finally: - _leave_task(self._loop, self) self = None # Needed to break cycles when an exception occurs. def __wakeup(self, future): @@ -897,8 +930,27 @@ def callback(): return future -# WeakSet containing all alive tasks. -_all_tasks = weakref.WeakSet() +def create_eager_task_factory(custom_task_constructor): + + if "eager_start" not in inspect.signature(custom_task_constructor).parameters: + raise TypeError( + "Provided constructor does not support eager task execution") + + def factory(loop, coro, *, name=None, context=None): + return custom_task_constructor( + coro, loop=loop, name=name, context=context, eager_start=True) + + + return factory + +eager_task_factory = create_eager_task_factory(Task) + + +# Collectively these two sets hold references to the complete set of active +# tasks. Eagerly executed tasks use a faster regular set as an optimization +# but may graduate to a WeakSet if the task blocks on IO. +_scheduled_tasks = weakref.WeakSet() +_eager_tasks = set() # Dictionary containing tasks that are currently active in # all running event loops. {EventLoop: Task} @@ -906,8 +958,13 @@ def callback(): def _register_task(task): - """Register a new task in asyncio as executed by loop.""" - _all_tasks.add(task) + """Register an asyncio Task scheduled to run on an event loop.""" + _scheduled_tasks.add(task) + + +def _register_eager_task(task): + """Register an asyncio Task about to be eagerly executed.""" + _eager_tasks.add(task) def _enter_task(loop, task): @@ -926,28 +983,49 @@ def _leave_task(loop, task): del _current_tasks[loop] +def _swap_current_task(loop, task): + prev_task = _current_tasks.get(loop) + if task is None: + del _current_tasks[loop] + else: + _current_tasks[loop] = task + return prev_task + + def _unregister_task(task): - """Unregister a task.""" - _all_tasks.discard(task) + """Unregister a completed, scheduled Task.""" + _scheduled_tasks.discard(task) + + +def _unregister_eager_task(task): + """Unregister a task which finished its first eager step.""" + _eager_tasks.discard(task) _py_current_task = current_task _py_register_task = _register_task +_py_register_eager_task = _register_eager_task _py_unregister_task = _unregister_task +_py_unregister_eager_task = _unregister_eager_task _py_enter_task = _enter_task _py_leave_task = _leave_task +_py_swap_current_task = _swap_current_task try: - from _asyncio import (_register_task, _unregister_task, - _enter_task, _leave_task, - _all_tasks, _current_tasks, + from _asyncio import (_register_task, _register_eager_task, + _unregister_task, _unregister_eager_task, + _enter_task, _leave_task, _swap_current_task, + _scheduled_tasks, _eager_tasks, _current_tasks, current_task) except ImportError: pass else: _c_current_task = current_task _c_register_task = _register_task + _c_register_eager_task = _register_eager_task _c_unregister_task = _unregister_task + _c_unregister_eager_task = _unregister_eager_task _c_enter_task = _enter_task _c_leave_task = _leave_task + _c_swap_current_task = _swap_current_task diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py new file mode 100644 index 000000000000..fe690934292a --- /dev/null +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -0,0 +1,344 @@ +"""Tests for base_events.py""" + +import asyncio +import contextvars +import gc +import time +import unittest + +from types import GenericAlias +from unittest import mock +from asyncio import base_events +from asyncio import tasks +from test.test_asyncio import utils as test_utils +from test.test_asyncio.test_tasks import get_innermost_context +from test import support + +MOCK_ANY = mock.ANY + + +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + +class EagerTaskFactoryLoopTests: + + Task = None + + def run_coro(self, coro): + """ + Helper method to run the `coro` coroutine in the test event loop. + It helps with making sure the event loop is running before starting + to execute `coro`. This is important for testing the eager step + functionality, since an eager step is taken only if the event loop + is already running. + """ + + async def coro_runner(): + self.assertTrue(asyncio.get_event_loop().is_running()) + return await coro + + return self.loop.run_until_complete(coro) + + def setUp(self): + super().setUp() + self.loop = asyncio.new_event_loop() + self.eager_task_factory = asyncio.create_eager_task_factory(self.Task) + self.loop.set_task_factory(self.eager_task_factory) + self.set_event_loop(self.loop) + + def test_eager_task_factory_set(self): + self.assertIsNotNone(self.eager_task_factory) + self.assertIs(self.loop.get_task_factory(), self.eager_task_factory) + + async def noop(): pass + + async def run(): + t = self.loop.create_task(noop()) + self.assertIsInstance(t, self.Task) + await t + + self.run_coro(run()) + + def test_await_future_during_eager_step(self): + + async def set_result(fut, val): + fut.set_result(val) + + async def run(): + fut = self.loop.create_future() + t = self.loop.create_task(set_result(fut, 'my message')) + # assert the eager step completed the task + self.assertTrue(t.done()) + return await fut + + self.assertEqual(self.run_coro(run()), 'my message') + + def test_eager_completion(self): + + async def coro(): + return 'hello' + + async def run(): + t = self.loop.create_task(coro()) + # assert the eager step completed the task + self.assertTrue(t.done()) + return await t + + self.assertEqual(self.run_coro(run()), 'hello') + + def test_block_after_eager_step(self): + + async def coro(): + await asyncio.sleep(0.1) + return 'finished after blocking' + + async def run(): + t = self.loop.create_task(coro()) + self.assertFalse(t.done()) + result = await t + self.assertTrue(t.done()) + return result + + self.assertEqual(self.run_coro(run()), 'finished after blocking') + + def test_cancellation_after_eager_completion(self): + + async def coro(): + return 'finished without blocking' + + async def run(): + t = self.loop.create_task(coro()) + t.cancel() + result = await t + # finished task can't be cancelled + self.assertFalse(t.cancelled()) + return result + + self.assertEqual(self.run_coro(run()), 'finished without blocking') + + def test_cancellation_after_eager_step_blocks(self): + + async def coro(): + await asyncio.sleep(0.1) + return 'finished after blocking' + + async def run(): + t = self.loop.create_task(coro()) + t.cancel('cancellation message') + self.assertGreater(t.cancelling(), 0) + result = await t + + with self.assertRaises(asyncio.CancelledError) as cm: + self.run_coro(run()) + + self.assertEqual('cancellation message', cm.exception.args[0]) + + def test_current_task(self): + captured_current_task = None + + async def coro(): + nonlocal captured_current_task + captured_current_task = asyncio.current_task() + # verify the task before and after blocking is identical + await asyncio.sleep(0.1) + self.assertIs(asyncio.current_task(), captured_current_task) + + async def run(): + t = self.loop.create_task(coro()) + self.assertIs(captured_current_task, t) + await t + + self.run_coro(run()) + captured_current_task = None + + def test_all_tasks_with_eager_completion(self): + captured_all_tasks = None + + async def coro(): + nonlocal captured_all_tasks + captured_all_tasks = asyncio.all_tasks() + + async def run(): + t = self.loop.create_task(coro()) + self.assertIn(t, captured_all_tasks) + self.assertNotIn(t, asyncio.all_tasks()) + + self.run_coro(run()) + + def test_all_tasks_with_blocking(self): + captured_eager_all_tasks = None + + async def coro(fut1, fut2): + nonlocal captured_eager_all_tasks + captured_eager_all_tasks = asyncio.all_tasks() + await fut1 + fut2.set_result(None) + + async def run(): + fut1 = self.loop.create_future() + fut2 = self.loop.create_future() + t = self.loop.create_task(coro(fut1, fut2)) + self.assertIn(t, captured_eager_all_tasks) + self.assertIn(t, asyncio.all_tasks()) + fut1.set_result(None) + await fut2 + self.assertNotIn(t, asyncio.all_tasks()) + + self.run_coro(run()) + + def test_context_vars(self): + cv = contextvars.ContextVar('cv', default=0) + + coro_first_step_ran = False + coro_second_step_ran = False + + async def coro(): + nonlocal coro_first_step_ran + nonlocal coro_second_step_ran + self.assertEqual(cv.get(), 1) + cv.set(2) + self.assertEqual(cv.get(), 2) + coro_first_step_ran = True + await asyncio.sleep(0.1) + self.assertEqual(cv.get(), 2) + cv.set(3) + self.assertEqual(cv.get(), 3) + coro_second_step_ran = True + + async def run(): + cv.set(1) + t = self.loop.create_task(coro()) + self.assertTrue(coro_first_step_ran) + self.assertFalse(coro_second_step_ran) + self.assertEqual(cv.get(), 1) + await t + self.assertTrue(coro_second_step_ran) + self.assertEqual(cv.get(), 1) + + self.run_coro(run()) + + +class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): + Task = tasks._PyTask + + + at unittest.skipUnless(hasattr(tasks, '_CTask'), + 'requires the C _asyncio module') +class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + + +class AsyncTaskCounter: + def __init__(self, loop, *, task_class, eager): + self.suspense_count = 0 + self.task_count = 0 + + def CountingTask(*args, eager_start=False, **kwargs): + if not eager_start: + self.task_count += 1 + kwargs["eager_start"] = eager_start + return task_class(*args, **kwargs) + + if eager: + factory = asyncio.create_eager_task_factory(CountingTask) + else: + def factory(loop, coro, **kwargs): + return CountingTask(coro, loop=loop, **kwargs) + loop.set_task_factory(factory) + + def get(self): + return self.task_count + + +async def awaitable_chain(depth): + if depth == 0: + return 0 + return 1 + await awaitable_chain(depth - 1) + + +async def recursive_taskgroups(width, depth): + if depth == 0: + return + + async with asyncio.TaskGroup() as tg: + futures = [ + tg.create_task(recursive_taskgroups(width, depth - 1)) + for _ in range(width) + ] + + +async def recursive_gather(width, depth): + if depth == 0: + return + + await asyncio.gather( + *[recursive_gather(width, depth - 1) for _ in range(width)] + ) + + +class BaseTaskCountingTests: + + Task = None + eager = None + expected_task_count = None + + def setUp(self): + super().setUp() + self.loop = asyncio.new_event_loop() + self.counter = AsyncTaskCounter(self.loop, task_class=self.Task, eager=self.eager) + self.set_event_loop(self.loop) + + def test_awaitables_chain(self): + observed_depth = self.loop.run_until_complete(awaitable_chain(100)) + self.assertEqual(observed_depth, 100) + self.assertEqual(self.counter.get(), 0 if self.eager else 1) + + def test_recursive_taskgroups(self): + num_tasks = self.loop.run_until_complete(recursive_taskgroups(5, 4)) + self.assertEqual(self.counter.get(), self.expected_task_count) + + def test_recursive_gather(self): + self.loop.run_until_complete(recursive_gather(5, 4)) + self.assertEqual(self.counter.get(), self.expected_task_count) + + +class BaseNonEagerTaskFactoryTests(BaseTaskCountingTests): + eager = False + expected_task_count = 781 # 1 + 5 + 5^2 + 5^3 + 5^4 + + +class BaseEagerTaskFactoryTests(BaseTaskCountingTests): + eager = True + expected_task_count = 0 + + +class NonEagerTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): + Task = asyncio.Task + + +class EagerTests(BaseEagerTaskFactoryTests, test_utils.TestCase): + Task = asyncio.Task + + +class NonEagerPyTaskTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): + Task = tasks._PyTask + + +class EagerPyTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase): + Task = tasks._PyTask + + + at unittest.skipUnless(hasattr(tasks, '_CTask'), + 'requires the C _asyncio module') +class NonEagerCTaskTests(BaseNonEagerTaskFactoryTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + + + at unittest.skipUnless(hasattr(tasks, '_CTask'), + 'requires the C _asyncio module') +class EagerCTaskTests(BaseEagerTaskFactoryTests, test_utils.TestCase): + Task = getattr(tasks, '_CTask', None) + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst b/Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst new file mode 100644 index 000000000000..0b3854d74eb9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst @@ -0,0 +1,6 @@ +Implemented an eager task factory in asyncio. +When used as a task factory on an event loop, it performs eager execution of +coroutines. Coroutines that are able to complete synchronously (e.g. return or +raise without blocking) are returned immediately as a finished task, and the +task is never scheduled to the event loop. If the coroutine blocks, the +(pending) task is scheduled and returned. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 82dbc087322a..8b1a29b6d33e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -8,6 +8,7 @@ #include "pycore_runtime_init.h" // _Py_ID() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef +#include "cpython/context.h" #include // offsetof() @@ -31,8 +32,11 @@ typedef struct { all running event loops. {EventLoop: Task} */ PyObject *current_tasks; - /* WeakSet containing all alive tasks. */ - PyObject *all_tasks; + /* WeakSet containing all tasks scheduled to run on event loops. */ + PyObject *scheduled_tasks; + + /* Set containing all eagerly executing tasks. */ + PyObject *eager_tasks; /* An isinstance type cache for the 'is_coroutine()' function. */ PyObject *iscoroutine_typecache; @@ -156,6 +160,9 @@ class _asyncio.Future "FutureObj *" "&Future_Type" /* Get FutureIter from Future */ static PyObject * future_new_iter(PyObject *); +static PyObject * +task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result); + static int _is_coroutine(asyncio_state *state, PyObject *coro) @@ -1830,6 +1837,7 @@ class _asyncio.Task "TaskObj *" "&Task_Type" static int task_call_step_soon(asyncio_state *state, TaskObj *, PyObject *); static PyObject * task_wakeup(TaskObj *, PyObject *); static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *); +static int task_eager_start(asyncio_state *state, TaskObj *task); /* ----- Task._step wrapper */ @@ -1940,7 +1948,7 @@ static PyMethodDef TaskWakeupDef = { static int register_task(asyncio_state *state, PyObject *task) { - PyObject *res = PyObject_CallMethodOneArg(state->all_tasks, + PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks, &_Py_ID(add), task); if (res == NULL) { return -1; @@ -1949,11 +1957,16 @@ register_task(asyncio_state *state, PyObject *task) return 0; } +static int +register_eager_task(asyncio_state *state, PyObject *task) +{ + return PySet_Add(state->eager_tasks, task); +} static int unregister_task(asyncio_state *state, PyObject *task) { - PyObject *res = PyObject_CallMethodOneArg(state->all_tasks, + PyObject *res = PyObject_CallMethodOneArg(state->scheduled_tasks, &_Py_ID(discard), task); if (res == NULL) { return -1; @@ -1962,6 +1975,11 @@ unregister_task(asyncio_state *state, PyObject *task) return 0; } +static int +unregister_eager_task(asyncio_state *state, PyObject *task) +{ + return PySet_Discard(state->eager_tasks, task); +} static int enter_task(asyncio_state *state, PyObject *loop, PyObject *task) @@ -2015,6 +2033,54 @@ leave_task(asyncio_state *state, PyObject *loop, PyObject *task) return _PyDict_DelItem_KnownHash(state->current_tasks, loop, hash); } +static PyObject * +swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task) +{ + PyObject *prev_task; + Py_hash_t hash; + hash = PyObject_Hash(loop); + if (hash == -1) { + return NULL; + } + + prev_task = _PyDict_GetItem_KnownHash(state->current_tasks, loop, hash); + if (prev_task == NULL) { + if (PyErr_Occurred()) { + return NULL; + } + prev_task = Py_None; + } + + if (task == Py_None) { + if (_PyDict_DelItem_KnownHash(state->current_tasks, loop, hash) == -1) { + return NULL; + } + } else { + if (_PyDict_SetItem_KnownHash(state->current_tasks, loop, task, hash) == -1) { + return NULL; + } + } + + Py_INCREF(prev_task); + + return prev_task; +} + +static int +is_loop_running(PyObject *loop) +{ + PyObject *func = PyObject_GetAttr(loop, &_Py_ID(is_running)); + if (func == NULL) { + PyErr_Format(PyExc_TypeError, "Loop missing is_running()"); + return -1; + } + PyObject *res = PyObject_CallNoArgs(func); + int retval = Py_IsTrue(res); + Py_DECREF(func); + Py_DECREF(res); + return !!retval; +} + /* ----- Task */ /*[clinic input] @@ -2025,15 +2091,16 @@ _asyncio.Task.__init__ loop: object = None name: object = None context: object = None + eager_start: bool = False A coroutine wrapped in a Future. [clinic start generated code]*/ static int _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, - PyObject *name, PyObject *context) -/*[clinic end generated code: output=49ac96fe33d0e5c7 input=924522490c8ce825]*/ - + PyObject *name, PyObject *context, + int eager_start) +/*[clinic end generated code: output=7aced2d27836f1a1 input=18e3f113a51b829d]*/ { if (future_init((FutureObj*)self, loop)) { return -1; @@ -2083,6 +2150,19 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, return -1; } + if (eager_start) { + int loop_running = is_loop_running(self->task_loop); + if (loop_running == -1) { + return -1; + } + if (loop_running) { + if (task_eager_start(state, self)) { + return -1; + } + return 0; + } + } + if (task_call_step_soon(state, self, NULL)) { return -1; } @@ -2831,6 +2911,20 @@ task_step_impl(asyncio_state *state, TaskObj *task, PyObject *exc) Py_RETURN_NONE; } + PyObject *ret = task_step_handle_result_impl(state, task, result); + return ret; + +fail: + return NULL; +} + + +static PyObject * +task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *result) +{ + int res; + PyObject *o; + if (result == (PyObject*)task) { /* We have a task that wants to await on itself */ goto self_await; @@ -3062,6 +3156,65 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc) } } +static int +task_eager_start(asyncio_state *state, TaskObj *task) +{ + assert(task != NULL); + PyObject *prevtask = swap_current_task(state, task->task_loop, (PyObject *)task); + if (prevtask == NULL) { + return -1; + } + + if (register_eager_task(state, (PyObject *)task) == -1) { + Py_DECREF(prevtask); + return -1; + } + + if (PyContext_Enter(task->task_context) == -1) { + Py_DECREF(prevtask); + return -1; + } + + int retval = 0; + + PyObject *stepres = task_step_impl(state, task, NULL); + if (stepres == NULL) { + PyObject *exc = PyErr_GetRaisedException(); + _PyErr_ChainExceptions1(exc); + retval = -1; + } else { + Py_DECREF(stepres); + } + + PyObject *curtask = swap_current_task(state, task->task_loop, prevtask); + Py_DECREF(prevtask); + if (curtask == NULL) { + retval = -1; + } else { + assert(curtask == (PyObject *)task); + Py_DECREF(curtask); + } + + if (unregister_eager_task(state, (PyObject *)task) == -1) { + retval = -1; + } + + if (PyContext_Exit(task->task_context) == -1) { + retval = -1; + } + + if (task->task_state == STATE_PENDING) { + if (register_task(state, (PyObject *)task) == -1) { + retval = -1; + } + } else { + // This seems to really help performance on pyperformance benchmarks + Py_CLEAR(task->task_coro); + } + + return retval; +} + static PyObject * task_wakeup(TaskObj *task, PyObject *o) { @@ -3225,6 +3378,27 @@ _asyncio__register_task_impl(PyObject *module, PyObject *task) Py_RETURN_NONE; } +/*[clinic input] +_asyncio._register_eager_task + + task: object + +Register a new task in asyncio as executed by loop. + +Returns None. +[clinic start generated code]*/ + +static PyObject * +_asyncio__register_eager_task_impl(PyObject *module, PyObject *task) +/*[clinic end generated code: output=dfe1d45367c73f1a input=237f684683398c51]*/ +{ + asyncio_state *state = get_asyncio_state(module); + if (register_eager_task(state, task) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + /*[clinic input] _asyncio._unregister_task @@ -3247,6 +3421,27 @@ _asyncio__unregister_task_impl(PyObject *module, PyObject *task) Py_RETURN_NONE; } +/*[clinic input] +_asyncio._unregister_eager_task + + task: object + +Unregister a task. + +Returns None. +[clinic start generated code]*/ + +static PyObject * +_asyncio__unregister_eager_task_impl(PyObject *module, PyObject *task) +/*[clinic end generated code: output=a426922bd07f23d1 input=9d07401ef14ee048]*/ +{ + asyncio_state *state = get_asyncio_state(module); + if (unregister_eager_task(state, task) < 0) { + return NULL; + } + Py_RETURN_NONE; +} + /*[clinic input] _asyncio._enter_task @@ -3298,6 +3493,27 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task) } +/*[clinic input] +_asyncio._swap_current_task + + loop: object + task: object + +Temporarily swap in the supplied task and return the original one (or None). + +This is intended for use during eager coroutine execution. + +[clinic start generated code]*/ + +static PyObject * +_asyncio__swap_current_task_impl(PyObject *module, PyObject *loop, + PyObject *task) +/*[clinic end generated code: output=9f88de958df74c7e input=c9c72208d3d38b6c]*/ +{ + return swap_current_task(get_asyncio_state(module), loop, task); +} + + /*[clinic input] _asyncio.current_task @@ -3379,7 +3595,8 @@ module_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->asyncio_InvalidStateError); Py_VISIT(state->asyncio_CancelledError); - Py_VISIT(state->all_tasks); + Py_VISIT(state->scheduled_tasks); + Py_VISIT(state->eager_tasks); Py_VISIT(state->current_tasks); Py_VISIT(state->iscoroutine_typecache); @@ -3416,7 +3633,8 @@ module_clear(PyObject *mod) Py_CLEAR(state->asyncio_InvalidStateError); Py_CLEAR(state->asyncio_CancelledError); - Py_CLEAR(state->all_tasks); + Py_CLEAR(state->scheduled_tasks); + Py_CLEAR(state->eager_tasks); Py_CLEAR(state->current_tasks); Py_CLEAR(state->iscoroutine_typecache); @@ -3496,9 +3714,14 @@ module_init(asyncio_state *state) PyObject *weak_set; WITH_MOD("weakref") GET_MOD_ATTR(weak_set, "WeakSet"); - state->all_tasks = PyObject_CallNoArgs(weak_set); + state->scheduled_tasks = PyObject_CallNoArgs(weak_set); Py_CLEAR(weak_set); - if (state->all_tasks == NULL) { + if (state->scheduled_tasks == NULL) { + goto fail; + } + + state->eager_tasks = PySet_New(NULL); + if (state->eager_tasks == NULL) { goto fail; } @@ -3522,9 +3745,12 @@ static PyMethodDef asyncio_methods[] = { _ASYNCIO__GET_RUNNING_LOOP_METHODDEF _ASYNCIO__SET_RUNNING_LOOP_METHODDEF _ASYNCIO__REGISTER_TASK_METHODDEF + _ASYNCIO__REGISTER_EAGER_TASK_METHODDEF _ASYNCIO__UNREGISTER_TASK_METHODDEF + _ASYNCIO__UNREGISTER_EAGER_TASK_METHODDEF _ASYNCIO__ENTER_TASK_METHODDEF _ASYNCIO__LEAVE_TASK_METHODDEF + _ASYNCIO__SWAP_CURRENT_TASK_METHODDEF {NULL, NULL} }; @@ -3561,7 +3787,11 @@ module_exec(PyObject *mod) return -1; } - if (PyModule_AddObjectRef(mod, "_all_tasks", state->all_tasks) < 0) { + if (PyModule_AddObjectRef(mod, "_scheduled_tasks", state->scheduled_tasks) < 0) { + return -1; + } + + if (PyModule_AddObjectRef(mod, "_eager_tasks", state->eager_tasks) < 0) { return -1; } diff --git a/Modules/clinic/_asynciomodule.c.h b/Modules/clinic/_asynciomodule.c.h index 43c5d7717986..6a780a80cd0b 100644 --- a/Modules/clinic/_asynciomodule.c.h +++ b/Modules/clinic/_asynciomodule.c.h @@ -482,14 +482,15 @@ _asyncio_Future__make_cancelled_error(FutureObj *self, PyObject *Py_UNUSED(ignor } PyDoc_STRVAR(_asyncio_Task___init____doc__, -"Task(coro, *, loop=None, name=None, context=None)\n" +"Task(coro, *, loop=None, name=None, context=None, eager_start=False)\n" "--\n" "\n" "A coroutine wrapped in a Future."); static int _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, - PyObject *name, PyObject *context); + PyObject *name, PyObject *context, + int eager_start); static int _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) @@ -497,14 +498,14 @@ _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) int return_value = -1; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 4 + #define NUM_KEYWORDS 5 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(coro), &_Py_ID(loop), &_Py_ID(name), &_Py_ID(context), }, + .ob_item = { &_Py_ID(coro), &_Py_ID(loop), &_Py_ID(name), &_Py_ID(context), &_Py_ID(eager_start), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -513,14 +514,14 @@ _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"coro", "loop", "name", "context", NULL}; + static const char * const _keywords[] = {"coro", "loop", "name", "context", "eager_start", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "Task", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[4]; + PyObject *argsbuf[5]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; @@ -528,6 +529,7 @@ _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *loop = Py_None; PyObject *name = Py_None; PyObject *context = Py_None; + int eager_start = 0; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); if (!fastargs) { @@ -549,9 +551,18 @@ _asyncio_Task___init__(PyObject *self, PyObject *args, PyObject *kwargs) goto skip_optional_kwonly; } } - context = fastargs[3]; + if (fastargs[3]) { + context = fastargs[3]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + eager_start = PyObject_IsTrue(fastargs[4]); + if (eager_start < 0) { + goto exit; + } skip_optional_kwonly: - return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop, name, context); + return_value = _asyncio_Task___init___impl((TaskObj *)self, coro, loop, name, context, eager_start); exit: return return_value; @@ -1064,6 +1075,63 @@ _asyncio__register_task(PyObject *module, PyObject *const *args, Py_ssize_t narg return return_value; } +PyDoc_STRVAR(_asyncio__register_eager_task__doc__, +"_register_eager_task($module, /, task)\n" +"--\n" +"\n" +"Register a new task in asyncio as executed by loop.\n" +"\n" +"Returns None."); + +#define _ASYNCIO__REGISTER_EAGER_TASK_METHODDEF \ + {"_register_eager_task", _PyCFunction_CAST(_asyncio__register_eager_task), METH_FASTCALL|METH_KEYWORDS, _asyncio__register_eager_task__doc__}, + +static PyObject * +_asyncio__register_eager_task_impl(PyObject *module, PyObject *task); + +static PyObject * +_asyncio__register_eager_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(task), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"task", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_register_eager_task", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *task; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + task = args[0]; + return_value = _asyncio__register_eager_task_impl(module, task); + +exit: + return return_value; +} + PyDoc_STRVAR(_asyncio__unregister_task__doc__, "_unregister_task($module, /, task)\n" "--\n" @@ -1121,6 +1189,63 @@ _asyncio__unregister_task(PyObject *module, PyObject *const *args, Py_ssize_t na return return_value; } +PyDoc_STRVAR(_asyncio__unregister_eager_task__doc__, +"_unregister_eager_task($module, /, task)\n" +"--\n" +"\n" +"Unregister a task.\n" +"\n" +"Returns None."); + +#define _ASYNCIO__UNREGISTER_EAGER_TASK_METHODDEF \ + {"_unregister_eager_task", _PyCFunction_CAST(_asyncio__unregister_eager_task), METH_FASTCALL|METH_KEYWORDS, _asyncio__unregister_eager_task__doc__}, + +static PyObject * +_asyncio__unregister_eager_task_impl(PyObject *module, PyObject *task); + +static PyObject * +_asyncio__unregister_eager_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(task), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"task", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_unregister_eager_task", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *task; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + task = args[0]; + return_value = _asyncio__unregister_eager_task_impl(module, task); + +exit: + return return_value; +} + PyDoc_STRVAR(_asyncio__enter_task__doc__, "_enter_task($module, /, loop, task)\n" "--\n" @@ -1243,6 +1368,66 @@ _asyncio__leave_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, return return_value; } +PyDoc_STRVAR(_asyncio__swap_current_task__doc__, +"_swap_current_task($module, /, loop, task)\n" +"--\n" +"\n" +"Temporarily swap in the supplied task and return the original one (or None).\n" +"\n" +"This is intended for use during eager coroutine execution."); + +#define _ASYNCIO__SWAP_CURRENT_TASK_METHODDEF \ + {"_swap_current_task", _PyCFunction_CAST(_asyncio__swap_current_task), METH_FASTCALL|METH_KEYWORDS, _asyncio__swap_current_task__doc__}, + +static PyObject * +_asyncio__swap_current_task_impl(PyObject *module, PyObject *loop, + PyObject *task); + +static PyObject * +_asyncio__swap_current_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(loop), &_Py_ID(task), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"loop", "task", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_swap_current_task", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject *loop; + PyObject *task; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + loop = args[0]; + task = args[1]; + return_value = _asyncio__swap_current_task_impl(module, loop, task); + +exit: + return return_value; +} + PyDoc_STRVAR(_asyncio_current_task__doc__, "current_task($module, /, loop=None)\n" "--\n" @@ -1302,4 +1487,4 @@ _asyncio_current_task(PyObject *module, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=00f494214f2fd008 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6b0e283177b07639 input=a9049054013a1b77]*/ From webhook-mailer at python.org Mon May 1 17:29:38 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 01 May 2023 21:29:38 -0000 Subject: [Python-checkins] gh-87092: Expose assembler to unit tests (#103988) Message-ID: https://github.com/python/cpython/commit/80b714835d6f5e1cb8fbc486f9575b5eee9f007e commit: 80b714835d6f5e1cb8fbc486f9575b5eee9f007e branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-01T22:29:30+01:00 summary: gh-87092: Expose assembler to unit tests (#103988) files: A Lib/test/test_compiler_assemble.py M Include/internal/pycore_compile.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/test/support/bytecode_helper.py M Modules/_testinternalcapi.c M Modules/clinic/_testinternalcapi.c.h M Python/compile.c M Python/flowgraph.c diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 1a032f652ddd..4bd4ef57238f 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -103,6 +103,10 @@ PyAPI_FUNC(PyObject*) _PyCompile_OptimizeCfg( PyObject *instructions, PyObject *consts); +PyAPI_FUNC(PyCodeObject*) +_PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, + PyObject *instructions); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 5e8a8d784127..f0740b68dd11 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1029,6 +1029,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(memlimit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(message)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(metaclass)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(metadata)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(method)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mod)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mode)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 28e82203d8f6..234d5e2a0989 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -517,6 +517,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(memlimit) STRUCT_FOR_ID(message) STRUCT_FOR_ID(metaclass) + STRUCT_FOR_ID(metadata) STRUCT_FOR_ID(method) STRUCT_FOR_ID(mod) STRUCT_FOR_ID(mode) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index dd4471160a4a..16f2147aa8e9 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1023,6 +1023,7 @@ extern "C" { INIT_ID(memlimit), \ INIT_ID(message), \ INIT_ID(metaclass), \ + INIT_ID(metadata), \ INIT_ID(method), \ INIT_ID(mod), \ INIT_ID(mode), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 1a8338b341fd..cd41b731537f 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1404,6 +1404,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(metaclass); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(metadata); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(method); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/test/support/bytecode_helper.py b/Lib/test/support/bytecode_helper.py index 1d9b889c9209..357ec44dbc21 100644 --- a/Lib/test/support/bytecode_helper.py +++ b/Lib/test/support/bytecode_helper.py @@ -3,7 +3,7 @@ import unittest import dis import io -from _testinternalcapi import compiler_codegen, optimize_cfg +from _testinternalcapi import compiler_codegen, optimize_cfg, assemble_code_object _UNSPECIFIED = object() @@ -108,6 +108,18 @@ def normalize_insts(self, insts): res.append((opcode, arg, *loc)) return res + def complete_insts_info(self, insts): + # fill in omitted fields in location, and oparg 0 for ops with no arg. + res = [] + for item in insts: + assert isinstance(item, tuple) + inst = list(item) + opcode = dis.opmap[inst[0]] + oparg = inst[1] + loc = inst[2:] + [-1] * (6 - len(inst)) + res.append((opcode, oparg, *loc)) + return res + class CodegenTestCase(CompilationStepTestCase): @@ -118,20 +130,14 @@ def generate_code(self, ast): class CfgOptimizationTestCase(CompilationStepTestCase): - def complete_insts_info(self, insts): - # fill in omitted fields in location, and oparg 0 for ops with no arg. - res = [] - for item in insts: - assert isinstance(item, tuple) - inst = list(reversed(item)) - opcode = dis.opmap[inst.pop()] - oparg = inst.pop() - loc = inst + [-1] * (4 - len(inst)) - res.append((opcode, oparg, *loc)) - return res - def get_optimized(self, insts, consts): insts = self.normalize_insts(insts) insts = self.complete_insts_info(insts) insts = optimize_cfg(insts, consts) return insts, consts + +class AssemblerTestCase(CompilationStepTestCase): + + def get_code_object(self, filename, insts, metadata): + co = assemble_code_object(filename, insts, metadata) + return co diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py new file mode 100644 index 000000000000..96c1691e24a9 --- /dev/null +++ b/Lib/test/test_compiler_assemble.py @@ -0,0 +1,71 @@ + +import ast +import types + +from test.support.bytecode_helper import AssemblerTestCase + + +# Tests for the code-object creation stage of the compiler. + +class IsolatedAssembleTests(AssemblerTestCase): + + def complete_metadata(self, metadata, filename="myfile.py"): + if metadata is None: + metadata = {} + for key in ['name', 'qualname']: + metadata.setdefault(key, key) + for key in ['consts']: + metadata.setdefault(key, []) + for key in ['names', 'varnames', 'cellvars', 'freevars']: + metadata.setdefault(key, {}) + for key in ['argcount', 'posonlyargcount', 'kwonlyargcount']: + metadata.setdefault(key, 0) + metadata.setdefault('firstlineno', 1) + metadata.setdefault('filename', filename) + return metadata + + def assemble_test(self, insts, metadata, expected): + metadata = self.complete_metadata(metadata) + insts = self.complete_insts_info(insts) + + co = self.get_code_object(metadata['filename'], insts, metadata) + self.assertIsInstance(co, types.CodeType) + + expected_metadata = {} + for key, value in metadata.items(): + if isinstance(value, list): + expected_metadata[key] = tuple(value) + elif isinstance(value, dict): + expected_metadata[key] = tuple(value.keys()) + else: + expected_metadata[key] = value + + for key, value in expected_metadata.items(): + self.assertEqual(getattr(co, "co_" + key), value) + + f = types.FunctionType(co, {}) + for args, res in expected.items(): + self.assertEqual(f(*args), res) + + def test_simple_expr(self): + metadata = { + 'filename' : 'avg.py', + 'name' : 'avg', + 'qualname' : 'stats.avg', + 'consts' : [2], + 'argcount' : 2, + 'varnames' : {'x' : 0, 'y' : 1}, + } + + # code for "return (x+y)/2" + insts = [ + ('RESUME', 0), + ('LOAD_FAST', 0, 1), # 'x' + ('LOAD_FAST', 1, 1), # 'y' + ('BINARY_OP', 0, 1), # '+' + ('LOAD_CONST', 0, 1), # 2 + ('BINARY_OP', 11, 1), # '/' + ('RETURN_VALUE', 1), + ] + expected = {(3, 4) : 3.5, (-100, 200) : 50, (10, 18) : 14} + self.assemble_test(insts, metadata, expected) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 632fac2de0c4..1e38f1aa6349 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -14,7 +14,7 @@ #include "Python.h" #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() -#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg +#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble #include "pycore_fileutils.h" // _Py_normpath #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_gc.h" // PyGC_Head @@ -625,6 +625,68 @@ _testinternalcapi_optimize_cfg_impl(PyObject *module, PyObject *instructions, return _PyCompile_OptimizeCfg(instructions, consts); } +static int +get_nonnegative_int_from_dict(PyObject *dict, const char *key) { + PyObject *obj = PyDict_GetItemString(dict, key); + if (obj == NULL) { + return -1; + } + return PyLong_AsLong(obj); +} + +/*[clinic input] + +_testinternalcapi.assemble_code_object -> object + + filename: object + instructions: object + metadata: object + +Create a code object for the given instructions. +[clinic start generated code]*/ + +static PyObject * +_testinternalcapi_assemble_code_object_impl(PyObject *module, + PyObject *filename, + PyObject *instructions, + PyObject *metadata) +/*[clinic end generated code: output=38003dc16a930f48 input=e713ad77f08fb3a8]*/ + +{ + assert(PyDict_Check(metadata)); + _PyCompile_CodeUnitMetadata umd; + + umd.u_name = PyDict_GetItemString(metadata, "name"); + umd.u_qualname = PyDict_GetItemString(metadata, "qualname"); + + assert(PyUnicode_Check(umd.u_name)); + assert(PyUnicode_Check(umd.u_qualname)); + + umd.u_consts = PyDict_GetItemString(metadata, "consts"); + umd.u_names = PyDict_GetItemString(metadata, "names"); + umd.u_varnames = PyDict_GetItemString(metadata, "varnames"); + umd.u_cellvars = PyDict_GetItemString(metadata, "cellvars"); + umd.u_freevars = PyDict_GetItemString(metadata, "freevars"); + + assert(PyList_Check(umd.u_consts)); + assert(PyDict_Check(umd.u_names)); + assert(PyDict_Check(umd.u_varnames)); + assert(PyDict_Check(umd.u_cellvars)); + assert(PyDict_Check(umd.u_freevars)); + + umd.u_argcount = get_nonnegative_int_from_dict(metadata, "argcount"); + umd.u_posonlyargcount = get_nonnegative_int_from_dict(metadata, "posonlyargcount"); + umd.u_kwonlyargcount = get_nonnegative_int_from_dict(metadata, "kwonlyargcount"); + umd.u_firstlineno = get_nonnegative_int_from_dict(metadata, "firstlineno"); + + assert(umd.u_argcount >= 0); + assert(umd.u_posonlyargcount >= 0); + assert(umd.u_kwonlyargcount >= 0); + assert(umd.u_firstlineno >= 0); + + return (PyObject*)_PyCompile_Assemble(&umd, filename, instructions); +} + static PyObject * get_interp_settings(PyObject *self, PyObject *args) @@ -705,6 +767,7 @@ static PyMethodDef module_functions[] = { {"set_eval_frame_record", set_eval_frame_record, METH_O, NULL}, _TESTINTERNALCAPI_COMPILER_CODEGEN_METHODDEF _TESTINTERNALCAPI_OPTIMIZE_CFG_METHODDEF + _TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF {"get_interp_settings", get_interp_settings, METH_VARARGS, NULL}, {"clear_extension", clear_extension, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ diff --git a/Modules/clinic/_testinternalcapi.c.h b/Modules/clinic/_testinternalcapi.c.h index e8d5681b1949..895732225725 100644 --- a/Modules/clinic/_testinternalcapi.c.h +++ b/Modules/clinic/_testinternalcapi.c.h @@ -128,4 +128,66 @@ _testinternalcapi_optimize_cfg(PyObject *module, PyObject *const *args, Py_ssize exit: return return_value; } -/*[clinic end generated code: output=efe95836482fd542 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_testinternalcapi_assemble_code_object__doc__, +"assemble_code_object($module, /, filename, instructions, metadata)\n" +"--\n" +"\n" +"Create a code object for the given instructions."); + +#define _TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF \ + {"assemble_code_object", _PyCFunction_CAST(_testinternalcapi_assemble_code_object), METH_FASTCALL|METH_KEYWORDS, _testinternalcapi_assemble_code_object__doc__}, + +static PyObject * +_testinternalcapi_assemble_code_object_impl(PyObject *module, + PyObject *filename, + PyObject *instructions, + PyObject *metadata); + +static PyObject * +_testinternalcapi_assemble_code_object(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(filename), &_Py_ID(instructions), &_Py_ID(metadata), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"filename", "instructions", "metadata", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "assemble_code_object", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject *filename; + PyObject *instructions; + PyObject *metadata; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + filename = args[0]; + instructions = args[1]; + metadata = args[2]; + return_value = _testinternalcapi_assemble_code_object_impl(module, filename, instructions, metadata); + +exit: + return return_value; +} +/*[clinic end generated code: output=d5e08c9d67f9721f input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index e8789def8673..cbe5403aafbc 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -308,7 +308,6 @@ instr_sequence_fini(instr_sequence *seq) { seq->s_instrs = NULL; } - static int instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); @@ -6754,11 +6753,11 @@ _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj) static int * -build_cellfixedoffsets(struct compiler_unit *u) +build_cellfixedoffsets(_PyCompile_CodeUnitMetadata *umd) { - 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 nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); int noffsets = ncellvars + nfreevars; int *fixed = PyMem_New(int, noffsets); @@ -6772,8 +6771,8 @@ build_cellfixedoffsets(struct compiler_unit *u) PyObject *varname, *cellindex; Py_ssize_t pos = 0; - while (PyDict_Next(u->u_metadata.u_cellvars, &pos, &varname, &cellindex)) { - PyObject *varindex = PyDict_GetItem(u->u_metadata.u_varnames, varname); + while (PyDict_Next(umd->u_cellvars, &pos, &varname, &cellindex)) { + PyObject *varindex = PyDict_GetItem(umd->u_varnames, varname); if (varindex != NULL) { assert(PyLong_AS_LONG(cellindex) < INT_MAX); assert(PyLong_AS_LONG(varindex) < INT_MAX); @@ -6787,17 +6786,17 @@ build_cellfixedoffsets(struct compiler_unit *u) } static int -insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, +insert_prefix_instructions(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixed, int nfreevars, int code_flags) { - assert(u->u_metadata.u_firstlineno > 0); + assert(umd->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_metadata.u_firstlineno, u->u_metadata.u_firstlineno, -1, -1), + .i_loc = LOCATION(umd->u_firstlineno, umd->u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); @@ -6811,12 +6810,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_metadata.u_cellvars); + const int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); if (ncellvars) { - // u->u_metadata.u_cellvars has the cells out of order so we sort them + // umd->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_metadata.u_varnames); + const int nvars = ncellvars + (int)PyDict_GET_SIZE(umd->u_varnames); int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); if (sorted == NULL) { PyErr_NoMemory(); @@ -6860,11 +6859,11 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, } static int -fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) +fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int *fixedmap) { - 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 nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); int noffsets = ncellvars + nfreevars; // First deal with duplicates (arg cells). @@ -6906,30 +6905,30 @@ 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) +prepare_localsplus(_PyCompile_CodeUnitMetadata *umd, cfg_builder *g, int code_flags) { - 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(PyDict_GET_SIZE(umd->u_varnames) < INT_MAX); + assert(PyDict_GET_SIZE(umd->u_cellvars) < INT_MAX); + assert(PyDict_GET_SIZE(umd->u_freevars) < INT_MAX); + int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(umd->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(umd->u_freevars); assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; - int* cellfixedoffsets = build_cellfixedoffsets(u); + int* cellfixedoffsets = build_cellfixedoffsets(umd); if (cellfixedoffsets == NULL) { return ERROR; } // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(u, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { + if (insert_prefix_instructions(umd, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { PyMem_Free(cellfixedoffsets); return ERROR; } - int numdropped = fix_cell_offsets(u, g->g_entryblock, cellfixedoffsets); + int numdropped = fix_cell_offsets(umd, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. cellfixedoffsets = NULL; if (numdropped < 0) { @@ -6980,7 +6979,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, } /** Assembly **/ - int nlocalsplus = prepare_localsplus(u, &g, code_flags); + int nlocalsplus = prepare_localsplus(&u->u_metadata, &g, code_flags); if (nlocalsplus < 0) { goto error; } @@ -7157,11 +7156,6 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) goto error; } } - if (seq->s_used && !IS_TERMINATOR_OPCODE(seq->s_instrs[seq->s_used-1].i_opcode)) { - if (instr_sequence_addop(seq, RETURN_VALUE, 0, NO_LOCATION) < 0) { - goto error; - } - } PyMem_Free(is_target); return SUCCESS; error: @@ -7328,6 +7322,67 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) return res; } +int _PyCfg_JumpLabelsToTargets(basicblock *entryblock); + +PyCodeObject * +_PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, + PyObject *instructions) +{ + PyCodeObject *co = NULL; + instr_sequence optimized_instrs; + memset(&optimized_instrs, 0, sizeof(instr_sequence)); + + PyObject *const_cache = PyDict_New(); + if (const_cache == NULL) { + return NULL; + } + + cfg_builder g; + if (instructions_to_cfg(instructions, &g) < 0) { + goto error; + } + + if (_PyCfg_JumpLabelsToTargets(g.g_entryblock) < 0) { + goto error; + } + + int code_flags = 0; + int nlocalsplus = prepare_localsplus(umd, &g, code_flags); + if (nlocalsplus < 0) { + goto error; + } + + int maxdepth = _PyCfg_Stackdepth(g.g_entryblock, code_flags); + if (maxdepth < 0) { + goto error; + } + + _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock); + + /* Order of basic blocks must have been determined by now */ + + if (_PyCfg_ResolveJumps(&g) < 0) { + goto error; + } + + /* Can't modify the bytecode after computing jump offsets. */ + + if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) { + goto error; + } + + PyObject *consts = umd->u_consts; + co = _PyAssemble_MakeCodeObject(umd, const_cache, + consts, maxdepth, &optimized_instrs, + nlocalsplus, code_flags, filename); + +error: + Py_DECREF(const_cache); + _PyCfgBuilder_Fini(&g); + instr_sequence_fini(&optimized_instrs); + return co; +} + /* Retained for API compatibility. * Optimization is now done in _PyCfg_OptimizeCodeUnit */ diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 6f83a910cab3..f79afb4c66cd 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -223,6 +223,15 @@ dump_basicblock(const basicblock *b) } } } + +void +_PyCfgBuilder_DumpGraph(const basicblock *entryblock) +{ + for (const basicblock *b = entryblock; b != NULL; b = b->b_next) { + dump_basicblock(b); + } +} + #endif @@ -592,6 +601,11 @@ translate_jump_labels_to_targets(basicblock *entryblock) return SUCCESS; } +int +_PyCfg_JumpLabelsToTargets(basicblock *entryblock) +{ + return translate_jump_labels_to_targets(entryblock); +} static int mark_except_handlers(basicblock *entryblock) { From webhook-mailer at python.org Mon May 1 18:14:55 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 01 May 2023 22:14:55 -0000 Subject: [Python-checkins] gh-104057: Fix direct invocation of test_super (#104064) Message-ID: https://github.com/python/cpython/commit/605f8785db26c3acdde90cfd4ecebb208362a1b8 commit: 605f8785db26c3acdde90cfd4ecebb208362a1b8 branch: main author: Kirill Podoprigora <80244920+Eclips4 at users.noreply.github.com> committer: carljm date: 2023-05-01T16:14:49-06:00 summary: gh-104057: Fix direct invocation of test_super (#104064) files: M Lib/test/test_super.py diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py index ed773a3cff2a..698ab48f48ea 100644 --- a/Lib/test/test_super.py +++ b/Lib/test/test_super.py @@ -359,7 +359,7 @@ class C: def method(self): return super().msg - with patch("test.test_super.super", MySuper) as m: + with patch(f"{__name__}.super", MySuper) as m: self.assertEqual(C().method(), "super super") def test_shadowed_dynamic_two_arg(self): @@ -373,7 +373,7 @@ class C: def method(self): return super(1, 2).msg - with patch("test.test_super.super", MySuper) as m: + with patch(f"{__name__}.super", MySuper) as m: self.assertEqual(C().method(), "super super") self.assertEqual(call_args, [(1, 2)]) From webhook-mailer at python.org Mon May 1 19:55:48 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 01 May 2023 23:55:48 -0000 Subject: [Python-checkins] gh-104016: Skip test for deeply neste f-strings on wasi (#104071) Message-ID: https://github.com/python/cpython/commit/b1ca34d4d5e463b8108eea20090f12292390f0cf commit: b1ca34d4d5e463b8108eea20090f12292390f0cf branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2023-05-01T23:55:41Z summary: gh-104016: Skip test for deeply neste f-strings on wasi (#104071) files: M Lib/test/test_fstring.py diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 5c5176dc54a6..be71fde5aaba 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -561,11 +561,12 @@ def test_mismatched_parens(self): ]) self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'") + @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI") 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 create_nested_fstring(n): if n == 0: return "1+1" @@ -575,13 +576,13 @@ def create_nested_fstring(n): self.assertAllRaise(SyntaxError, "too many nested f-strings", [create_nested_fstring(160)]) - + def test_syntax_error_in_nested_fstring(self): # See gh-104016 for more information on this crash self.assertAllRaise(SyntaxError, "invalid syntax", ['f"{1 1:' + ('{f"1:' * 199)]) - + def test_double_braces(self): self.assertEqual(f'{{', '{') self.assertEqual(f'a{{', 'a{') From webhook-mailer at python.org Mon May 1 21:36:12 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 02 May 2023 01:36:12 -0000 Subject: [Python-checkins] gh-94673: Properly Initialize and Finalize Static Builtin Types for Each Interpreter (gh-104072) Message-ID: https://github.com/python/cpython/commit/fdd878650d325297cd801305bc2d1b0e903e42b4 commit: fdd878650d325297cd801305bc2d1b0e903e42b4 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-05-01T19:36:00-06:00 summary: gh-94673: Properly Initialize and Finalize Static Builtin Types for Each Interpreter (gh-104072) Until now, we haven't been initializing nor finalizing the per-interpreter state properly. files: M Include/internal/pycore_object.h M Include/internal/pycore_pylifecycle.h M Include/internal/pycore_structseq.h M Include/internal/pycore_typeobject.h M Modules/_io/_iomodule.c M Objects/exceptions.c M Objects/floatobject.c M Objects/longobject.c M Objects/object.c M Objects/structseq.c M Objects/typeobject.c M Objects/unicodeobject.c M Objects/weakrefobject.c M Python/errors.c M Python/pylifecycle.c M Python/sysmodule.c M Python/thread.c diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 2ca047846e09..2ee0180c0554 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -272,8 +272,9 @@ _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) { if (PyType_Check(op) && ((PyTypeObject *)op)->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); static_builtin_state *state = _PyStaticType_GetState( - (PyTypeObject *)op); + interp, (PyTypeObject *)op); return _PyStaticType_GET_WEAKREFS_LISTPTR(state); } // Essentially _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(): diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index f96261a650da..7f8cc643ec0c 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -39,7 +39,7 @@ extern PyStatus _PySys_Create( extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options); extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config); extern int _PySys_UpdateConfig(PyThreadState *tstate); -extern void _PySys_Fini(PyInterpreterState *interp); +extern void _PySys_FiniTypes(PyInterpreterState *interp); extern int _PyBuiltins_AddExceptions(PyObject * bltinmod); extern PyStatus _Py_HashRandomization_Init(const PyConfig *); diff --git a/Include/internal/pycore_structseq.h b/Include/internal/pycore_structseq.h index bd1e85c6883f..6f5dfc12707c 100644 --- a/Include/internal/pycore_structseq.h +++ b/Include/internal/pycore_structseq.h @@ -16,18 +16,22 @@ PyAPI_FUNC(PyTypeObject *) _PyStructSequence_NewType( unsigned long tp_flags); extern int _PyStructSequence_InitBuiltinWithFlags( + PyInterpreterState *interp, PyTypeObject *type, PyStructSequence_Desc *desc, unsigned long tp_flags); static inline int -_PyStructSequence_InitBuiltin(PyTypeObject *type, +_PyStructSequence_InitBuiltin(PyInterpreterState *interp, + PyTypeObject *type, PyStructSequence_Desc *desc) { - return _PyStructSequence_InitBuiltinWithFlags(type, desc, 0); + return _PyStructSequence_InitBuiltinWithFlags(interp, type, desc, 0); } -extern void _PyStructSequence_FiniBuiltin(PyTypeObject *type); +extern void _PyStructSequence_FiniBuiltin( + PyInterpreterState *interp, + PyTypeObject *type); #ifdef __cplusplus } diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 76253fd5fd86..5bd04736c01d 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -104,10 +104,10 @@ _PyType_GetModuleState(PyTypeObject *type) } -extern int _PyStaticType_InitBuiltin(PyTypeObject *type); -extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *); -extern void _PyStaticType_ClearWeakRefs(PyTypeObject *type); -extern void _PyStaticType_Dealloc(PyTypeObject *type); +extern int _PyStaticType_InitBuiltin(PyInterpreterState *, PyTypeObject *type); +extern static_builtin_state * _PyStaticType_GetState(PyInterpreterState *, PyTypeObject *); +extern void _PyStaticType_ClearWeakRefs(PyInterpreterState *, PyTypeObject *type); +extern void _PyStaticType_Dealloc(PyInterpreterState *, PyTypeObject *); PyObject * _Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress_missing_attribute); diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index a3bfbc9ac5a1..8ec3a6081c98 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -680,7 +680,7 @@ _PyIO_InitTypes(PyInterpreterState *interp) for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; - if (_PyStaticType_InitBuiltin(type) < 0) { + if (_PyStaticType_InitBuiltin(interp, type) < 0) { return _PyStatus_ERR("Can't initialize builtin type"); } } @@ -691,15 +691,11 @@ _PyIO_InitTypes(PyInterpreterState *interp) void _PyIO_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - // Deallocate types in the reverse order to deallocate subclasses before // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { PyTypeObject *type = static_types[i]; - _PyStaticType_Dealloc(type); + _PyStaticType_Dealloc(interp, type); } } diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 6c9dfbd9b415..ba5ee291f08b 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3598,7 +3598,7 @@ _PyExc_InitTypes(PyInterpreterState *interp) { for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) { PyTypeObject *exc = static_exceptions[i].exc; - if (_PyStaticType_InitBuiltin(exc) < 0) { + if (_PyStaticType_InitBuiltin(interp, exc) < 0) { return -1; } } @@ -3609,13 +3609,9 @@ _PyExc_InitTypes(PyInterpreterState *interp) static void _PyExc_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - for (Py_ssize_t i=Py_ARRAY_LENGTH(static_exceptions) - 1; i >= 0; i--) { PyTypeObject *exc = static_exceptions[i].exc; - _PyStaticType_Dealloc(exc); + _PyStaticType_Dealloc(interp, exc); } } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index a694ddcd019e..d257857d9c61 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1991,8 +1991,9 @@ PyStatus _PyFloat_InitTypes(PyInterpreterState *interp) { /* Init float info */ - if (_PyStructSequence_InitBuiltin(&FloatInfoType, - &floatinfo_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &FloatInfoType, + &floatinfo_desc) < 0) + { return _PyStatus_ERR("can't init float info type"); } @@ -2028,9 +2029,7 @@ _PyFloat_Fini(PyInterpreterState *interp) void _PyFloat_FiniType(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(interp)) { - _PyStructSequence_FiniBuiltin(&FloatInfoType); - } + _PyStructSequence_FiniBuiltin(interp, &FloatInfoType); } /* Print summary info about the state of the optimized allocator */ diff --git a/Objects/longobject.c b/Objects/longobject.c index de043488d7a1..853e934e2107 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -7,7 +7,6 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _Py_SmallInts #include "pycore_object.h" // _PyObject_Init() -#include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() @@ -6352,7 +6351,9 @@ PyStatus _PyLong_InitTypes(PyInterpreterState *interp) { /* initialize int_info */ - if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &Int_InfoType, + &int_info_desc) < 0) + { return _PyStatus_ERR("can't init int info type"); } @@ -6363,9 +6364,5 @@ _PyLong_InitTypes(PyInterpreterState *interp) void _PyLong_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - - _PyStructSequence_FiniBuiltin(&Int_InfoType); + _PyStructSequence_FiniBuiltin(interp, &Int_InfoType); } diff --git a/Objects/object.c b/Objects/object.c index 4ce10cf1192d..ee8690101d3c 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2105,7 +2105,7 @@ _PyTypes_InitTypes(PyInterpreterState *interp) // All other static types (unless initialized elsewhere) for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; - if (_PyStaticType_InitBuiltin(type) < 0) { + if (_PyStaticType_InitBuiltin(interp, type) < 0) { return _PyStatus_ERR("Can't initialize builtin type"); } if (type == &PyType_Type) { @@ -2128,15 +2128,11 @@ _PyTypes_InitTypes(PyInterpreterState *interp) void _PyTypes_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - // Deallocate types in the reverse order to deallocate subclasses before // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) { PyTypeObject *type = static_types[i]; - _PyStaticType_Dealloc(type); + _PyStaticType_Dealloc(interp, type); } } diff --git a/Objects/structseq.c b/Objects/structseq.c index d8f55dc1eae5..ea476bf7a6a9 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -502,7 +502,8 @@ initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc, } int -_PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type, +_PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, + PyTypeObject *type, PyStructSequence_Desc *desc, unsigned long tp_flags) { @@ -536,7 +537,7 @@ _PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type, } #endif - if (_PyStaticType_InitBuiltin(type) < 0) { + if (_PyStaticType_InitBuiltin(interp, type) < 0) { PyErr_Format(PyExc_RuntimeError, "Can't initialize builtin type %s", desc->name); @@ -606,7 +607,7 @@ PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) initialized via _PyStructSequence_InitBuiltinWithFlags(). */ void -_PyStructSequence_FiniBuiltin(PyTypeObject *type) +_PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type) { // Ensure that the type is initialized assert(type->tp_name != NULL); @@ -620,13 +621,15 @@ _PyStructSequence_FiniBuiltin(PyTypeObject *type) return; } - _PyStaticType_Dealloc(type); + _PyStaticType_Dealloc(interp, type); - // Undo _PyStructSequence_InitBuiltinWithFlags(). - type->tp_name = NULL; - PyMem_Free(type->tp_members); - type->tp_members = NULL; - type->tp_base = NULL; + if (_Py_IsMainInterpreter(interp)) { + // Undo _PyStructSequence_InitBuiltinWithFlags(). + type->tp_name = NULL; + PyMem_Free(type->tp_members); + type->tp_members = NULL; + type->tp_base = NULL; + } } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 060d14e254ab..2ed806fb0155 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -69,13 +69,11 @@ static inline PyTypeObject * subclass_from_ref(PyObject *ref); /* helpers for for static builtin types */ -#ifndef NDEBUG static inline int static_builtin_index_is_set(PyTypeObject *self) { return self->tp_subclasses != NULL; } -#endif static inline size_t static_builtin_index_get(PyTypeObject *self) @@ -107,43 +105,46 @@ static_builtin_state_get(PyInterpreterState *interp, PyTypeObject *self) /* For static types we store some state in an array on each interpreter. */ static_builtin_state * -_PyStaticType_GetState(PyTypeObject *self) +_PyStaticType_GetState(PyInterpreterState *interp, PyTypeObject *self) { assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); - PyInterpreterState *interp = _PyInterpreterState_GET(); return static_builtin_state_get(interp, self); } +/* Set the type's per-interpreter state. */ static void -static_builtin_state_init(PyTypeObject *self) +static_builtin_state_init(PyInterpreterState *interp, PyTypeObject *self) { - /* Set the type's per-interpreter state. */ - PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!static_builtin_index_is_set(self)) { + static_builtin_index_set(self, interp->types.num_builtins_initialized); + } + static_builtin_state *state = static_builtin_state_get(interp, self); /* It should only be called once for each builtin type. */ - assert(!static_builtin_index_is_set(self)); - - static_builtin_index_set(self, interp->types.num_builtins_initialized); - interp->types.num_builtins_initialized++; - - static_builtin_state *state = static_builtin_state_get(interp, self); + assert(state->type == NULL); state->type = self; + /* state->tp_subclasses is left NULL until init_subclasses() sets it. */ /* state->tp_weaklist is left NULL until insert_head() or insert_after() (in weakrefobject.c) sets it. */ + + interp->types.num_builtins_initialized++; } +/* Reset the type's per-interpreter state. + This basically undoes what static_builtin_state_init() did. */ static void -static_builtin_state_clear(PyTypeObject *self) +static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self) { - /* Reset the type's per-interpreter state. - This basically undoes what static_builtin_state_init() did. */ - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = static_builtin_state_get(interp, self); + + assert(state->type != NULL); state->type = NULL; assert(state->tp_weaklist == NULL); // It was already cleared out. - static_builtin_index_clear(self); + + if (_Py_IsMainInterpreter(interp)) { + static_builtin_index_clear(self); + } assert(interp->types.num_builtins_initialized > 0); interp->types.num_builtins_initialized--; @@ -4491,33 +4492,37 @@ clear_static_tp_subclasses(PyTypeObject *type) clear_subclasses(type); } +static void +clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type) +{ + if (_Py_IsMainInterpreter(interp)) { + Py_CLEAR(type->tp_dict); + Py_CLEAR(type->tp_bases); + Py_CLEAR(type->tp_mro); + Py_CLEAR(type->tp_cache); + } + clear_static_tp_subclasses(type); +} + void -_PyStaticType_Dealloc(PyTypeObject *type) +_PyStaticType_Dealloc(PyInterpreterState *interp, PyTypeObject *type) { - assert(!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)); + assert(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); + assert(_Py_IsImmortal((PyObject *)type)); type_dealloc_common(type); - Py_CLEAR(type->tp_dict); - Py_CLEAR(type->tp_bases); - Py_CLEAR(type->tp_mro); - Py_CLEAR(type->tp_cache); - clear_static_tp_subclasses(type); + clear_static_type_objects(interp, type); - // PyObject_ClearWeakRefs() raises an exception if Py_REFCNT() != 0 - if (Py_REFCNT(type) == 0) { - PyObject_ClearWeakRefs((PyObject *)type); + if (_Py_IsMainInterpreter(interp)) { + type->tp_flags &= ~Py_TPFLAGS_READY; + type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + type->tp_version_tag = 0; } - type->tp_flags &= ~Py_TPFLAGS_READY; - type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; - type->tp_version_tag = 0; - - if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - _PyStaticType_ClearWeakRefs(type); - static_builtin_state_clear(type); - /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ - } + _PyStaticType_ClearWeakRefs(interp, type); + static_builtin_state_clear(interp, type); + /* We leave _Py_TPFLAGS_STATIC_BUILTIN set on tp_flags. */ } @@ -4564,7 +4569,8 @@ static PyObject * lookup_subclasses(PyTypeObject *self) { if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - static_builtin_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); assert(state != NULL); return state->tp_subclasses; } @@ -4574,8 +4580,9 @@ lookup_subclasses(PyTypeObject *self) int _PyType_HasSubclasses(PyTypeObject *self) { + PyInterpreterState *interp = _PyInterpreterState_GET(); if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN && - _PyStaticType_GetState(self) == NULL) { + _PyStaticType_GetState(interp, self) == NULL) { return 0; } if (lookup_subclasses(self) == NULL) { @@ -6938,7 +6945,8 @@ type_ready_post_checks(PyTypeObject *type) else if (type->tp_dictoffset < (Py_ssize_t)sizeof(PyObject)) { if (type->tp_dictoffset + type->tp_basicsize <= 0) { PyErr_Format(PyExc_SystemError, - "type %s has a tp_dictoffset that is too small"); + "type %s has a tp_dictoffset that is too small", + type->tp_name); } } return 0; @@ -7029,17 +7037,32 @@ PyType_Ready(PyTypeObject *type) } int -_PyStaticType_InitBuiltin(PyTypeObject *self) +_PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) { assert(_Py_IsImmortal((PyObject *)self)); assert(!(self->tp_flags & Py_TPFLAGS_HEAPTYPE)); + assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT)); + assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF)); +#ifndef NDEBUG + int ismain = _Py_IsMainInterpreter(interp); +#endif if (self->tp_flags & Py_TPFLAGS_READY) { + assert(!ismain); assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); + assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG); + + static_builtin_state_init(interp, self); + + /* Per-interpreter tp_subclasses is done lazily. + Otherwise we would initialize it here. */ + assert(_PyType_CheckConsistency(self)); return 0; } + assert(ismain); + self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN; self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; @@ -7047,11 +7070,11 @@ _PyStaticType_InitBuiltin(PyTypeObject *self) self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++; self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; - static_builtin_state_init(self); + static_builtin_state_init(interp, self); int res = type_ready(self); if (res < 0) { - static_builtin_state_clear(self); + static_builtin_state_clear(interp, self); } return res; } @@ -7065,7 +7088,8 @@ init_subclasses(PyTypeObject *self) return NULL; } if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - static_builtin_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); state->tp_subclasses = subclasses; return subclasses; } @@ -7080,7 +7104,8 @@ clear_subclasses(PyTypeObject *self) callers also test if tp_subclasses is NULL to check if a static type has no subclass. */ if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - static_builtin_state *state = _PyStaticType_GetState(self); + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); Py_CLEAR(state->tp_subclasses); return; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7537c12e9268..6ae68cc20f7d 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14573,13 +14573,13 @@ _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) PyStatus _PyUnicode_InitTypes(PyInterpreterState *interp) { - if (_PyStaticType_InitBuiltin(&EncodingMapType) < 0) { + if (_PyStaticType_InitBuiltin(interp, &EncodingMapType) < 0) { goto error; } - if (_PyStaticType_InitBuiltin(&PyFieldNameIter_Type) < 0) { + if (_PyStaticType_InitBuiltin(interp, &PyFieldNameIter_Type) < 0) { goto error; } - if (_PyStaticType_InitBuiltin(&PyFormatterIter_Type) < 0) { + if (_PyStaticType_InitBuiltin(interp, &PyFormatterIter_Type) < 0) { goto error; } return _PyStatus_OK(); @@ -15158,13 +15158,9 @@ unicode_is_finalizing(void) void _PyUnicode_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - - _PyStaticType_Dealloc(&EncodingMapType); - _PyStaticType_Dealloc(&PyFieldNameIter_Type); - _PyStaticType_Dealloc(&PyFormatterIter_Type); + _PyStaticType_Dealloc(interp, &EncodingMapType); + _PyStaticType_Dealloc(interp, &PyFieldNameIter_Type); + _PyStaticType_Dealloc(interp, &PyFormatterIter_Type); } diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index c1afe63ecf66..aee79fc1410b 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -1017,9 +1017,9 @@ PyObject_ClearWeakRefs(PyObject *object) * or anything else. */ void -_PyStaticType_ClearWeakRefs(PyTypeObject *type) +_PyStaticType_ClearWeakRefs(PyInterpreterState *interp, PyTypeObject *type) { - static_builtin_state *state = _PyStaticType_GetState(type); + static_builtin_state *state = _PyStaticType_GetState(interp, type); PyObject **list = _PyStaticType_GET_WEAKREFS_LISTPTR(state); while (*list != NULL) { /* Note that clear_weakref() pops the first ref off the type's diff --git a/Python/errors.c b/Python/errors.c index ce72049b92de..a8000ac94918 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1342,8 +1342,9 @@ static PyStructSequence_Desc UnraisableHookArgs_desc = { PyStatus _PyErr_InitTypes(PyInterpreterState *interp) { - if (_PyStructSequence_InitBuiltin(&UnraisableHookArgsType, - &UnraisableHookArgs_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &UnraisableHookArgsType, + &UnraisableHookArgs_desc) < 0) + { return _PyStatus_ERR("failed to initialize UnraisableHookArgs type"); } return _PyStatus_OK(); @@ -1353,11 +1354,7 @@ _PyErr_InitTypes(PyInterpreterState *interp) void _PyErr_FiniTypes(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - - _PyStructSequence_FiniBuiltin(&UnraisableHookArgsType); + _PyStructSequence_FiniBuiltin(interp, &UnraisableHookArgsType); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ba248d208e42..b8a115236900 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1663,8 +1663,10 @@ flush_std_files(void) static void finalize_interp_types(PyInterpreterState *interp) { + _PyIO_FiniTypes(interp); + _PyUnicode_FiniTypes(interp); - _PySys_Fini(interp); + _PySys_FiniTypes(interp); _PyExc_Fini(interp); _PyAsyncGen_Fini(interp); _PyContext_Fini(interp); @@ -1706,8 +1708,6 @@ finalize_interp_clear(PyThreadState *tstate) /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); - _PyIO_FiniTypes(tstate->interp); - /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. Call _PySys_ClearAuditHooks when PyObject available. */ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 81dabe6102f1..781588b0df4e 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3141,6 +3141,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) { PyObject *version_info; int res; + PyInterpreterState *interp = tstate->interp; /* stdin/stdout/stderr are set in pylifecycle.c */ @@ -3166,7 +3167,9 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("float_info", PyFloat_GetInfo()); SET_SYS("int_info", PyLong_GetInfo()); /* initialize hash_info */ - if (_PyStructSequence_InitBuiltin(&Hash_InfoType, &hash_info_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &Hash_InfoType, + &hash_info_desc) < 0) + { goto type_init_failed; } SET_SYS("hash_info", get_hash_info(tstate)); @@ -3190,7 +3193,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) #define ENSURE_INFO_TYPE(TYPE, DESC) \ do { \ if (_PyStructSequence_InitBuiltinWithFlags( \ - &TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \ + interp, &TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \ goto type_init_failed; \ } \ } while (0) @@ -3226,8 +3229,9 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) SET_SYS("thread_info", PyThread_GetInfo()); /* initialize asyncgen_hooks */ - if (_PyStructSequence_InitBuiltin( - &AsyncGenHooksType, &asyncgen_hooks_desc) < 0) { + if (_PyStructSequence_InitBuiltin(interp, &AsyncGenHooksType, + &asyncgen_hooks_desc) < 0) + { goto type_init_failed; } @@ -3489,20 +3493,20 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) void -_PySys_Fini(PyInterpreterState *interp) +_PySys_FiniTypes(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(interp)) { - _PyStructSequence_FiniBuiltin(&VersionInfoType); - _PyStructSequence_FiniBuiltin(&FlagsType); + _PyStructSequence_FiniBuiltin(interp, &VersionInfoType); + _PyStructSequence_FiniBuiltin(interp, &FlagsType); #if defined(MS_WINDOWS) - _PyStructSequence_FiniBuiltin(&WindowsVersionType); + _PyStructSequence_FiniBuiltin(interp, &WindowsVersionType); #endif - _PyStructSequence_FiniBuiltin(&Hash_InfoType); - _PyStructSequence_FiniBuiltin(&AsyncGenHooksType); + _PyStructSequence_FiniBuiltin(interp, &Hash_InfoType); + _PyStructSequence_FiniBuiltin(interp, &AsyncGenHooksType); #ifdef __EMSCRIPTEN__ + if (_Py_IsMainInterpreter(interp)) { Py_CLEAR(EmscriptenInfoType); -#endif } +#endif } diff --git a/Python/thread.c b/Python/thread.c index f90cd34a0735..7fc53f9b6136 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -137,7 +137,8 @@ PyThread_GetInfo(void) int len; #endif - if (_PyStructSequence_InitBuiltin(&ThreadInfoType, &threadinfo_desc) < 0) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (_PyStructSequence_InitBuiltin(interp, &ThreadInfoType, &threadinfo_desc) < 0) { return NULL; } @@ -191,9 +192,5 @@ PyThread_GetInfo(void) void _PyThread_FiniType(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return; - } - - _PyStructSequence_FiniBuiltin(&ThreadInfoType); + _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType); } From webhook-mailer at python.org Mon May 1 22:34:50 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 02 May 2023 02:34:50 -0000 Subject: [Python-checkins] gh-94673: Hide Objects in PyTypeObject Behind Accessors (gh-104074) Message-ID: https://github.com/python/cpython/commit/f73abf8e03fd370c86fbb2a249fe1e065f7d84b4 commit: f73abf8e03fd370c86fbb2a249fe1e065f7d84b4 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-05-01T20:34:43-06:00 summary: gh-94673: Hide Objects in PyTypeObject Behind Accessors (gh-104074) This makes it much cleaner to move more PyTypeObject fields to PyInterpreterState. files: M Include/internal/pycore_object.h M Include/internal/pycore_typeobject.h M Modules/_abc.c M Objects/structseq.c M Objects/typeobject.c M Python/context.c diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 2ee0180c0554..91853ad0525b 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -331,10 +331,6 @@ extern int _Py_CheckSlotResult( const char *slot_name, int success); -// PyType_Ready() must be called if _PyType_IsReady() is false. -// See also the Py_TPFLAGS_READY flag. -#define _PyType_IsReady(type) ((type)->tp_dict != NULL) - // Test if a type supports weak references static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) { return (type->tp_weaklistoffset != 0); @@ -392,8 +388,6 @@ _PyDictOrValues_SetValues(PyDictOrValues *ptr, PyDictValues *values) extern PyObject ** _PyObject_ComputedDictPointer(PyObject *); extern void _PyObject_FreeInstanceAttributes(PyObject *obj); extern int _PyObject_IsInstanceDictEmpty(PyObject *); -extern int _PyType_HasSubclasses(PyTypeObject *); -extern PyObject* _PyType_GetSubclasses(PyTypeObject *); // Access macro to the members which are floating "behind" the object static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) { diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 5bd04736c01d..f865e51aeba5 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -109,6 +109,20 @@ extern static_builtin_state * _PyStaticType_GetState(PyInterpreterState *, PyTyp extern void _PyStaticType_ClearWeakRefs(PyInterpreterState *, PyTypeObject *type); extern void _PyStaticType_Dealloc(PyInterpreterState *, PyTypeObject *); +PyAPI_FUNC(PyObject *) _PyType_GetDict(PyTypeObject *); +extern PyObject * _PyType_GetBases(PyTypeObject *type); +extern PyObject * _PyType_GetMRO(PyTypeObject *type); +extern PyObject* _PyType_GetSubclasses(PyTypeObject *); +extern int _PyType_HasSubclasses(PyTypeObject *); + +// PyType_Ready() must be called if _PyType_IsReady() is false. +// See also the Py_TPFLAGS_READY flag. +static inline int +_PyType_IsReady(PyTypeObject *type) +{ + return _PyType_GetDict(type) != NULL; +} + PyObject * _Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress_missing_attribute); PyObject * diff --git a/Modules/_abc.c b/Modules/_abc.c index 9d6654b4e58a..997b618d557a 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -452,7 +452,8 @@ _abc__abc_init(PyObject *module, PyObject *self) * their special status w.r.t. pattern matching. */ if (PyType_Check(self)) { PyTypeObject *cls = (PyTypeObject *)self; - PyObject *flags = PyDict_GetItemWithError(cls->tp_dict, + PyObject *dict = _PyType_GetDict(cls); + PyObject *flags = PyDict_GetItemWithError(dict, &_Py_ID(__abc_tpflags__)); if (flags == NULL) { if (PyErr_Occurred()) { @@ -471,7 +472,7 @@ _abc__abc_init(PyObject *module, PyObject *self) } ((PyTypeObject *)self)->tp_flags |= (val & COLLECTION_FLAGS); } - if (PyDict_DelItem(cls->tp_dict, &_Py_ID(__abc_tpflags__)) < 0) { + if (PyDict_DelItem(dict, &_Py_ID(__abc_tpflags__)) < 0) { return NULL; } } @@ -742,7 +743,7 @@ _abc__abc_subclasscheck_impl(PyObject *module, PyObject *self, Py_DECREF(ok); /* 4. Check if it's a direct subclass. */ - PyObject *mro = ((PyTypeObject *)subclass)->tp_mro; + PyObject *mro = _PyType_GetMRO((PyTypeObject *)subclass); assert(PyTuple_Check(mro)); for (pos = 0; pos < PyTuple_GET_SIZE(mro); pos++) { PyObject *mro_item = PyTuple_GET_ITEM(mro, pos); diff --git a/Objects/structseq.c b/Objects/structseq.c index ea476bf7a6a9..f63660acb639 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -26,7 +26,7 @@ const char * const PyStructSequence_UnnamedField = "unnamed field"; static Py_ssize_t get_type_attr_as_size(PyTypeObject *tp, PyObject *name) { - PyObject *v = PyDict_GetItemWithError(tp->tp_dict, name); + PyObject *v = PyDict_GetItemWithError(_PyType_GetDict(tp), name); if (v == NULL && !PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "Missed attribute '%U' of type %s", @@ -493,7 +493,7 @@ initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc, Py_INCREF(type); if (initialize_structseq_dict( - desc, type->tp_dict, n_members, n_unnamed_members) < 0) { + desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) { Py_DECREF(type); return -1; } @@ -549,7 +549,7 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, } if (initialize_structseq_dict( - desc, type->tp_dict, n_members, n_unnamed_members) < 0) { + desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) { goto error; } @@ -675,7 +675,7 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags) } if (initialize_structseq_dict( - desc, type->tp_dict, n_members, n_unnamed_members) < 0) { + desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) { Py_DECREF(type); return NULL; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2ed806fb0155..a9d3a69263fb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -64,7 +64,19 @@ lookup_maybe_method(PyObject *self, PyObject *attr, int *unbound); static int slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value); -static inline PyTypeObject * subclass_from_ref(PyObject *ref); + +static inline PyTypeObject * +type_from_ref(PyObject *ref) +{ + assert(PyWeakref_CheckRef(ref)); + PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref + assert(obj != NULL); + if (obj == Py_None) { + return NULL; + } + assert(PyType_Check(obj)); + return _PyType_CAST(obj); +} /* helpers for for static builtin types */ @@ -155,6 +167,178 @@ static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self) /* end static builtin helpers */ +/* accessors for objects stored on PyTypeObject */ + +static inline PyObject * +lookup_tp_dict(PyTypeObject *self) +{ + return self->tp_dict; +} + +PyObject * +_PyType_GetDict(PyTypeObject *self) +{ + return lookup_tp_dict(self); +} + +static inline void +set_tp_dict(PyTypeObject *self, PyObject *dict) +{ + self->tp_dict = dict; +} + +static inline void +clear_tp_dict(PyTypeObject *self) +{ + Py_CLEAR(self->tp_dict); +} + + +static inline PyObject * +lookup_tp_bases(PyTypeObject *self) +{ + return self->tp_bases; +} + +PyObject * +_PyType_GetBases(PyTypeObject *self) +{ + return lookup_tp_bases(self); +} + +static inline void +set_tp_bases(PyTypeObject *self, PyObject *bases) +{ + self->tp_bases = bases; +} + +static inline void +clear_tp_bases(PyTypeObject *self) +{ + Py_CLEAR(self->tp_bases); +} + + +static inline PyObject * +lookup_tp_mro(PyTypeObject *self) +{ + return self->tp_mro; +} + +PyObject * +_PyType_GetMRO(PyTypeObject *self) +{ + return lookup_tp_mro(self); +} + +static inline void +set_tp_mro(PyTypeObject *self, PyObject *mro) +{ + self->tp_mro = mro; +} + +static inline void +clear_tp_mro(PyTypeObject *self) +{ + Py_CLEAR(self->tp_mro); +} + + +static PyObject * +init_tp_subclasses(PyTypeObject *self) +{ + PyObject *subclasses = PyDict_New(); + if (subclasses == NULL) { + return NULL; + } + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + state->tp_subclasses = subclasses; + return subclasses; + } + self->tp_subclasses = (void *)subclasses; + return subclasses; +} + +static void +clear_tp_subclasses(PyTypeObject *self) +{ + /* Delete the dictionary to save memory. _PyStaticType_Dealloc() + callers also test if tp_subclasses is NULL to check if a static type + has no subclass. */ + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + Py_CLEAR(state->tp_subclasses); + return; + } + Py_CLEAR(self->tp_subclasses); +} + +static inline PyObject * +lookup_tp_subclasses(PyTypeObject *self) +{ + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + return state->tp_subclasses; + } + return (PyObject *)self->tp_subclasses; +} + +int +_PyType_HasSubclasses(PyTypeObject *self) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN + // XXX _PyStaticType_GetState() should never return NULL. + && _PyStaticType_GetState(interp, self) == NULL) + { + return 0; + } + if (lookup_tp_subclasses(self) == NULL) { + return 0; + } + return 1; +} + +PyObject* +_PyType_GetSubclasses(PyTypeObject *self) +{ + PyObject *list = PyList_New(0); + if (list == NULL) { + return NULL; + } + + PyObject *subclasses = lookup_tp_subclasses(self); // borrowed ref + if (subclasses == NULL) { + return list; + } + assert(PyDict_CheckExact(subclasses)); + // The loop cannot modify tp_subclasses, there is no need + // to hold a strong reference (use a borrowed reference). + + Py_ssize_t i = 0; + PyObject *ref; // borrowed ref + while (PyDict_Next(subclasses, &i, NULL, &ref)) { + PyTypeObject *subclass = type_from_ref(ref); // borrowed + if (subclass == NULL) { + continue; + } + + if (PyList_Append(list, _PyObject_CAST(subclass)) < 0) { + Py_DECREF(list); + return NULL; + } + } + return list; +} + +/* end accessors for objects stored on PyTypeObject */ + + /* * finds the beginning of the docstring's introspection signature. * if present, returns a pointer pointing to the first '('. @@ -225,7 +409,7 @@ _PyType_CheckConsistency(PyTypeObject *type) CHECK(PyType_Check(type)); CHECK(!(type->tp_flags & Py_TPFLAGS_READYING)); - CHECK(type->tp_dict != NULL); + CHECK(lookup_tp_dict(type) != NULL); if (type->tp_flags & Py_TPFLAGS_HAVE_GC) { // bpo-44263: tp_traverse is required if Py_TPFLAGS_HAVE_GC is set. @@ -235,7 +419,7 @@ _PyType_CheckConsistency(PyTypeObject *type) if (type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION) { CHECK(type->tp_new == NULL); - CHECK(PyDict_Contains(type->tp_dict, &_Py_ID(__new__)) == 0); + CHECK(PyDict_Contains(lookup_tp_dict(type), &_Py_ID(__new__)) == 0); } return 1; @@ -361,8 +545,6 @@ _PyTypes_Fini(PyInterpreterState *interp) } -static PyObject * lookup_subclasses(PyTypeObject *); - int PyType_AddWatcher(PyType_WatchCallback callback) { @@ -462,14 +644,14 @@ PyType_Modified(PyTypeObject *type) return; } - PyObject *subclasses = lookup_subclasses(type); + PyObject *subclasses = lookup_tp_subclasses(type); if (subclasses != NULL) { assert(PyDict_CheckExact(subclasses)); Py_ssize_t i = 0; PyObject *ref; while (PyDict_Next(subclasses, &i, NULL, &ref)) { - PyTypeObject *subclass = subclass_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); // borrowed if (subclass == NULL) { continue; } @@ -598,7 +780,7 @@ assign_version_tag(PyInterpreterState *interp, PyTypeObject *type) assert (type->tp_version_tag != 0); } - PyObject *bases = type->tp_bases; + PyObject *bases = lookup_tp_bases(type); Py_ssize_t n = PyTuple_GET_SIZE(bases); for (Py_ssize_t i = 0; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(bases, i); @@ -749,7 +931,8 @@ type_module(PyTypeObject *type, void *context) PyObject *mod; if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - mod = PyDict_GetItemWithError(type->tp_dict, &_Py_ID(__module__)); + PyObject *dict = lookup_tp_dict(type); + mod = PyDict_GetItemWithError(dict, &_Py_ID(__module__)); if (mod == NULL) { if (!PyErr_Occurred()) { PyErr_Format(PyExc_AttributeError, "__module__"); @@ -781,7 +964,8 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context) PyType_Modified(type); - return PyDict_SetItem(type->tp_dict, &_Py_ID(__module__), value); + PyObject *dict = lookup_tp_dict(type); + return PyDict_SetItem(dict, &_Py_ID(__module__), value); } static PyObject * @@ -790,9 +974,10 @@ type_abstractmethods(PyTypeObject *type, void *context) PyObject *mod = NULL; /* type itself has an __abstractmethods__ descriptor (this). Don't return that. */ - if (type != &PyType_Type) - mod = PyDict_GetItemWithError(type->tp_dict, - &_Py_ID(__abstractmethods__)); + if (type != &PyType_Type) { + PyObject *dict = lookup_tp_dict(type); + mod = PyDict_GetItemWithError(dict, &_Py_ID(__abstractmethods__)); + } if (!mod) { if (!PyErr_Occurred()) { PyErr_SetObject(PyExc_AttributeError, &_Py_ID(__abstractmethods__)); @@ -810,15 +995,16 @@ type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context) special to update subclasses. */ int abstract, res; + PyObject *dict = lookup_tp_dict(type); if (value != NULL) { abstract = PyObject_IsTrue(value); if (abstract < 0) return -1; - res = PyDict_SetItem(type->tp_dict, &_Py_ID(__abstractmethods__), value); + res = PyDict_SetItem(dict, &_Py_ID(__abstractmethods__), value); } else { abstract = 0; - res = PyDict_DelItem(type->tp_dict, &_Py_ID(__abstractmethods__)); + res = PyDict_DelItem(dict, &_Py_ID(__abstractmethods__)); if (res && PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_SetObject(PyExc_AttributeError, &_Py_ID(__abstractmethods__)); return -1; @@ -837,7 +1023,7 @@ type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context) static PyObject * type_get_bases(PyTypeObject *type, void *context) { - return Py_NewRef(type->tp_bases); + return Py_NewRef(lookup_tp_bases(type)); } static PyTypeObject *best_base(PyObject *); @@ -865,7 +1051,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp) /* error / reentrance */ return res; } - PyObject *new_mro = type->tp_mro; + PyObject *new_mro = lookup_tp_mro(type); PyObject *tuple; if (old_mro != NULL) { @@ -884,7 +1070,7 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp) Py_XDECREF(tuple); if (res < 0) { - type->tp_mro = old_mro; + set_tp_mro(type, old_mro); Py_DECREF(new_mro); return -1; } @@ -963,7 +1149,8 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) below), which in turn may cause an inheritance cycle through tp_base chain. And this is definitely not what you want to ever happen. */ - (base->tp_mro != NULL && type_is_subtype_base_chain(base, type))) + (lookup_tp_mro(base) != NULL + && type_is_subtype_base_chain(base, type))) { PyErr_SetString(PyExc_TypeError, "a __bases__ item causes an inheritance cycle"); @@ -980,11 +1167,11 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) return -1; } - PyObject *old_bases = type->tp_bases; + PyObject *old_bases = lookup_tp_bases(type); assert(old_bases != NULL); PyTypeObject *old_base = type->tp_base; - type->tp_bases = Py_NewRef(new_bases); + set_tp_bases(type, Py_NewRef(new_bases)); type->tp_base = (PyTypeObject *)Py_NewRef(new_base); PyObject *temp = PyList_New(0); @@ -999,7 +1186,7 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) /* Take no action in case if type->tp_bases has been replaced through reentrance. */ int res; - if (type->tp_bases == new_bases) { + if (lookup_tp_bases(type) == new_bases) { /* any base that was in __bases__ but now isn't, we need to remove |type| from its tp_subclasses. conversely, any class now in __bases__ that wasn't @@ -1030,18 +1217,18 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), "", 2, 3, &cls, &new_mro, &old_mro); /* Do not rollback if cls has a newer version of MRO. */ - if (cls->tp_mro == new_mro) { - cls->tp_mro = Py_XNewRef(old_mro); + if (lookup_tp_mro(cls) == new_mro) { + set_tp_mro(cls, Py_XNewRef(old_mro)); Py_DECREF(new_mro); } } Py_DECREF(temp); bail: - if (type->tp_bases == new_bases) { + if (lookup_tp_bases(type) == new_bases) { assert(type->tp_base == new_base); - type->tp_bases = old_bases; + set_tp_bases(type, old_bases); type->tp_base = old_base; Py_DECREF(new_bases); @@ -1059,10 +1246,11 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) static PyObject * type_dict(PyTypeObject *type, void *context) { - if (type->tp_dict == NULL) { + PyObject *dict = lookup_tp_dict(type); + if (dict == NULL) { Py_RETURN_NONE; } - return PyDictProxy_New(type->tp_dict); + return PyDictProxy_New(dict); } static PyObject * @@ -1072,7 +1260,8 @@ type_get_doc(PyTypeObject *type, void *context) if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) { return _PyType_GetDocFromInternalDoc(type->tp_name, type->tp_doc); } - result = PyDict_GetItemWithError(type->tp_dict, &_Py_ID(__doc__)); + PyObject *dict = lookup_tp_dict(type); + result = PyDict_GetItemWithError(dict, &_Py_ID(__doc__)); if (result == NULL) { if (!PyErr_Occurred()) { result = Py_NewRef(Py_None); @@ -1100,7 +1289,8 @@ type_set_doc(PyTypeObject *type, PyObject *value, void *context) if (!check_set_special_type_attr(type, value, "__doc__")) return -1; PyType_Modified(type); - return PyDict_SetItem(type->tp_dict, &_Py_ID(__doc__), value); + PyObject *dict = lookup_tp_dict(type); + return PyDict_SetItem(dict, &_Py_ID(__doc__), value); } static PyObject * @@ -1113,9 +1303,9 @@ type_get_annotations(PyTypeObject *type, void *context) PyObject *annotations; /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ - if (PyDict_Contains(type->tp_dict, &_Py_ID(__annotations__))) { - annotations = PyDict_GetItemWithError( - type->tp_dict, &_Py_ID(__annotations__)); + PyObject *dict = lookup_tp_dict(type); + if (PyDict_Contains(dict, &_Py_ID(__annotations__))) { + annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); /* ** PyDict_GetItemWithError could still fail, ** for instance with a well-timed Ctrl-C or a MemoryError. @@ -1133,7 +1323,7 @@ type_get_annotations(PyTypeObject *type, void *context) annotations = PyDict_New(); if (annotations) { int result = PyDict_SetItem( - type->tp_dict, &_Py_ID(__annotations__), annotations); + dict, &_Py_ID(__annotations__), annotations); if (result) { Py_CLEAR(annotations); } else { @@ -1155,16 +1345,17 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context) } int result; + PyObject *dict = lookup_tp_dict(type); if (value != NULL) { /* set */ - result = PyDict_SetItem(type->tp_dict, &_Py_ID(__annotations__), value); + result = PyDict_SetItem(dict, &_Py_ID(__annotations__), value); } else { /* delete */ - if (!PyDict_Contains(type->tp_dict, &_Py_ID(__annotations__))) { + if (!PyDict_Contains(dict, &_Py_ID(__annotations__))) { PyErr_Format(PyExc_AttributeError, "__annotations__"); return -1; } - result = PyDict_DelItem(type->tp_dict, &_Py_ID(__annotations__)); + result = PyDict_DelItem(dict, &_Py_ID(__annotations__)); } if (result == 0) { @@ -1751,7 +1942,7 @@ PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) { PyObject *mro; - mro = a->tp_mro; + mro = lookup_tp_mro(a); if (mro != NULL) { /* Deal with multiple inheritance without recursion by walking the MRO tuple */ @@ -2135,17 +2326,17 @@ mro_implementation(PyTypeObject *type) return NULL; } - PyObject *bases = type->tp_bases; + PyObject *bases = lookup_tp_bases(type); Py_ssize_t n = PyTuple_GET_SIZE(bases); for (Py_ssize_t i = 0; i < n; i++) { PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i)); - if (base->tp_mro == NULL) { + if (lookup_tp_mro(base) == NULL) { PyErr_Format(PyExc_TypeError, "Cannot extend an incomplete type '%.100s'", base->tp_name); return NULL; } - assert(PyTuple_Check(base->tp_mro)); + assert(PyTuple_Check(lookup_tp_mro(base))); } if (n == 1) { @@ -2153,7 +2344,8 @@ mro_implementation(PyTypeObject *type) * is trivial. */ PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, 0)); - Py_ssize_t k = PyTuple_GET_SIZE(base->tp_mro); + PyObject *base_mro = lookup_tp_mro(base); + Py_ssize_t k = PyTuple_GET_SIZE(base_mro); PyObject *result = PyTuple_New(k + 1); if (result == NULL) { return NULL; @@ -2162,7 +2354,7 @@ mro_implementation(PyTypeObject *type) ; PyTuple_SET_ITEM(result, 0, Py_NewRef(type)); for (Py_ssize_t i = 0; i < k; i++) { - PyObject *cls = PyTuple_GET_ITEM(base->tp_mro, i); + PyObject *cls = PyTuple_GET_ITEM(base_mro, i); PyTuple_SET_ITEM(result, i + 1, Py_NewRef(cls)); } return result; @@ -2189,7 +2381,7 @@ mro_implementation(PyTypeObject *type) for (Py_ssize_t i = 0; i < n; i++) { PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i)); - to_merge[i] = base->tp_mro; + to_merge[i] = lookup_tp_mro(base); } to_merge[n] = bases; @@ -2344,9 +2536,9 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro) /* Keep a reference to be able to do a reentrancy check below. Don't let old_mro be GC'ed and its address be reused for another object, like (suddenly!) a new tp_mro. */ - old_mro = Py_XNewRef(type->tp_mro); + old_mro = Py_XNewRef(lookup_tp_mro(type)); new_mro = mro_invoke(type); /* might cause reentrance */ - reent = (type->tp_mro != old_mro); + reent = (lookup_tp_mro(type) != old_mro); Py_XDECREF(old_mro); if (new_mro == NULL) { return -1; @@ -2357,12 +2549,12 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro) return 0; } - type->tp_mro = new_mro; + set_tp_mro(type, new_mro); - type_mro_modified(type, type->tp_mro); + type_mro_modified(type, new_mro); /* corner case: the super class might have been hidden from the custom MRO */ - type_mro_modified(type, type->tp_bases); + type_mro_modified(type, lookup_tp_bases(type)); // XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE? if (!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)) { @@ -2964,7 +3156,7 @@ type_new_alloc(type_new_ctx *ctx) type->tp_as_mapping = &et->as_mapping; type->tp_as_buffer = &et->as_buffer; - type->tp_bases = Py_NewRef(ctx->bases); + set_tp_bases(type, Py_NewRef(ctx->bases)); type->tp_base = (PyTypeObject *)Py_NewRef(ctx->base); type->tp_dealloc = subtype_dealloc; @@ -3004,7 +3196,8 @@ type_new_set_name(const type_new_ctx *ctx, PyTypeObject *type) static int type_new_set_module(PyTypeObject *type) { - int r = PyDict_Contains(type->tp_dict, &_Py_ID(__module__)); + PyObject *dict = lookup_tp_dict(type); + int r = PyDict_Contains(dict, &_Py_ID(__module__)); if (r < 0) { return -1; } @@ -3025,7 +3218,7 @@ type_new_set_module(PyTypeObject *type) return 0; } - if (PyDict_SetItem(type->tp_dict, &_Py_ID(__module__), module) < 0) { + if (PyDict_SetItem(dict, &_Py_ID(__module__), module) < 0) { return -1; } return 0; @@ -3038,8 +3231,8 @@ static int type_new_set_ht_name(PyTypeObject *type) { PyHeapTypeObject *et = (PyHeapTypeObject *)type; - PyObject *qualname = PyDict_GetItemWithError( - type->tp_dict, &_Py_ID(__qualname__)); + PyObject *dict = lookup_tp_dict(type); + PyObject *qualname = PyDict_GetItemWithError(dict, &_Py_ID(__qualname__)); if (qualname != NULL) { if (!PyUnicode_Check(qualname)) { PyErr_Format(PyExc_TypeError, @@ -3048,7 +3241,7 @@ type_new_set_ht_name(PyTypeObject *type) return -1; } et->ht_qualname = Py_NewRef(qualname); - if (PyDict_DelItem(type->tp_dict, &_Py_ID(__qualname__)) < 0) { + if (PyDict_DelItem(dict, &_Py_ID(__qualname__)) < 0) { return -1; } } @@ -3068,7 +3261,8 @@ type_new_set_ht_name(PyTypeObject *type) static int type_new_set_doc(PyTypeObject *type) { - PyObject *doc = PyDict_GetItemWithError(type->tp_dict, &_Py_ID(__doc__)); + PyObject *dict = lookup_tp_dict(type); + PyObject *doc = PyDict_GetItemWithError(dict, &_Py_ID(__doc__)); if (doc == NULL) { if (PyErr_Occurred()) { return -1; @@ -3103,7 +3297,8 @@ type_new_set_doc(PyTypeObject *type) static int type_new_staticmethod(PyTypeObject *type, PyObject *attr) { - PyObject *func = PyDict_GetItemWithError(type->tp_dict, attr); + PyObject *dict = lookup_tp_dict(type); + PyObject *func = PyDict_GetItemWithError(dict, attr); if (func == NULL) { if (PyErr_Occurred()) { return -1; @@ -3118,7 +3313,7 @@ type_new_staticmethod(PyTypeObject *type, PyObject *attr) if (static_func == NULL) { return -1; } - if (PyDict_SetItem(type->tp_dict, attr, static_func) < 0) { + if (PyDict_SetItem(dict, attr, static_func) < 0) { Py_DECREF(static_func); return -1; } @@ -3130,7 +3325,8 @@ type_new_staticmethod(PyTypeObject *type, PyObject *attr) static int type_new_classmethod(PyTypeObject *type, PyObject *attr) { - PyObject *func = PyDict_GetItemWithError(type->tp_dict, attr); + PyObject *dict = lookup_tp_dict(type); + PyObject *func = PyDict_GetItemWithError(dict, attr); if (func == NULL) { if (PyErr_Occurred()) { return -1; @@ -3146,7 +3342,7 @@ type_new_classmethod(PyTypeObject *type, PyObject *attr) return -1; } - if (PyDict_SetItem(type->tp_dict, attr, method) < 0) { + if (PyDict_SetItem(dict, attr, method) < 0) { Py_DECREF(method); return -1; } @@ -3232,8 +3428,8 @@ type_new_set_slots(const type_new_ctx *ctx, PyTypeObject *type) static int type_new_set_classcell(PyTypeObject *type) { - PyObject *cell = PyDict_GetItemWithError( - type->tp_dict, &_Py_ID(__classcell__)); + PyObject *dict = lookup_tp_dict(type); + PyObject *cell = PyDict_GetItemWithError(dict, &_Py_ID(__classcell__)); if (cell == NULL) { if (PyErr_Occurred()) { return -1; @@ -3250,7 +3446,7 @@ type_new_set_classcell(PyTypeObject *type) } (void)PyCell_Set(cell, (PyObject *) type); - if (PyDict_DelItem(type->tp_dict, &_Py_ID(__classcell__)) < 0) { + if (PyDict_DelItem(dict, &_Py_ID(__classcell__)) < 0) { return -1; } return 0; @@ -3357,7 +3553,7 @@ type_new_init(type_new_ctx *ctx) goto error; } - type->tp_dict = dict; + set_tp_dict(type, dict); PyHeapTypeObject *et = (PyHeapTypeObject*)type; et->ht_slots = ctx->slots; @@ -3856,7 +4052,7 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, /* Set slots we have prepared */ type->tp_base = (PyTypeObject *)Py_NewRef(base); - type->tp_bases = bases; + set_tp_bases(type, bases); bases = NULL; // We give our reference to bases to the type type->tp_doc = tp_doc; @@ -3936,12 +4132,13 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, goto finally; } + PyObject *dict = lookup_tp_dict(type); if (type->tp_doc) { PyObject *__doc__ = PyUnicode_FromString(_PyType_DocWithoutSignature(type->tp_name, type->tp_doc)); if (!__doc__) { goto finally; } - r = PyDict_SetItem(type->tp_dict, &_Py_ID(__doc__), __doc__); + r = PyDict_SetItem(dict, &_Py_ID(__doc__), __doc__); Py_DECREF(__doc__); if (r < 0) { goto finally; @@ -3949,18 +4146,18 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, } if (weaklistoffset) { - if (PyDict_DelItem((PyObject *)type->tp_dict, &_Py_ID(__weaklistoffset__)) < 0) { + if (PyDict_DelItem(dict, &_Py_ID(__weaklistoffset__)) < 0) { goto finally; } } if (dictoffset) { - if (PyDict_DelItem((PyObject *)type->tp_dict, &_Py_ID(__dictoffset__)) < 0) { + if (PyDict_DelItem(dict, &_Py_ID(__dictoffset__)) < 0) { goto finally; } } /* Set type.__module__ */ - r = PyDict_Contains(type->tp_dict, &_Py_ID(__module__)); + r = PyDict_Contains(dict, &_Py_ID(__module__)); if (r < 0) { goto finally; } @@ -3972,7 +4169,7 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, if (modname == NULL) { goto finally; } - r = PyDict_SetItem(type->tp_dict, &_Py_ID(__module__), modname); + r = PyDict_SetItem(dict, &_Py_ID(__module__), modname); Py_DECREF(modname); if (r != 0) { goto finally; @@ -4094,7 +4291,7 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) { assert(PyType_Check(type)); - PyObject *mro = type->tp_mro; + PyObject *mro = lookup_tp_mro(type); // The type must be ready assert(mro != NULL); assert(PyTuple_Check(mro)); @@ -4143,14 +4340,14 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error) } /* Look in tp_dict of types in MRO */ - PyObject *mro = type->tp_mro; + PyObject *mro = lookup_tp_mro(type); if (mro == NULL) { if ((type->tp_flags & Py_TPFLAGS_READYING) == 0) { if (PyType_Ready(type) < 0) { *error = -1; return NULL; } - mro = type->tp_mro; + mro = lookup_tp_mro(type); } if (mro == NULL) { *error = 1; @@ -4165,7 +4362,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error) Py_ssize_t n = PyTuple_GET_SIZE(mro); for (Py_ssize_t i = 0; i < n; i++) { PyObject *base = PyTuple_GET_ITEM(mro, i); - PyObject *dict = _PyType_CAST(base)->tp_dict; + PyObject *dict = lookup_tp_dict(_PyType_CAST(base)); assert(dict && PyDict_Check(dict)); res = _PyDict_GetItem_KnownHash(dict, name, hash); if (res != NULL) { @@ -4439,20 +4636,19 @@ _PyDictKeys_DecRef(PyDictKeysObject *keys); static void type_dealloc_common(PyTypeObject *type) { - if (type->tp_bases != NULL) { + PyObject *bases = lookup_tp_bases(type); + if (bases != NULL) { PyObject *exc = PyErr_GetRaisedException(); - remove_all_subclasses(type, type->tp_bases); + remove_all_subclasses(type, bases); PyErr_SetRaisedException(exc); } } -static void clear_subclasses(PyTypeObject *self); - static void clear_static_tp_subclasses(PyTypeObject *type) { - PyObject *subclasses = lookup_subclasses(type); + PyObject *subclasses = lookup_tp_subclasses(type); if (subclasses == NULL) { return; } @@ -4481,7 +4677,7 @@ clear_static_tp_subclasses(PyTypeObject *type) Py_ssize_t i = 0; PyObject *key, *ref; // borrowed ref while (PyDict_Next(subclasses, &i, &key, &ref)) { - PyTypeObject *subclass = subclass_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); // borrowed if (subclass == NULL) { continue; } @@ -4489,16 +4685,16 @@ clear_static_tp_subclasses(PyTypeObject *type) assert(!(subclass->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); } - clear_subclasses(type); + clear_tp_subclasses(type); } static void clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type) { if (_Py_IsMainInterpreter(interp)) { - Py_CLEAR(type->tp_dict); - Py_CLEAR(type->tp_bases); - Py_CLEAR(type->tp_mro); + clear_tp_dict(type); + clear_tp_bases(type); + clear_tp_mro(type); Py_CLEAR(type->tp_cache); } clear_static_tp_subclasses(type); @@ -4545,7 +4741,7 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_bases); Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); - clear_subclasses(type); + clear_tp_subclasses(type); /* A type's tp_doc is heap allocated, unlike the tp_doc slots * of most other objects. It's okay to cast it to char *. @@ -4565,65 +4761,6 @@ type_dealloc(PyTypeObject *type) } -static PyObject * -lookup_subclasses(PyTypeObject *self) -{ - if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - assert(state != NULL); - return state->tp_subclasses; - } - return (PyObject *)self->tp_subclasses; -} - -int -_PyType_HasSubclasses(PyTypeObject *self) -{ - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN && - _PyStaticType_GetState(interp, self) == NULL) { - return 0; - } - if (lookup_subclasses(self) == NULL) { - return 0; - } - return 1; -} - -PyObject* -_PyType_GetSubclasses(PyTypeObject *self) -{ - PyObject *list = PyList_New(0); - if (list == NULL) { - return NULL; - } - - PyObject *subclasses = lookup_subclasses(self); // borrowed ref - if (subclasses == NULL) { - return list; - } - assert(PyDict_CheckExact(subclasses)); - // The loop cannot modify tp_subclasses, there is no need - // to hold a strong reference (use a borrowed reference). - - Py_ssize_t i = 0; - PyObject *ref; // borrowed ref - while (PyDict_Next(subclasses, &i, NULL, &ref)) { - PyTypeObject *subclass = subclass_from_ref(ref); // borrowed - if (subclass == NULL) { - continue; - } - - if (PyList_Append(list, _PyObject_CAST(subclass)) < 0) { - Py_DECREF(list); - return NULL; - } - } - return list; -} - - /*[clinic input] type.__subclasses__ @@ -4837,8 +4974,9 @@ type_clear(PyTypeObject *type) */ PyType_Modified(type); - if (type->tp_dict) { - PyDict_Clear(type->tp_dict); + PyObject *dict = lookup_tp_dict(type); + if (dict) { + PyDict_Clear(dict); } Py_CLEAR(((PyHeapTypeObject *)type)->ht_module); @@ -5387,7 +5525,8 @@ _PyType_GetSlotNames(PyTypeObject *cls) assert(PyType_Check(cls)); /* Get the slot names from the cache in the class if possible. */ - slotnames = PyDict_GetItemWithError(cls->tp_dict, &_Py_ID(__slotnames__)); + PyObject *dict = lookup_tp_dict(cls); + slotnames = PyDict_GetItemWithError(dict, &_Py_ID(__slotnames__)); if (slotnames != NULL) { if (slotnames != Py_None && !PyList_Check(slotnames)) { PyErr_Format(PyExc_TypeError, @@ -5887,8 +6026,8 @@ object___reduce_ex___impl(PyObject *self, int protocol) PyObject *reduce, *res; if (objreduce == NULL) { - objreduce = PyDict_GetItemWithError( - PyBaseObject_Type.tp_dict, &_Py_ID(__reduce__)); + PyObject *dict = lookup_tp_dict(&PyBaseObject_Type); + objreduce = PyDict_GetItemWithError(dict, &_Py_ID(__reduce__)); if (objreduce == NULL && PyErr_Occurred()) { return NULL; } @@ -6154,11 +6293,12 @@ type_add_method(PyTypeObject *type, PyMethodDef *meth) } int err; + PyObject *dict = lookup_tp_dict(type); if (!(meth->ml_flags & METH_COEXIST)) { - err = PyDict_SetDefault(type->tp_dict, name, descr) == NULL; + err = PyDict_SetDefault(dict, name, descr) == NULL; } else { - err = PyDict_SetItem(type->tp_dict, name, descr) < 0; + err = PyDict_SetItem(dict, name, descr) < 0; } if (!isdescr) { Py_DECREF(name); @@ -6197,7 +6337,7 @@ type_add_members(PyTypeObject *type) return 0; } - PyObject *dict = type->tp_dict; + PyObject *dict = lookup_tp_dict(type); for (; memb->name != NULL; memb++) { PyObject *descr = PyDescr_NewMember(type, memb); if (descr == NULL) @@ -6221,7 +6361,7 @@ type_add_getset(PyTypeObject *type) return 0; } - PyObject *dict = type->tp_dict; + PyObject *dict = lookup_tp_dict(type); for (; gsp->name != NULL; gsp++) { PyObject *descr = PyDescr_NewGetSet(type, gsp); if (descr == NULL) { @@ -6300,7 +6440,7 @@ inherit_special(PyTypeObject *type, PyTypeObject *base) static int overrides_hash(PyTypeObject *type) { - PyObject *dict = type->tp_dict; + PyObject *dict = lookup_tp_dict(type); assert(dict != NULL); int r = PyDict_Contains(dict, &_Py_ID(__eq__)); @@ -6579,7 +6719,7 @@ type_ready_set_bases(PyTypeObject *type) } /* Initialize tp_bases */ - PyObject *bases = type->tp_bases; + PyObject *bases = lookup_tp_bases(type); if (bases == NULL) { PyTypeObject *base = type->tp_base; if (base == NULL) { @@ -6591,7 +6731,7 @@ type_ready_set_bases(PyTypeObject *type) if (bases == NULL) { return -1; } - type->tp_bases = bases; + set_tp_bases(type, bases); } return 0; } @@ -6600,7 +6740,7 @@ type_ready_set_bases(PyTypeObject *type) static int type_ready_set_dict(PyTypeObject *type) { - if (type->tp_dict != NULL) { + if (lookup_tp_dict(type) != NULL) { return 0; } @@ -6608,7 +6748,7 @@ type_ready_set_dict(PyTypeObject *type) if (dict == NULL) { return -1; } - type->tp_dict = dict; + set_tp_dict(type, dict); return 0; } @@ -6618,7 +6758,8 @@ type_ready_set_dict(PyTypeObject *type) static int type_dict_set_doc(PyTypeObject *type) { - int r = PyDict_Contains(type->tp_dict, &_Py_ID(__doc__)); + PyObject *dict = lookup_tp_dict(type); + int r = PyDict_Contains(dict, &_Py_ID(__doc__)); if (r < 0) { return -1; } @@ -6634,14 +6775,14 @@ type_dict_set_doc(PyTypeObject *type) return -1; } - if (PyDict_SetItem(type->tp_dict, &_Py_ID(__doc__), doc) < 0) { + if (PyDict_SetItem(dict, &_Py_ID(__doc__), doc) < 0) { Py_DECREF(doc); return -1; } Py_DECREF(doc); } else { - if (PyDict_SetItem(type->tp_dict, &_Py_ID(__doc__), Py_None) < 0) { + if (PyDict_SetItem(dict, &_Py_ID(__doc__), Py_None) < 0) { return -1; } } @@ -6706,14 +6847,14 @@ type_ready_mro(PyTypeObject *type) if (mro_internal(type, NULL) < 0) { return -1; } - assert(type->tp_mro != NULL); - assert(PyTuple_Check(type->tp_mro)); + PyObject *mro = lookup_tp_mro(type); + assert(mro != NULL); + assert(PyTuple_Check(mro)); /* All bases of statically allocated type should be statically allocated, and static builtin types must have static builtin bases. */ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { assert(type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE); - PyObject *mro = type->tp_mro; Py_ssize_t n = PyTuple_GET_SIZE(mro); for (Py_ssize_t i = 0; i < n; i++) { PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i)); @@ -6774,8 +6915,8 @@ type_ready_inherit(PyTypeObject *type) } // Inherit slots - PyObject *mro = type->tp_mro; - Py_ssize_t n = PyTuple_GET_SIZE(type->tp_mro); + PyObject *mro = lookup_tp_mro(type); + Py_ssize_t n = PyTuple_GET_SIZE(mro); for (Py_ssize_t i = 1; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(mro, i); if (PyType_Check(b)) { @@ -6820,7 +6961,8 @@ type_ready_set_hash(PyTypeObject *type) return 0; } - int r = PyDict_Contains(type->tp_dict, &_Py_ID(__hash__)); + PyObject *dict = lookup_tp_dict(type); + int r = PyDict_Contains(dict, &_Py_ID(__hash__)); if (r < 0) { return -1; } @@ -6828,7 +6970,7 @@ type_ready_set_hash(PyTypeObject *type) return 0; } - if (PyDict_SetItem(type->tp_dict, &_Py_ID(__hash__), Py_None) < 0) { + if (PyDict_SetItem(dict, &_Py_ID(__hash__), Py_None) < 0) { return -1; } type->tp_hash = PyObject_HashNotImplemented; @@ -6840,7 +6982,7 @@ type_ready_set_hash(PyTypeObject *type) static int type_ready_add_subclasses(PyTypeObject *type) { - PyObject *bases = type->tp_bases; + PyObject *bases = lookup_tp_bases(type); Py_ssize_t nbase = PyTuple_GET_SIZE(bases); for (Py_ssize_t i = 0; i < nbase; i++) { PyObject *b = PyTuple_GET_ITEM(bases, i); @@ -7080,38 +7222,6 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) } -static PyObject * -init_subclasses(PyTypeObject *self) -{ - PyObject *subclasses = PyDict_New(); - if (subclasses == NULL) { - return NULL; - } - if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - state->tp_subclasses = subclasses; - return subclasses; - } - self->tp_subclasses = (void *)subclasses; - return subclasses; -} - -static void -clear_subclasses(PyTypeObject *self) -{ - /* Delete the dictionary to save memory. _PyStaticType_Dealloc() - callers also test if tp_subclasses is NULL to check if a static type - has no subclass. */ - if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - static_builtin_state *state = _PyStaticType_GetState(interp, self); - Py_CLEAR(state->tp_subclasses); - return; - } - Py_CLEAR(self->tp_subclasses); -} - static int add_subclass(PyTypeObject *base, PyTypeObject *type) { @@ -7128,9 +7238,9 @@ add_subclass(PyTypeObject *base, PyTypeObject *type) // Only get tp_subclasses after creating the key and value. // PyWeakref_NewRef() can trigger a garbage collection which can execute // arbitrary Python code and so modify base->tp_subclasses. - PyObject *subclasses = lookup_subclasses(base); + PyObject *subclasses = lookup_tp_subclasses(base); if (subclasses == NULL) { - subclasses = init_subclasses(base); + subclasses = init_tp_subclasses(base); if (subclasses == NULL) { Py_DECREF(key); Py_DECREF(ref); @@ -7161,19 +7271,6 @@ add_all_subclasses(PyTypeObject *type, PyObject *bases) return res; } -static inline PyTypeObject * -subclass_from_ref(PyObject *ref) -{ - assert(PyWeakref_CheckRef(ref)); - PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref - assert(obj != NULL); - if (obj == Py_None) { - return NULL; - } - assert(PyType_Check(obj)); - return _PyType_CAST(obj); -} - static PyObject * get_subclasses_key(PyTypeObject *type, PyTypeObject *base) { @@ -7187,10 +7284,10 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base) We fall back to manually traversing the values. */ Py_ssize_t i = 0; PyObject *ref; // borrowed ref - PyObject *subclasses = lookup_subclasses(base); + PyObject *subclasses = lookup_tp_subclasses(base); if (subclasses != NULL) { while (PyDict_Next(subclasses, &i, &key, &ref)) { - PyTypeObject *subclass = subclass_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); // borrowed if (subclass == type) { return Py_NewRef(key); } @@ -7203,7 +7300,7 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base) static void remove_subclass(PyTypeObject *base, PyTypeObject *type) { - PyObject *subclasses = lookup_subclasses(base); // borrowed ref + PyObject *subclasses = lookup_tp_subclasses(base); // borrowed ref if (subclasses == NULL) { return; } @@ -7219,7 +7316,7 @@ remove_subclass(PyTypeObject *base, PyTypeObject *type) Py_XDECREF(key); if (PyDict_Size(subclasses) == 0) { - clear_subclasses(base); + clear_tp_subclasses(base); } } @@ -7517,7 +7614,7 @@ static int hackcheck(PyObject *self, setattrofunc func, const char *what) { PyTypeObject *type = Py_TYPE(self); - PyObject *mro = type->tp_mro; + PyObject *mro = lookup_tp_mro(type); if (!mro) { /* Probably ok not to check the call in this case. */ return 1; @@ -7805,7 +7902,8 @@ static struct PyMethodDef tp_new_methoddef[] = { static int add_tp_new_wrapper(PyTypeObject *type) { - int r = PyDict_Contains(type->tp_dict, &_Py_ID(__new__)); + PyObject *dict = lookup_tp_dict(type); + int r = PyDict_Contains(dict, &_Py_ID(__new__)); if (r > 0) { return 0; } @@ -7817,7 +7915,7 @@ add_tp_new_wrapper(PyTypeObject *type) if (func == NULL) { return -1; } - r = PyDict_SetItem(type->tp_dict, &_Py_ID(__new__), func); + r = PyDict_SetItem(dict, &_Py_ID(__new__), func); Py_DECREF(func); return r; } @@ -9181,7 +9279,8 @@ update_all_slots(PyTypeObject* type) static int type_new_set_names(PyTypeObject *type) { - PyObject *names_to_set = PyDict_Copy(type->tp_dict); + PyObject *dict = lookup_tp_dict(type); + PyObject *names_to_set = PyDict_Copy(dict); if (names_to_set == NULL) { return -1; } @@ -9270,7 +9369,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name, // It is safe to use a borrowed reference because update_subclasses() is // only used with update_slots_callback() which doesn't modify // tp_subclasses. - PyObject *subclasses = lookup_subclasses(type); // borrowed ref + PyObject *subclasses = lookup_tp_subclasses(type); // borrowed ref if (subclasses == NULL) { return 0; } @@ -9279,13 +9378,13 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name, Py_ssize_t i = 0; PyObject *ref; while (PyDict_Next(subclasses, &i, NULL, &ref)) { - PyTypeObject *subclass = subclass_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); // borrowed if (subclass == NULL) { continue; } /* Avoid recursing down into unaffected classes */ - PyObject *dict = subclass->tp_dict; + PyObject *dict = lookup_tp_dict(subclass); if (dict != NULL && PyDict_Check(dict)) { int r = PyDict_Contains(dict, attr_name); if (r < 0) { @@ -9336,7 +9435,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name, static int add_operators(PyTypeObject *type) { - PyObject *dict = type->tp_dict; + PyObject *dict = lookup_tp_dict(type); pytype_slotdef *p; PyObject *descr; void **ptr; @@ -9432,7 +9531,7 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject * PyObject *mro, *res; Py_ssize_t i, n; - mro = su_obj_type->tp_mro; + mro = lookup_tp_mro(su_obj_type); if (mro == NULL) return NULL; @@ -9453,7 +9552,7 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject * Py_INCREF(mro); do { PyObject *obj = PyTuple_GET_ITEM(mro, i); - PyObject *dict = _PyType_CAST(obj)->tp_dict; + PyObject *dict = lookup_tp_dict(_PyType_CAST(obj)); assert(dict != NULL && PyDict_Check(dict)); res = PyDict_GetItemWithError(dict, name); diff --git a/Python/context.c b/Python/context.c index 5d385508405e..1ffae9871be7 100644 --- a/Python/context.c +++ b/Python/context.c @@ -1309,7 +1309,7 @@ _PyContext_Init(PyInterpreterState *interp) PyObject *missing = get_token_missing(); if (PyDict_SetItemString( - PyContextToken_Type.tp_dict, "MISSING", missing)) + _PyType_GetDict(&PyContextToken_Type), "MISSING", missing)) { Py_DECREF(missing); return _PyStatus_ERR("can't init context types"); From webhook-mailer at python.org Mon May 1 22:53:24 2023 From: webhook-mailer at python.org (terryjreedy) Date: Tue, 02 May 2023 02:53:24 -0000 Subject: [Python-checkins] gh-88496: IDLE - fix another test on macOS (#104075) Message-ID: https://github.com/python/cpython/commit/690df4c16ca4f0054d27a6148da9e6af809a2658 commit: 690df4c16ca4f0054d27a6148da9e6af809a2658 branch: main author: Terry Jan Reedy committer: terryjreedy date: 2023-05-02T02:53:16Z summary: gh-88496: IDLE - fix another test on macOS (#104075) Needed for Catalina: test_sidebar add 'idletasks' and skip assert. files: M Lib/idlelib/idle_test/test_sidebar.py diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py index 5506fd2b0e22..fb52b3a01795 100644 --- a/Lib/idlelib/idle_test/test_sidebar.py +++ b/Lib/idlelib/idle_test/test_sidebar.py @@ -57,7 +57,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.editwin.per.close() - cls.root.update() + cls.root.update_idletasks() cls.root.destroy() del cls.text, cls.text_frame, cls.editwin, cls.root @@ -695,7 +695,8 @@ def test_mousewheel(self): delta = -1 if sys.platform == 'darwin' else 120 sidebar.canvas.event_generate('', x=0, y=0, delta=delta) yield - self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0'))) + if sys.platform != 'darwin': # .update_idletasks() does not work. + self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0'))) # Scroll back down using the event. sidebar.canvas.event_generate('', x=0, y=0) From webhook-mailer at python.org Mon May 1 23:23:04 2023 From: webhook-mailer at python.org (terryjreedy) Date: Tue, 02 May 2023 03:23:04 -0000 Subject: [Python-checkins] [3.11] gh-88496: IDLE - fix another test on macOS (GH-104075) (#104076) Message-ID: https://github.com/python/cpython/commit/9f191a1a7760187f6ce116b6a87c4765637ebe57 commit: 9f191a1a7760187f6ce116b6a87c4765637ebe57 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy date: 2023-05-02T03:22:57Z summary: [3.11] gh-88496: IDLE - fix another test on macOS (GH-104075) (#104076) gh-88496: IDLE - fix another test on macOS (GH-104075) Needed for Catalina: test_sidebar add 'idletasks' and skip assert. (cherry picked from commit 690df4c16ca4f0054d27a6148da9e6af809a2658) Co-authored-by: Terry Jan Reedy files: M Lib/idlelib/idle_test/test_sidebar.py diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py index 5506fd2b0e22..fb52b3a01795 100644 --- a/Lib/idlelib/idle_test/test_sidebar.py +++ b/Lib/idlelib/idle_test/test_sidebar.py @@ -57,7 +57,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): cls.editwin.per.close() - cls.root.update() + cls.root.update_idletasks() cls.root.destroy() del cls.text, cls.text_frame, cls.editwin, cls.root @@ -695,7 +695,8 @@ def test_mousewheel(self): delta = -1 if sys.platform == 'darwin' else 120 sidebar.canvas.event_generate('', x=0, y=0, delta=delta) yield - self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0'))) + if sys.platform != 'darwin': # .update_idletasks() does not work. + self.assertIsNone(text.dlineinfo(text.index(f'{last_lineno}.0'))) # Scroll back down using the event. sidebar.canvas.event_generate('', x=0, y=0) From webhook-mailer at python.org Tue May 2 00:00:06 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 02 May 2023 04:00:06 -0000 Subject: [Python-checkins] GH-103472: close response in HTTPConnection._tunnel (#103473) Message-ID: https://github.com/python/cpython/commit/9de0cf20fa0485e327e57cc0864c7476da85cfad commit: 9de0cf20fa0485e327e57cc0864c7476da85cfad branch: main author: Thomas Grainger committer: gpshead date: 2023-05-02T03:59:42Z summary: GH-103472: close response in HTTPConnection._tunnel (#103473) Avoid a potential `ResourceWarning` in `http.client.HTTPConnection` by closing the proxy / tunnel's CONNECT response explicitly. --------- Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst M Lib/http/client.py M Lib/test/test_httplib.py diff --git a/Lib/http/client.py b/Lib/http/client.py index 0f5cd35247ae..74f7bcb68fb6 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -941,23 +941,26 @@ def _tunnel(self): del headers response = self.response_class(self.sock, method=self._method) - (version, code, message) = response._read_status() + try: + (version, code, message) = response._read_status() - if code != http.HTTPStatus.OK: - self.close() - raise OSError(f"Tunnel connection failed: {code} {message.strip()}") - while True: - line = response.fp.readline(_MAXLINE + 1) - if len(line) > _MAXLINE: - raise LineTooLong("header line") - if not line: - # for sites which EOF without sending a trailer - break - if line in (b'\r\n', b'\n', b''): - break + if code != http.HTTPStatus.OK: + self.close() + raise OSError(f"Tunnel connection failed: {code} {message.strip()}") + while True: + line = response.fp.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise LineTooLong("header line") + if not line: + # for sites which EOF without sending a trailer + break + if line in (b'\r\n', b'\n', b''): + break - if self.debuglevel > 0: - print('header:', line.decode()) + if self.debuglevel > 0: + print('header:', line.decode()) + finally: + response.close() def connect(self): """Connect to the host and port specified in __init__.""" diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index b4f4e2b14351..37f77fe0a320 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2390,6 +2390,29 @@ def test_tunnel_debuglog(self): lines = output.getvalue().splitlines() self.assertIn('header: {}'.format(expected_header), lines) + def test_tunnel_leak(self): + sock = None + + def _create_connection(address, timeout=None, source_address=None): + nonlocal sock + sock = FakeSocket( + 'HTTP/1.1 404 NOT FOUND\r\n\r\n', + host=address[0], + port=address[1], + ) + return sock + + self.conn._create_connection = _create_connection + self.conn.set_tunnel('destination.com') + exc = None + try: + self.conn.request('HEAD', '/', '') + except OSError as e: + # keeping a reference to exc keeps response alive in the traceback + exc = e + self.assertIsNotNone(exc) + self.assertTrue(sock.file_closed) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst new file mode 100644 index 000000000000..01d84f024bd4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst @@ -0,0 +1,2 @@ +Avoid a potential :exc:`ResourceWarning` in :class:`http.client.HTTPConnection` +by closing the proxy / tunnel's CONNECT response explicitly. From webhook-mailer at python.org Tue May 2 00:30:50 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 02 May 2023 04:30:50 -0000 Subject: [Python-checkins] gh-102997: Update macOS installer to SQLite 3.41.2. (GH-102998) Message-ID: https://github.com/python/cpython/commit/f0ad4567319ee4ae878d570ab7709ab63df9123e commit: f0ad4567319ee4ae878d570ab7709ab63df9123e branch: main author: Mariusz Felisiak committer: ned-deily date: 2023-05-02T00:30:43-04:00 summary: gh-102997: Update macOS installer to SQLite 3.41.2. (GH-102998) files: A Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 63fa21b2b33d..2f5937489ac0 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.40.1", - url="https://sqlite.org/2022/sqlite-autoconf-3400100.tar.gz", - checksum="42175b1a1d23529cb133bbd2b5900afd", + name="SQLite 3.41.2", + url="https://sqlite.org/2023/sqlite-autoconf-3410200.tar.gz", + checksum="862075fd1c38324878ef809eda39edfe", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst b/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst new file mode 100644 index 000000000000..d0b390a896b7 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.41.2. From webhook-mailer at python.org Tue May 2 01:01:28 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 02 May 2023 05:01:28 -0000 Subject: [Python-checkins] [3.11] gh-102997: Update macOS installer to SQLite 3.41.2. (GH-104080) Message-ID: https://github.com/python/cpython/commit/6805e495699988d201904930fa87f3aaa27d05b4 commit: 6805e495699988d201904930fa87f3aaa27d05b4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2023-05-02T05:01:20Z summary: [3.11] gh-102997: Update macOS installer to SQLite 3.41.2. (GH-104080) (cherry picked from commit f0ad4567319ee4ae878d570ab7709ab63df9123e) Co-authored-by: Mariusz Felisiak files: A Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 334e10e7060f..8748b205ed7d 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -358,9 +358,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.40.1", - url="https://sqlite.org/2022/sqlite-autoconf-3400100.tar.gz", - checksum="42175b1a1d23529cb133bbd2b5900afd", + name="SQLite 3.41.2", + url="https://sqlite.org/2023/sqlite-autoconf-3410200.tar.gz", + checksum="862075fd1c38324878ef809eda39edfe", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst b/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst new file mode 100644 index 000000000000..d0b390a896b7 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.41.2. From webhook-mailer at python.org Tue May 2 01:29:51 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 02 May 2023 05:29:51 -0000 Subject: [Python-checkins] [3.11] Replace Netlify with Read the Docs build previews (#103843) (#104083) Message-ID: https://github.com/python/cpython/commit/b07bae6971c3772c3d376813cdbbe4e719d4d322 commit: b07bae6971c3772c3d376813cdbbe4e719d4d322 branch: 3.11 author: Hugo van Kemenade committer: hugovk date: 2023-05-02T05:29:27Z summary: [3.11] Replace Netlify with Read the Docs build previews (#103843) (#104083) Co-authored-by: Oleg Iarygin Co-authored-by: C.A.M. Gerlach files: A .github/workflows/documentation-links.yml A .readthedocs.yml M Doc/conf.py M Doc/tools/templates/layout.html diff --git a/.github/workflows/documentation-links.yml b/.github/workflows/documentation-links.yml new file mode 100644 index 000000000000..43a7afec7388 --- /dev/null +++ b/.github/workflows/documentation-links.yml @@ -0,0 +1,27 @@ +name: Read the Docs PR preview +# Automatically edits a pull request's descriptions with a link +# to the documentation's preview on Read the Docs. + +on: + pull_request_target: + types: + - opened + paths: + - 'Doc/**' + - '.github/workflows/doc.yml' + +permissions: + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + documentation-links: + runs-on: ubuntu-latest + steps: + - uses: readthedocs/actions/preview at v1 + with: + project-slug: "cpython-previews" + single-version: "true" diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 000000000000..898a9ae89dbb --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,18 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details +# Project page: https://readthedocs.org/projects/cpython-previews/ + +version: 2 + +sphinx: + configuration: Doc/conf.py + +build: + os: ubuntu-22.04 + tools: + python: "3" + + commands: + - make -C Doc venv html + - mkdir _readthedocs + - mv Doc/build/html _readthedocs/html diff --git a/Doc/conf.py b/Doc/conf.py index 216f12dd7ef2..138a18409983 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -109,6 +109,15 @@ # Short title used e.g. for HTML tags. html_short_title = '%s Documentation' % release +# Deployment preview information +# (See .readthedocs.yml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html) +repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL") +html_context = { + "is_deployment_preview": os.getenv("READTHEDOCS_VERSION_TYPE") == "external", + "repository_url": repository_url.removesuffix(".git") if repository_url else None, + "pr_id": os.getenv("READTHEDOCS_VERSION") +} + # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index 98ccf4224804..b91f8138553e 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -8,6 +8,14 @@ <a href="/3/{{ pagename }}{{ file_suffix }}">{% trans %} Python documentation for the current stable release{% endtrans %}</a>. </div> {%- endif %} + +{%- if is_deployment_preview %} +<div id="deployment-preview-warning" style="padding: .5em; text-align: center; background-color: #fff2ba; color: #6a580e;"> + {% trans %}This is a deploy preview created from a <a href="{{ repository_url }}/pull/{{ pr_id }}">pull request</a>. + For authoritative documentation, see the {% endtrans %} + <a href="https://docs.python.org/3/{{ pagename }}{{ file_suffix }}">{% trans %} the current stable release{% endtrans %}</a>. +</div> +{%- endif %} {% endblock %} {% block rootrellink %} From webhook-mailer at python.org Tue May 2 02:05:53 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 02 May 2023 06:05:53 -0000 Subject: [Python-checkins] Improve assert_type phrasing (#104081) Message-ID: <mailman.98.1683007553.13550.python-checkins@python.org> https://github.com/python/cpython/commit/82ba6ce303d04a7b21034e38d220e23ca9f1dc0a commit: 82ba6ce303d04a7b21034e38d220e23ca9f1dc0a branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-01T23:05:25-07:00 summary: Improve assert_type phrasing (#104081) I'd like to make the fact that this does nothing at runtime really obvious, since I suspect this is unintuitive for users who are unfamiliar with static type checking. I thought of this because of https://discuss.python.org/t/add-arg-check-type-to-types/26384 wherein I'm skeptical that the user really did want `assert_type`. files: M Doc/library/typing.rst M Lib/typing.py diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 409a95d528b5..c22fc0b28a50 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2484,15 +2484,16 @@ Functions and decorators Ask a static type checker to confirm that *val* has an inferred type of *typ*. - When the type checker encounters a call to ``assert_type()``, it + At runtime this does nothing: it returns the first argument unchanged with no + checks or side effects, no matter the actual type of the argument. + + When a static type checker encounters a call to ``assert_type()``, it emits an error if the value is not of the specified type:: def greet(name: str) -> None: assert_type(name, str) # OK, inferred type of `name` is `str` assert_type(name, int) # type checker error - At runtime this returns the first argument unchanged with no side effects. - This function is useful for ensuring the type checker's understanding of a script is in line with the developer's intentions:: diff --git a/Lib/typing.py b/Lib/typing.py index 1a1c989dbaf3..0dacdd9031a7 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2319,15 +2319,16 @@ def cast(typ, val): def assert_type(val, typ, /): """Ask a static type checker to confirm that the value is of the given type. - When the type checker encounters a call to assert_type(), it + At runtime this does nothing: it returns the first argument unchanged with no + checks or side effects, no matter the actual type of the argument. + + When a static type checker encounters a call to assert_type(), it emits an error if the value is not of the specified type:: def greet(name: str) -> None: assert_type(name, str) # ok assert_type(name, int) # type checker error - At runtime this returns the first argument unchanged and otherwise - does nothing. """ return val From webhook-mailer at python.org Tue May 2 02:35:05 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 02 May 2023 06:35:05 -0000 Subject: [Python-checkins] GH-103484: Fix redirected permanently URLs (#104001) Message-ID: <mailman.99.1683009306.13550.python-checkins@python.org> https://github.com/python/cpython/commit/68ed2a2a3f1e715dc10724b0c000ec2fc498d11e commit: 68ed2a2a3f1e715dc10724b0c000ec2fc498d11e branch: main author: Rafael Fontenelle <rffontenelle at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-02T09:34:44+03:00 summary: GH-103484: Fix redirected permanently URLs (#104001) Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> Co-authored-by: Oleg Iarygin <dralife at yandex.ru> files: M Doc/conf.py M Doc/faq/extending.rst M Doc/faq/general.rst M Doc/faq/programming.rst M Doc/howto/pyporting.rst M Doc/library/asyncio-eventloop.rst M Doc/library/hashlib.rst M Doc/library/http.client.rst M Doc/library/importlib.metadata.rst M Doc/library/os.rst M Doc/library/plistlib.rst M Doc/library/resource.rst M Doc/library/select.rst M Doc/library/ssl.rst M Doc/library/statistics.rst M Doc/library/struct.rst M Doc/library/sys.rst M Doc/library/unittest.mock-examples.rst M Doc/library/unittest.rst M Doc/library/xmlrpc.client.rst M Doc/library/zipfile.rst M Doc/reference/datamodel.rst M Doc/reference/introduction.rst M Doc/using/cmdline.rst M Doc/using/mac.rst M Doc/using/windows.rst M Doc/whatsnew/2.0.rst M Doc/whatsnew/2.1.rst M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.3.rst M Doc/whatsnew/2.4.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.2.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.5.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.8.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/3.7.0a1.rst diff --git a/Doc/conf.py b/Doc/conf.py index cef2a0e2837f..6a3c01cd91a7 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -264,11 +264,29 @@ 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+', + r'https://bugs.python.org/issue\?@action=redirect&bpo=\d+': r'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+', + r'https://github.com/python/cpython/issues/\d+': r'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/.*' + r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*', + # Intentional HTTP use at Misc/NEWS.d/3.5.0a1.rst + r'http://www.python.org/$': 'https://www.python.org/$', + # Used in license page, keep as is + r'https://www.zope.org/': r'https://www.zope.dev/', + # Microsoft's redirects to learn.microsoft.com + r'https://msdn.microsoft.com/.*': 'https://learn.microsoft.com/.*', + r'https://docs.microsoft.com/.*': 'https://learn.microsoft.com/.*', + r'https://go.microsoft.com/fwlink/\?LinkID=\d+': 'https://learn.microsoft.com/.*', + # Language redirects + r'https://toml.io': 'https://toml.io/en/', + r'https://www.redhat.com': 'https://www.redhat.com/en', + # Other redirects + r'https://www.boost.org/libs/.+': r'https://www.boost.org/doc/libs/\d_\d+_\d/.+', + r'https://support.microsoft.com/en-us/help/\d+': 'https://support.microsoft.com/en-us/topic/.+', + r'https://perf.wiki.kernel.org$': 'https://perf.wiki.kernel.org/index.php/Main_Page', + r'https://www.sqlite.org': 'https://www.sqlite.org/index.html', + r'https://mitpress.mit.edu/sicp$': 'https://mitpress.mit.edu/9780262510875/structure-and-interpretation-of-computer-programs/', + r'https://www.python.org/psf/': 'https://www.python.org/psf-landing/', } linkcheck_anchors_ignore = [ diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst index 07282639e4f9..bc3080f60ee2 100644 --- a/Doc/faq/extending.rst +++ b/Doc/faq/extending.rst @@ -42,7 +42,7 @@ on what you're trying to do. .. XXX make sure these all work `Cython <https://cython.org>`_ and its relative `Pyrex -<https://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/>`_ are compilers +<https://www.csse.canterbury.ac.nz/greg.ewing/python/Pyrex/>`_ are compilers that accept a slightly modified form of Python and generate the corresponding C code. Cython and Pyrex make it possible to write an extension without having to learn Python's C API. diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 6256deb5797c..a9b2622e02ef 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -54,8 +54,8 @@ commercial use, to sell copies of Python in source or binary form (modified or unmodified), or to sell products that incorporate Python in some form. We would still like to know about all commercial use of Python, of course. -See `the PSF license page <https://www.python.org/psf/license/>`_ to find further -explanations and a link to the full text of the license. +See `the license page <https://docs.python.org/3/license.html>`_ to find further +explanations and the full text of the PSF License. The Python logo is trademarked, and in certain cases permission is required to use it. Consult `the Trademark Usage Policy @@ -215,7 +215,7 @@ every day, and Usenet readers are often more able to cope with this volume. Announcements of new software releases and events can be found in comp.lang.python.announce, a low-traffic moderated list that receives about five postings per day. It's available as `the python-announce mailing list -<https://mail.python.org/mailman/listinfo/python-announce-list>`_. +<https://mail.python.org/mailman3/lists/python-announce-list.python.org/>`_. More info about other mailing lists and newsgroups can be found at https://www.python.org/community/lists/. @@ -352,7 +352,7 @@ titled "Python X.Y Release Schedule", where X.Y is a version that hasn't been publicly released yet. New development is discussed on `the python-dev mailing list -<https://mail.python.org/mailman/listinfo/python-dev/>`_. +<https://mail.python.org/mailman3/lists/python-dev.python.org/>`_. Is it reasonable to propose incompatible changes to Python? diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index 38f9b171618b..ab5618db84f7 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -61,7 +61,7 @@ Yes. `Pyflakes <https://github.com/PyCQA/pyflakes>`_ do basic checking that will help you catch bugs sooner. -Static type checkers such as `Mypy <http://mypy-lang.org/>`_, +Static type checkers such as `Mypy <https://mypy-lang.org/>`_, `Pyre <https://pyre-check.org/>`_, and `Pytype <https://github.com/google/pytype>`_ can check type hints in Python source code. diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst index add1c11be534..baea3e85c3b8 100644 --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -438,7 +438,7 @@ to make sure everything functions as expected in both versions of Python. .. _Futurize: https://python-future.org/automatic_conversion.html .. _importlib2: https://pypi.org/project/importlib2 .. _Modernize: https://python-modernize.readthedocs.io/ -.. _mypy: http://mypy-lang.org/ +.. _mypy: https://mypy-lang.org/ .. _Porting to Python 3: http://python3porting.com/ .. _Pylint: https://pypi.org/project/pylint diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index e982cc166a3f..8d0022cc66da 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -529,7 +529,7 @@ Opening network connections specifies requirements for algorithms that reduce this user-visible delay and provides an algorithm. - For more information: https://tools.ietf.org/html/rfc6555 + For more information: https://datatracker.ietf.org/doc/html/rfc6555 .. versionchanged:: 3.11 diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index f8d10c0c295c..6275f96f7d4d 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -432,7 +432,7 @@ Constructor functions also accept the following tree hashing parameters: :alt: Explanation of tree mode parameters. See section 2.10 in `BLAKE2 specification -<https://blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree +<https://www.blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree hashing. @@ -619,7 +619,7 @@ on the hash function used in digital signatures. by the signer. (`NIST SP-800-106 "Randomized Hashing for Digital Signatures" - <https://csrc.nist.gov/publications/detail/sp/800-106/final>`_) + <https://csrc.nist.gov/publications/detail/sp/800-106/archive/2009-02-25>`_) In BLAKE2 the salt is processed as a one-time input to the hash function during initialization, rather than as an input to each compression function. @@ -628,7 +628,7 @@ initialization, rather than as an input to each compression function. *Salted hashing* (or just hashing) with BLAKE2 or any other general-purpose cryptographic hash function, such as SHA-256, is not suitable for hashing - passwords. See `BLAKE2 FAQ <https://blake2.net/#qa>`_ for more + passwords. See `BLAKE2 FAQ <https://www.blake2.net/#qa>`_ for more information. .. @@ -764,9 +764,9 @@ Domain Dedication 1.0 Universal: * *Alexandr Sokolovskiy* -.. _BLAKE2: https://blake2.net +.. _BLAKE2: https://www.blake2.net .. _HMAC: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code -.. _BLAKE: https://131002.net/blake/ +.. _BLAKE: https://web.archive.org/web/20200918190133/https://131002.net/blake/ .. _SHA-3: https://en.wikipedia.org/wiki/NIST_hash_function_competition .. _ChaCha: https://cr.yp.to/chacha.html .. _pyblake2: https://pythonhosted.org/pyblake2/ @@ -782,7 +782,7 @@ Domain Dedication 1.0 Universal: Module :mod:`base64` Another way to encode binary hashes for non-binary environments. - https://blake2.net + https://www.blake2.net Official BLAKE2 website. https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 38821b32c91c..abdc6b447a8b 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -354,7 +354,7 @@ HTTPConnection Objects 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:`` + <https://datatracker.ietf.org/doc/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 diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index b306d5f55a71..3097bcf47b62 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -178,7 +178,7 @@ The "selectable" entry points were introduced in ``importlib_metadata`` no parameters and always returned a dictionary of entry points, keyed by group. With ``importlib_metadata`` 5.0 and Python 3.12, ``entry_points`` always returns an ``EntryPoints`` object. See -`backports.entry_points_selectable <https://pypi.org/project/backports.entry_points_selectable>`_ +`backports.entry_points_selectable <https://pypi.org/project/backports.entry-points-selectable>`_ for compatibility options. diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 50e951c631fa..76623c630543 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -4593,7 +4593,7 @@ written in Python, such as a mail server's external command delivery program. :attr:`!children_system`, and :attr:`!elapsed` in that order. See the Unix manual page - :manpage:`times(2)` and `times(3) <https://www.freebsd.org/cgi/man.cgi?time(3)>`_ manual page on Unix or `the GetProcessTimes MSDN + :manpage:`times(2)` and `times(3) <https://man.freebsd.org/cgi/man.cgi?time(3)>`_ manual page on Unix or `the GetProcessTimes MSDN <https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes>`_ on Windows. On Windows, only :attr:`!user` and :attr:`!system` are known; the other attributes are zero. diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index 7aad15ec91a0..732ef3536863 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -46,7 +46,7 @@ or :class:`datetime.datetime` objects. .. seealso:: - `PList manual page <https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/>`_ + `PList manual page <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/PropertyLists/>`_ Apple's documentation of the file format. diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst index e7bf45d7d569..a5324c82c634 100644 --- a/Doc/library/resource.rst +++ b/Doc/library/resource.rst @@ -244,7 +244,7 @@ platform. used by all of this user id's processes. This limit is enforced only if bit 1 of the vm.overcommit sysctl is set. Please see - `tuning(7) <https://www.freebsd.org/cgi/man.cgi?query=tuning&sektion=7>`__ + `tuning(7) <https://man.freebsd.org/cgi/man.cgi?query=tuning&sektion=7>`__ for a complete description of this sysctl. .. availability:: FreeBSD. diff --git a/Doc/library/select.rst b/Doc/library/select.rst index 2890706bab72..b0891b0c8f58 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -505,7 +505,7 @@ Kqueue Objects Kevent Objects -------------- -https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 +https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 .. attribute:: kevent.ident diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 4b60b7c643b6..18a6c5ab4858 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1719,7 +1719,7 @@ to speed up repeated connections from the same clients. .. versionadded:: 3.3 .. seealso:: - `SSL/TLS & Perfect Forward Secrecy <https://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy>`_ + `SSL/TLS & Perfect Forward Secrecy <https://vincent.bernat.ch/en/blog/2011-ssl-perfect-forward-secrecy>`_ Vincent Bernat. .. method:: SSLContext.wrap_socket(sock, server_side=False, \ diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index f934b0e0319d..395b324c8603 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -22,7 +22,7 @@ This module provides functions for calculating mathematical statistics of numeric (:class:`~numbers.Real`-valued) data. The module is not intended to be a competitor to third-party libraries such -as `NumPy <https://numpy.org>`_, `SciPy <https://www.scipy.org/>`_, or +as `NumPy <https://numpy.org>`_, `SciPy <https://scipy.org/>`_, or proprietary full-featured statistics packages aimed at professional statisticians such as Minitab, SAS and Matlab. It is aimed at the level of graphing and scientific calculators. diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 9c0e32ba16bf..78fd6e397ae6 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -602,4 +602,4 @@ The :mod:`struct` module also defines the following type: .. _ieee 754 standard: https://en.wikipedia.org/wiki/IEEE_754-2008_revision -.. _IETF RFC 1700: https://tools.ietf.org/html/rfc1700 +.. _IETF RFC 1700: https://datatracker.ietf.org/doc/html/rfc1700 diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 7c0e85142e77..95ad243bdde3 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -792,7 +792,7 @@ always available. additional garbage collector overhead if the object is managed by the garbage collector. - See `recursive sizeof recipe <https://code.activestate.com/recipes/577504>`_ + See `recursive sizeof recipe <https://code.activestate.com/recipes/577504/>`_ for an example of using :func:`getsizeof` recursively to find the size of containers and all their contents. diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index f9a207bad690..895b9f9f0767 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -1074,7 +1074,7 @@ subclass. Sometimes this is inconvenient. For example, `one user <https://code.google.com/archive/p/mock/issues/105>`_ is subclassing mock to created a `Twisted adaptor -<https://twistedmatrix.com/documents/11.0.0/api/twisted.python.components.html>`_. +<https://twisted.org/documents/11.0.0/api/twisted.python.components.html>`_. Having this applied to attributes too actually causes errors. ``Mock`` (in all its flavours) uses a method called ``_get_child_mock`` to create diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index c70153dfcd69..b26e6c0e6bc0 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -72,7 +72,7 @@ test runner a GUI tool for test discovery and execution. This is intended largely for ease of use for those new to unit testing. For production environments it is recommended that tests be driven by a continuous integration system such as - `Buildbot <https://buildbot.net/>`_, `Jenkins <https://jenkins.io/>`_, + `Buildbot <https://buildbot.net/>`_, `Jenkins <https://www.jenkins.io/>`_, `GitHub Actions <https://github.com/features/actions>`_, or `AppVeyor <https://www.appveyor.com/>`_. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst index bd2c49a6edab..146c4fd76823 100644 --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -161,7 +161,7 @@ between conformable Python objects and XML on the wire. .. seealso:: - `XML-RPC HOWTO <https://www.tldp.org/HOWTO/XML-RPC-HOWTO/index.html>`_ + `XML-RPC HOWTO <https://tldp.org/HOWTO/XML-RPC-HOWTO/index.html>`_ A good description of XML-RPC operation and client software in several languages. Contains pretty much everything an XML-RPC client developer needs to know. diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 6f4826cb065c..45f3d340bd82 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -128,7 +128,7 @@ The module defines the following items: Documentation on the ZIP file format by Phil Katz, the creator of the format and algorithms used. - `Info-ZIP Home Page <http://www.info-zip.org/>`_ + `Info-ZIP Home Page <https://infozip.sourceforge.net/>`_ Information about the Info-ZIP project's ZIP archive programs and development libraries. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 55431f1951e5..c35bf4016a28 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1564,7 +1564,7 @@ Basic customization This is intended to provide protection against a denial-of-service caused by carefully chosen inputs that exploit the worst case performance of a dict insertion, O(n\ :sup:`2`) complexity. See - http://www.ocert.org/advisories/ocert-2011-003.html for details. + http://ocert.org/advisories/ocert-2011-003.html for details. Changing hash values affects the iteration order of sets. Python has never made guarantees about this ordering diff --git a/Doc/reference/introduction.rst b/Doc/reference/introduction.rst index 914a11556c94..81f0a5c5d438 100644 --- a/Doc/reference/introduction.rst +++ b/Doc/reference/introduction.rst @@ -74,7 +74,7 @@ PyPy and a Just in Time compiler. One of the goals of the project is to encourage experimentation with the language itself by making it easier to modify the interpreter (since it is written in Python). Additional information is - available on `the PyPy project's home page <https://pypy.org/>`_. + available on `the PyPy project's home page <https://www.pypy.org/>`_. Each of these implementations varies in some way from the language as documented in this manual, or introduces specific information beyond what's covered in the diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index b35e8454fa2a..9d4042ce5a7e 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -370,7 +370,7 @@ Miscellaneous options Hash randomization is intended to provide protection against a denial-of-service caused by carefully chosen inputs that exploit the worst case performance of a dict construction, O(n\ :sup:`2`) complexity. See - http://www.ocert.org/advisories/ocert-2011-003.html for details. + http://ocert.org/advisories/ocert-2011-003.html for details. :envvar:`PYTHONHASHSEED` allows you to set a fixed value for the hash seed secret. diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 9ae0270eaee7..69cd5c92d884 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -66,7 +66,7 @@ number of standard Unix command line editors, :program:`vim` and :program:`BBEdit` or :program:`TextWrangler` from Bare Bones Software (see http://www.barebones.com/products/bbedit/index.html) are good choices, as is :program:`TextMate` (see https://macromates.com/). Other editors include -:program:`Gvim` (https://macvim-dev.github.io/macvim/) and :program:`Aquamacs` +:program:`Gvim` (https://macvim.org/macvim/) and :program:`Aquamacs` (http://aquamacs.org/). To run your script from the Terminal window you must make sure that diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 380950eb507f..43e3c72f3e1c 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -541,7 +541,7 @@ Besides the standard CPython distribution, there are modified packages including additional functionality. The following is a list of popular versions and their key features: -`ActivePython <https://www.activestate.com/activepython/>`_ +`ActivePython <https://www.activestate.com/products/python/>`_ Installer with multi-platform compatibility, documentation, PyWin32 `Anaconda <https://www.anaconda.com/download/>`_ diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index 4bcb2acae1e6..0eefefd863a6 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -933,7 +933,7 @@ using it:: parser.parse( 'hamlet.xml' ) For more information, consult the Python documentation, or the XML HOWTO at -http://pyxml.sourceforge.net/topics/howto/xml-howto.html. +https://pyxml.sourceforge.net/topics/howto/xml-howto.html. DOM Support diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst index 0136de587740..676da702b396 100644 --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -613,7 +613,7 @@ New and Improved Modules framework based on running embedded examples in docstrings and comparing the results against the expected output. PyUnit, contributed by Steve Purcell, is a unit testing framework inspired by JUnit, which was in turn an adaptation of - Kent Beck's Smalltalk testing framework. See http://pyunit.sourceforge.net/ for + Kent Beck's Smalltalk testing framework. See https://pyunit.sourceforge.net/ for more information about PyUnit. * The :mod:`difflib` module contains a class, :class:`SequenceMatcher`, which diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 0c3bfda19339..82aff0be1ed3 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -632,10 +632,10 @@ queen threatens another) and the Knight's Tour (a route that takes a knight to every square of an $NxN$ chessboard without visiting any square twice). The idea of generators comes from other programming languages, especially Icon -(https://www.cs.arizona.edu/icon/), where the idea of generators is central. In +(https://www2.cs.arizona.edu/icon/), where the idea of generators is central. In Icon, every expression and function call behaves like a generator. One example from "An Overview of the Icon Programming Language" at -https://www.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks +https://www2.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks like:: sentence := "Store it in the neighboring harbor" diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index c6e2003e92f1..af489d7cb45c 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -218,10 +218,10 @@ queen threatens another) and the Knight's Tour (a route that takes a knight to every square of an $NxN$ chessboard without visiting any square twice). The idea of generators comes from other programming languages, especially Icon -(https://www.cs.arizona.edu/icon/), where the idea of generators is central. In +(https://www2.cs.arizona.edu/icon/), where the idea of generators is central. In Icon, every expression and function call behaves like a generator. One example from "An Overview of the Icon Programming Language" at -https://www.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks +https://www2.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks like:: sentence := "Store it in the neighboring harbor" @@ -1332,7 +1332,7 @@ complete list of changes, or look through the CVS logs for all the details. (Contributed by Kevin O'Connor.) * The IDLE integrated development environment has been updated using the code - from the IDLEfork project (http://idlefork.sourceforge.net). The most notable feature is + from the IDLEfork project (https://idlefork.sourceforge.net). The most notable feature is that the code being developed is now executed in a subprocess, meaning that there's no longer any need for manual ``reload()`` operations. IDLE's core code has been incorporated into the standard library as the :mod:`idlelib` package. diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 63e819876ce3..98dc83fe935d 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -756,7 +756,7 @@ API that perform ASCII-only conversions, ignoring the locale setting: :c:expr:`double` to an ASCII string. The code for these functions came from the GLib library -(https://developer.gnome.org/glib/stable/), whose developers kindly +(https://developer-old.gnome.org/glib/2.26/), whose developers kindly relicensed the relevant functions and donated them to the Python Software Foundation. The :mod:`locale` module can now change the numeric locale, letting extensions such as GTK+ produce the correct results. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 4ee2aacb108a..84bb651e68ee 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1433,7 +1433,7 @@ one, :func:`math.trunc`, that's been backported to Python 2.6. `Scheme's numerical tower <https://www.gnu.org/software/guile/manual/html_node/Numerical-Tower.html#Numerical-Tower>`__, from the Guile manual. - `Scheme's number datatypes <https://schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2>`__ from the R5RS Scheme specification. + `Scheme's number datatypes <https://conservatory.scheme.org/schemers/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2>`__ from the R5RS Scheme specification. The :mod:`fractions` Module @@ -2363,7 +2363,7 @@ changes, or look through the Subversion logs for all the details. negotiation itself. (Patch contributed by Bill Fenner; :issue:`829951`.) -* The :mod:`socket` module now supports TIPC (http://tipc.sourceforge.net/), +* The :mod:`socket` module now supports TIPC (https://tipc.sourceforge.net/), a high-performance non-IP-based protocol designed for use in clustered environments. TIPC addresses are 4- or 5-tuples. (Contributed by Alberto Bertogli; :issue:`1646`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 687719a260a6..6b591d5e184e 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -220,7 +220,7 @@ The copy of the :ref:`launcher` included with Python 3.11 has been significantly updated. It now supports company/tag syntax as defined in :pep:`514` using the ``-V:<company>/<tag>`` argument instead of the limited ``-<major>.<minor>``. This allows launching distributions other than ``PythonCore``, -the one hosted on `python.org <https://python.org>`_. +the one hosted on `python.org <https://www.python.org>`_. When using ``-V:`` selectors, either company or tag can be omitted, but all installs will be searched. For example, ``-V:OtherPython/`` will select the @@ -2481,7 +2481,7 @@ Porting to Python 3.11 #endif Or use the `pythoncapi_compat project - <https://github.com/python/pythoncapi_compat>`__ to get these two + <https://github.com/python/pythoncapi-compat>`__ to get these two functions on older Python versions. * Changes of the :c:type:`PyThreadState` structure members: @@ -2533,8 +2533,8 @@ Porting to Python 3.11 } #endif - Or use `the pythoncapi_compat project - <https://github.com/python/pythoncapi_compat>`__ to get these functions + Or use `the pythoncapi-compat project + <https://github.com/python/pythoncapi-compat>`__ to get these functions on old Python functions. * Distributors are encouraged to build Python with the optimized Blake2 diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 1b1455b72b92..8dbe2a1d828b 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -785,8 +785,8 @@ functools (Contributed by Raymond Hettinger and incorporating design ideas from Jim Baker, Miki Tebeka, and Nick Coghlan; see `recipe 498245 - <https://code.activestate.com/recipes/498245>`_\, `recipe 577479 - <https://code.activestate.com/recipes/577479>`_\, :issue:`10586`, and + <https://code.activestate.com/recipes/498245/>`_\, `recipe 577479 + <https://code.activestate.com/recipes/577479/>`_\, :issue:`10586`, and :issue:`10593`.) * The :func:`functools.wraps` decorator now adds a :attr:`__wrapped__` attribute @@ -2603,7 +2603,7 @@ Also, there were a number of updates to the Mac OS X build, see for details. For users running a 32/64-bit build, there is a known problem with the default Tcl/Tk on Mac OS X 10.6. Accordingly, we recommend installing an updated alternative such as -`ActiveState Tcl/Tk 8.5.9 <https://www.activestate.com/activetcl/downloads>`_\. +`ActiveState Tcl/Tk 8.5.9 <https://web.archive.org/web/20101208191259/https://www.activestate.com/activetcl/downloads>`_\. See https://www.python.org/download/mac/tcltk/ for additional details. Porting to Python 3.2 diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 9e8d42469b01..5b6c3dcd45c6 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1893,7 +1893,7 @@ socket * The :class:`~socket.socket` class now supports the PF_RDS protocol family (https://en.wikipedia.org/wiki/Reliable_Datagram_Sockets and - https://oss.oracle.com/projects/rds/). + `https://oss.oracle.com/projects/rds <https://web.archive.org/web/20130115155505/https://oss.oracle.com/projects/rds/>`__). * The :class:`~socket.socket` class now supports the ``PF_SYSTEM`` protocol family on OS X. (Contributed by Michael Goderbauer in :issue:`13777`.) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index f872579ef546..14b6425cea69 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -425,7 +425,7 @@ are declared in the annotations:: While these annotations are available at runtime through the usual :attr:`__annotations__` attribute, *no automatic type checking happens at runtime*. Instead, it is assumed that a separate off-line type checker -(e.g. `mypy <http://mypy-lang.org>`_) will be used for on-demand +(e.g. `mypy <https://mypy-lang.org>`_) will be used for on-demand source code analysis. The type system supports unions, generic types, and a special type @@ -2212,7 +2212,7 @@ for details.) The :c:member:`PyTypeObject.tp_finalize` slot is now part of the stable ABI. Windows builds now require Microsoft Visual C++ 14.0, which -is available as part of `Visual Studio 2015 <https://www.visualstudio.com/>`_. +is available as part of `Visual Studio 2015 <https://visualstudio.microsoft.com/en/vs/older-downloads/#visual-studio-2015-and-other-products>`_. Extension modules now include a platform information tag in their filename on some platforms (the tag is optional, and CPython will import extensions without diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index e4294c88b585..c7faaebfed62 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -238,7 +238,7 @@ and the ``__annotations__`` attribute. and Guido van Rossum. Implemented by Ivan Levkivskyi. Tools that use or will use the new syntax: - `mypy <http://www.mypy-lang.org/>`_, + `mypy <https://www.mypy-lang.org/>`_, `pytype <https://github.com/google/pytype>`_, PyCharm, etc. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 37a6cf24e545..85e088b64acb 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2229,7 +2229,7 @@ The benchmarks were measured on an `Intel? Core? i7-4960HQ processor <https://ark.intel.com/content/www/us/en/ark/products/76088/intel-core-i7-4960hq-processor-6m-cache-up-to-3-80-ghz.html>`_ running the macOS 64-bit builds found at -`python.org <https://www.python.org/downloads/mac-osx/>`_. +`python.org <https://www.python.org/downloads/macos/>`_. The benchmark script displays timings in nanoseconds. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index e974ee3a3f73..fd86db963023 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -849,7 +849,7 @@ in nanoseconds. The benchmarks were measured on an `Intel? Core? i7-4960HQ processor <https://ark.intel.com/content/www/us/en/ark/products/76088/intel-core-i7-4960hq-processor-6m-cache-up-to-3-80-ghz.html>`_ running the macOS 64-bit builds found at -`python.org <https://www.python.org/downloads/mac-osx/>`_. +`python.org <https://www.python.org/downloads/macos/>`_. Deprecated diff --git a/Misc/NEWS.d/3.7.0a1.rst b/Misc/NEWS.d/3.7.0a1.rst index 9bada1b76be7..ef93454784b7 100644 --- a/Misc/NEWS.d/3.7.0a1.rst +++ b/Misc/NEWS.d/3.7.0a1.rst @@ -6255,7 +6255,7 @@ Fix python-gdb.py didn't support new dict implementation. .. section: Tools/Demos The pybench and pystone microbenchmark have been removed from Tools. Please -use the new Python benchmark suite https://github.com/python/performance +use the new Python benchmark suite https://github.com/python/pyperformance which is more reliable and includes a portable version of pybench working on Python 2 and Python 3. From webhook-mailer at python.org Tue May 2 02:48:22 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 02 May 2023 06:48:22 -0000 Subject: [Python-checkins] [3.11] GH-103472: close response in HTTPConnection._tunnel (GH-103473) (#104077) Message-ID: <mailman.100.1683010103.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0d4026432591d43185568dd31cef6a034c4b9261 commit: 0d4026432591d43185568dd31cef6a034c4b9261 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-01T23:48:07-07:00 summary: [3.11] GH-103472: close response in HTTPConnection._tunnel (GH-103473) (#104077) GH-103472: close response in HTTPConnection._tunnel (GH-103473) Avoid a potential `ResourceWarning` in `http.client.HTTPConnection` by closing the proxy / tunnel's CONNECT response explicitly. --------- (cherry picked from commit 9de0cf20fa0485e327e57cc0864c7476da85cfad) Co-authored-by: Thomas Grainger <tagrain at gmail.com> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst M Lib/http/client.py M Lib/test/test_httplib.py diff --git a/Lib/http/client.py b/Lib/http/client.py index eabb0ca26940..5d2196dd79af 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -918,23 +918,26 @@ def _tunnel(self): del headers response = self.response_class(self.sock, method=self._method) - (version, code, message) = response._read_status() + try: + (version, code, message) = response._read_status() - if code != http.HTTPStatus.OK: - self.close() - raise OSError(f"Tunnel connection failed: {code} {message.strip()}") - while True: - line = response.fp.readline(_MAXLINE + 1) - if len(line) > _MAXLINE: - raise LineTooLong("header line") - if not line: - # for sites which EOF without sending a trailer - break - if line in (b'\r\n', b'\n', b''): - break + if code != http.HTTPStatus.OK: + self.close() + raise OSError(f"Tunnel connection failed: {code} {message.strip()}") + while True: + line = response.fp.readline(_MAXLINE + 1) + if len(line) > _MAXLINE: + raise LineTooLong("header line") + if not line: + # for sites which EOF without sending a trailer + break + if line in (b'\r\n', b'\n', b''): + break - if self.debuglevel > 0: - print('header:', line.decode()) + if self.debuglevel > 0: + print('header:', line.decode()) + finally: + response.close() def connect(self): """Connect to the host and port specified in __init__.""" diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 15dab0356f5e..acae0127a13f 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2249,6 +2249,29 @@ def test_tunnel_debuglog(self): lines = output.getvalue().splitlines() self.assertIn('header: {}'.format(expected_header), lines) + def test_tunnel_leak(self): + sock = None + + def _create_connection(address, timeout=None, source_address=None): + nonlocal sock + sock = FakeSocket( + 'HTTP/1.1 404 NOT FOUND\r\n\r\n', + host=address[0], + port=address[1], + ) + return sock + + self.conn._create_connection = _create_connection + self.conn.set_tunnel('destination.com') + exc = None + try: + self.conn.request('HEAD', '/', '') + except OSError as e: + # keeping a reference to exc keeps response alive in the traceback + exc = e + self.assertIsNotNone(exc) + self.assertTrue(sock.file_closed) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst new file mode 100644 index 000000000000..01d84f024bd4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst @@ -0,0 +1,2 @@ +Avoid a potential :exc:`ResourceWarning` in :class:`http.client.HTTPConnection` +by closing the proxy / tunnel's CONNECT response explicitly. From webhook-mailer at python.org Tue May 2 03:38:05 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 02 May 2023 07:38:05 -0000 Subject: [Python-checkins] gh-102997: Update Windows installer to SQLite 3.41.2. (#102999) Message-ID: <mailman.101.1683013086.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f6314b92dcfc8ca6ff3fd150814f85448db69165 commit: f6314b92dcfc8ca6ff3fd150814f85448db69165 branch: main author: Mariusz Felisiak <felisiak.mariusz at gmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-02T09:37:57+02:00 summary: gh-102997: Update Windows installer to SQLite 3.41.2. (#102999) files: A Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst b/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst new file mode 100644 index 000000000000..c8f7259aecba --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.41.2. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 128241393f9f..30ee873af9af 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t -set libraries=%libraries% sqlite-3.40.1.0 +set libraries=%libraries% sqlite-3.41.2.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index 7994fbe7cd5e..29add07795f9 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -68,7 +68,7 @@ <Import Project="$(ExternalProps)" Condition="$(ExternalProps) != '' and Exists('$(ExternalProps)')" /> <PropertyGroup> - <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.40.1.0\</sqlite3Dir> + <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.41.2.0\</sqlite3Dir> <bz2Dir Condition="$(bz2Dir) == ''">$(ExternalsDir)bzip2-1.0.8\</bz2Dir> <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.2.5\</lzmaDir> <libffiDir Condition="$(libffiDir) == ''">$(ExternalsDir)libffi-3.4.4\</libffiDir> diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 4c799b64c461..9df56685b76a 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -188,7 +188,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.40.1, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.41.2, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Tue May 2 03:44:23 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 02 May 2023 07:44:23 -0000 Subject: [Python-checkins] [3.11] Improve assert_type phrasing (GH-104081) (#104084) Message-ID: <mailman.102.1683013465.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3e7e50e65632d6fb45b2055b0351a117f9f953b9 commit: 3e7e50e65632d6fb45b2055b0351a117f9f953b9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-02T08:44:16+01:00 summary: [3.11] Improve assert_type phrasing (GH-104081) (#104084) Improve assert_type phrasing (GH-104081) I'd like to make the fact that this does nothing at runtime really obvious, since I suspect this is unintuitive for users who are unfamiliar with static type checking. I thought of this because of https://discuss.python.org/t/add-arg-check-type-to-types/26384 wherein I'm skeptical that the user really did want `assert_type`. (cherry picked from commit 82ba6ce303d04a7b21034e38d220e23ca9f1dc0a) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/typing.rst M Lib/typing.py diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 60f49d7029df..00d74f7dc31e 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2438,15 +2438,16 @@ Functions and decorators Ask a static type checker to confirm that *val* has an inferred type of *typ*. - When the type checker encounters a call to ``assert_type()``, it + At runtime this does nothing: it returns the first argument unchanged with no + checks or side effects, no matter the actual type of the argument. + + When a static type checker encounters a call to ``assert_type()``, it emits an error if the value is not of the specified type:: def greet(name: str) -> None: assert_type(name, str) # OK, inferred type of `name` is `str` assert_type(name, int) # type checker error - At runtime this returns the first argument unchanged with no side effects. - This function is useful for ensuring the type checker's understanding of a script is in line with the developer's intentions:: diff --git a/Lib/typing.py b/Lib/typing.py index 7a50e0603537..2db354017a8b 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2250,15 +2250,16 @@ def cast(typ, val): def assert_type(val, typ, /): """Ask a static type checker to confirm that the value is of the given type. - When the type checker encounters a call to assert_type(), it + At runtime this does nothing: it returns the first argument unchanged with no + checks or side effects, no matter the actual type of the argument. + + When a static type checker encounters a call to assert_type(), it emits an error if the value is not of the specified type:: def greet(name: str) -> None: assert_type(name, str) # ok assert_type(name, int) # type checker error - At runtime this returns the first argument unchanged and otherwise - does nothing. """ return val From webhook-mailer at python.org Tue May 2 04:15:40 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 02 May 2023 08:15:40 -0000 Subject: [Python-checkins] [3.11] gh-102997: Update Windows installer to SQLite 3.41.2. (#102999) (#104085) Message-ID: <mailman.103.1683015340.13550.python-checkins@python.org> https://github.com/python/cpython/commit/61f1fbd04016e53d6ea96d23b84ead7d6ab9fbb9 commit: 61f1fbd04016e53d6ea96d23b84ead7d6ab9fbb9 branch: 3.11 author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-02T08:15:06Z summary: [3.11] gh-102997: Update Windows installer to SQLite 3.41.2. (#102999) (#104085) Co-authored-by: Mariusz Felisiak <felisiak.mariusz at gmail.com> files: A Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst b/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst new file mode 100644 index 0000000000000..c8f7259aecba6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.41.2. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 8507b5e528894..329f2a2ade235 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t -set libraries=%libraries% sqlite-3.40.1.0 +set libraries=%libraries% sqlite-3.41.2.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index 7994fbe7cd5e0..29add07795f90 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -68,7 +68,7 @@ <Import Project="$(ExternalProps)" Condition="$(ExternalProps) != '' and Exists('$(ExternalProps)')" /> <PropertyGroup> - <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.40.1.0\</sqlite3Dir> + <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.41.2.0\</sqlite3Dir> <bz2Dir Condition="$(bz2Dir) == ''">$(ExternalsDir)bzip2-1.0.8\</bz2Dir> <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.2.5\</lzmaDir> <libffiDir Condition="$(libffiDir) == ''">$(ExternalsDir)libffi-3.4.4\</libffiDir> diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index cce2632a6cdda..b73196510dcd3 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -187,7 +187,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.40.1, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.41.2, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Tue May 2 07:38:53 2023 From: webhook-mailer at python.org (encukou) Date: Tue, 02 May 2023 11:38:53 -0000 Subject: [Python-checkins] gh-103743: Add PyUnstable_Object_GC_NewWithExtraData (GH-103744) Message-ID: <mailman.104.1683027533.13550.python-checkins@python.org> https://github.com/python/cpython/commit/87223f32aba872cfebde6fbe38673799eb79f248 commit: 87223f32aba872cfebde6fbe38673799eb79f248 branch: main author: Jurica Bradari? <jbradaric at users.noreply.github.com> committer: encukou <encukou at gmail.com> date: 2023-05-02T13:38:46+02:00 summary: gh-103743: Add PyUnstable_Object_GC_NewWithExtraData (GH-103744) Co-authored-by: Petr Viktorin <encukou at gmail.com> Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst M Doc/c-api/gcsupport.rst M Include/cpython/objimpl.h M Lib/test/test_capi/test_misc.py M Modules/_testcapimodule.c M Modules/gcmodule.c diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index cb5d64a50487..c3260a21bc7f 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -59,12 +59,31 @@ rules: Analogous to :c:func:`PyObject_New` but for container objects with the :const:`Py_TPFLAGS_HAVE_GC` flag set. - .. c:function:: TYPE* PyObject_GC_NewVar(TYPE, PyTypeObject *type, Py_ssize_t size) Analogous to :c:func:`PyObject_NewVar` but for container objects with the :const:`Py_TPFLAGS_HAVE_GC` flag set. +.. c:function:: PyObject* PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size) + + Analogous to :c:func:`PyObject_GC_New` but allocates *extra_size* + bytes at the end of the object (at offset + :c:member:`~PyTypeObject.tp_basicsize`). + The allocated memory is initialized to zeros, + except for the :c:type:`Python object header <PyObject>`. + + The extra data will be deallocated with the object, but otherwise it is + not managed by Python. + + .. warning:: + The function is marked as unstable because the final mechanism + for reserving extra data after an instance is not yet decided. + For allocating a variable number of fields, prefer using + :c:type:`PyVarObject` and :c:member:`~PyTypeObject.tp_itemsize` + instead. + + .. versionadded:: 3.12 + .. c:function:: TYPE* PyObject_GC_Resize(TYPE, PyVarObject *op, Py_ssize_t newsize) diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 0b038d31080b..5a8cdd57c784 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -90,3 +90,6 @@ PyAPI_FUNC(int) PyObject_IS_GC(PyObject *obj); PyAPI_FUNC(int) PyType_SUPPORTS_WEAKREFS(PyTypeObject *type); PyAPI_FUNC(PyObject **) PyObject_GET_WEAKREFS_LISTPTR(PyObject *op); + +PyAPI_FUNC(PyObject *) PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *, + size_t); diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9470cf12a7d1..9d5d1ca6e7dc 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1043,6 +1043,20 @@ class dictsub(dict): ... # dict subclasses must work self.assertEqual(_testcapi.function_get_kw_defaults(some), None) self.assertEqual(some.__kwdefaults__, None) + def test_unstable_gc_new_with_extra_data(self): + class Data(_testcapi.ObjExtraData): + __slots__ = ('x', 'y') + + d = Data() + d.x = 10 + d.y = 20 + d.extra = 30 + self.assertEqual(d.x, 10) + self.assertEqual(d.y, 20) + self.assertEqual(d.extra, 30) + del d.extra + self.assertIsNone(d.extra) + class TestPendingCalls(unittest.TestCase): diff --git a/Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst b/Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst new file mode 100644 index 000000000000..d074350ed3eb --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst @@ -0,0 +1,2 @@ +Add :c:func:`PyUnstable_Object_GC_NewWithExtraData` function that can be used to +allocate additional memory after an object for data not managed by Python. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c1892f6fa0a4..a5d23b1b3d50 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3363,7 +3363,7 @@ test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), } state.target = obj; state.found = 0; - + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); Py_DECREF(obj); if (!state.found) { @@ -3400,6 +3400,98 @@ test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), Py_RETURN_NONE; } +typedef struct { + PyObject_HEAD +} ObjExtraData; + +static PyObject * +obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + size_t extra_size = sizeof(PyObject *); + PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size); + if (obj == NULL) { + return PyErr_NoMemory(); + } + PyObject_GC_Track(obj); + return obj; +} + +static PyObject ** +obj_extra_data_get_extra_storage(PyObject *self) +{ + return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize); +} + +static PyObject * +obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + PyObject *value = *extra_storage; + if (!value) { + Py_RETURN_NONE; + } + return Py_NewRef(value); +} + +static int +obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored)) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + Py_CLEAR(*extra_storage); + if (newval) { + *extra_storage = Py_NewRef(newval); + } + return 0; +} + +static PyGetSetDef obj_extra_data_getset[] = { + {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL}, + {NULL} +}; + +static int +obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + PyObject *value = *extra_storage; + Py_VISIT(value); + return 0; +} + +static int +obj_extra_data_clear(PyObject *self) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + Py_CLEAR(*extra_storage); + return 0; +} + +static void +obj_extra_data_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + obj_extra_data_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot ObjExtraData_Slots[] = { + {Py_tp_getset, obj_extra_data_getset}, + {Py_tp_dealloc, obj_extra_data_dealloc}, + {Py_tp_traverse, obj_extra_data_traverse}, + {Py_tp_clear, obj_extra_data_clear}, + {Py_tp_new, obj_extra_data_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec ObjExtraData_TypeSpec = { + .name = "_testcapi.ObjExtraData", + .basicsize = sizeof(ObjExtraData), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .slots = ObjExtraData_Slots, +}; struct atexit_data { int called; @@ -4124,6 +4216,17 @@ PyInit__testcapi(void) Py_INCREF(&MethStatic_Type); PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type); + PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec( + m, &ObjExtraData_TypeSpec, NULL); + if (ObjExtraData_Type == 0) { + return NULL; + } + int ret = PyModule_AddType(m, (PyTypeObject*)ObjExtraData_Type); + Py_DECREF(&ObjExtraData_Type); + if (ret < 0) { + return NULL; + } + PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX)); PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN)); PyModule_AddObject(m, "UCHAR_MAX", PyLong_FromLong(UCHAR_MAX)); diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 3fd5f4cd70e8..8a4d1a439828 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2367,6 +2367,19 @@ _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) return op; } +PyObject * +PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *tp, size_t extra_size) +{ + size_t presize = _PyType_PreHeaderSize(tp); + PyObject *op = gc_alloc(_PyObject_SIZE(tp) + extra_size, presize); + if (op == NULL) { + return NULL; + } + memset(op, 0, _PyObject_SIZE(tp) + extra_size); + _PyObject_Init(op, tp); + return op; +} + PyVarObject * _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) { From webhook-mailer at python.org Tue May 2 07:50:23 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 02 May 2023 11:50:23 -0000 Subject: [Python-checkins] [3.11] GH-103484: Fix redirected permanently URLs (GH-104001) (#104088) Message-ID: <mailman.105.1683028224.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5e76305236df99aec191431585cd4bfa0c080766 commit: 5e76305236df99aec191431585cd4bfa0c080766 branch: 3.11 author: Rafael Fontenelle <rffontenelle at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-02T14:50:16+03:00 summary: [3.11] GH-103484: Fix redirected permanently URLs (GH-104001) (#104088) Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> Co-authored-by: Oleg Iarygin <dralife at yandex.ru> Fix redirected permanently URLs (#104001) files: M Doc/conf.py M Doc/distutils/apiref.rst M Doc/distutils/examples.rst M Doc/distutils/setupscript.rst M Doc/faq/extending.rst M Doc/faq/general.rst M Doc/faq/programming.rst M Doc/howto/pyporting.rst M Doc/library/asyncio-eventloop.rst M Doc/library/hashlib.rst M Doc/library/os.rst M Doc/library/plistlib.rst M Doc/library/resource.rst M Doc/library/select.rst M Doc/library/ssl.rst M Doc/library/statistics.rst M Doc/library/struct.rst M Doc/library/sys.rst M Doc/library/unittest.mock-examples.rst M Doc/library/unittest.rst M Doc/library/xmlrpc.client.rst M Doc/library/zipfile.rst M Doc/reference/datamodel.rst M Doc/reference/introduction.rst M Doc/using/cmdline.rst M Doc/using/mac.rst M Doc/using/windows.rst M Doc/whatsnew/2.0.rst M Doc/whatsnew/2.1.rst M Doc/whatsnew/2.2.rst M Doc/whatsnew/2.3.rst M Doc/whatsnew/2.4.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.2.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.5.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.8.rst M Doc/whatsnew/3.9.rst M Misc/NEWS.d/3.7.0a1.rst diff --git a/Doc/conf.py b/Doc/conf.py index 138a18409983..3bb915b0b02e 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -260,11 +260,29 @@ 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+', + r'https://bugs.python.org/issue\?@action=redirect&bpo=\d+': r'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+', + r'https://github.com/python/cpython/issues/\d+': r'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/.*' + r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*', + # Intentional HTTP use at Misc/NEWS.d/3.5.0a1.rst + r'http://www.python.org/$': 'https://www.python.org/$', + # Used in license page, keep as is + r'https://www.zope.org/': r'https://www.zope.dev/', + # Microsoft's redirects to learn.microsoft.com + r'https://msdn.microsoft.com/.*': 'https://learn.microsoft.com/.*', + r'https://docs.microsoft.com/.*': 'https://learn.microsoft.com/.*', + r'https://go.microsoft.com/fwlink/\?LinkID=\d+': 'https://learn.microsoft.com/.*', + # Language redirects + r'https://toml.io': 'https://toml.io/en/', + r'https://www.redhat.com': 'https://www.redhat.com/en', + # Other redirects + r'https://www.boost.org/libs/.+': r'https://www.boost.org/doc/libs/\d_\d+_\d/.+', + r'https://support.microsoft.com/en-us/help/\d+': 'https://support.microsoft.com/en-us/topic/.+', + r'https://perf.wiki.kernel.org$': 'https://perf.wiki.kernel.org/index.php/Main_Page', + r'https://www.sqlite.org': 'https://www.sqlite.org/index.html', + r'https://mitpress.mit.edu/sicp$': 'https://mitpress.mit.edu/9780262510875/structure-and-interpretation-of-computer-programs/', + r'https://www.python.org/psf/': 'https://www.python.org/psf-landing/', } linkcheck_anchors_ignore = [ diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst index 87c928555554..56bed7d63f1e 100644 --- a/Doc/distutils/apiref.rst +++ b/Doc/distutils/apiref.rst @@ -1021,7 +1021,7 @@ directories. Files in *src* that begin with :file:`.nfs` are skipped (more information on these files is available in answer D2 of the `NFS FAQ page - <http://nfs.sourceforge.net/#section_d>`_). + <https://nfs.sourceforge.net/#section_d>`_). .. versionchanged:: 3.3.1 NFS files are ignored. diff --git a/Doc/distutils/examples.rst b/Doc/distutils/examples.rst index e492b7f60575..49e4b6e4b984 100644 --- a/Doc/distutils/examples.rst +++ b/Doc/distutils/examples.rst @@ -337,4 +337,4 @@ loads its values:: .. % \section{Putting it all together} -.. _docutils: http://docutils.sourceforge.net +.. _docutils: https://docutils.sourceforge.io diff --git a/Doc/distutils/setupscript.rst b/Doc/distutils/setupscript.rst index 4386a60b664b..8635c911622b 100644 --- a/Doc/distutils/setupscript.rst +++ b/Doc/distutils/setupscript.rst @@ -642,7 +642,7 @@ Notes: 'long string' Multiple lines of plain text in reStructuredText format (see - http://docutils.sourceforge.net/). + https://docutils.sourceforge.io/). 'list of strings' See below. diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst index 07282639e4f9..bc3080f60ee2 100644 --- a/Doc/faq/extending.rst +++ b/Doc/faq/extending.rst @@ -42,7 +42,7 @@ on what you're trying to do. .. XXX make sure these all work `Cython <https://cython.org>`_ and its relative `Pyrex -<https://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/>`_ are compilers +<https://www.csse.canterbury.ac.nz/greg.ewing/python/Pyrex/>`_ are compilers that accept a slightly modified form of Python and generate the corresponding C code. Cython and Pyrex make it possible to write an extension without having to learn Python's C API. diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 6256deb5797c..a9b2622e02ef 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -54,8 +54,8 @@ commercial use, to sell copies of Python in source or binary form (modified or unmodified), or to sell products that incorporate Python in some form. We would still like to know about all commercial use of Python, of course. -See `the PSF license page <https://www.python.org/psf/license/>`_ to find further -explanations and a link to the full text of the license. +See `the license page <https://docs.python.org/3/license.html>`_ to find further +explanations and the full text of the PSF License. The Python logo is trademarked, and in certain cases permission is required to use it. Consult `the Trademark Usage Policy @@ -215,7 +215,7 @@ every day, and Usenet readers are often more able to cope with this volume. Announcements of new software releases and events can be found in comp.lang.python.announce, a low-traffic moderated list that receives about five postings per day. It's available as `the python-announce mailing list -<https://mail.python.org/mailman/listinfo/python-announce-list>`_. +<https://mail.python.org/mailman3/lists/python-announce-list.python.org/>`_. More info about other mailing lists and newsgroups can be found at https://www.python.org/community/lists/. @@ -352,7 +352,7 @@ titled "Python X.Y Release Schedule", where X.Y is a version that hasn't been publicly released yet. New development is discussed on `the python-dev mailing list -<https://mail.python.org/mailman/listinfo/python-dev/>`_. +<https://mail.python.org/mailman3/lists/python-dev.python.org/>`_. Is it reasonable to propose incompatible changes to Python? diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index 38f9b171618b..ab5618db84f7 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -61,7 +61,7 @@ Yes. `Pyflakes <https://github.com/PyCQA/pyflakes>`_ do basic checking that will help you catch bugs sooner. -Static type checkers such as `Mypy <http://mypy-lang.org/>`_, +Static type checkers such as `Mypy <https://mypy-lang.org/>`_, `Pyre <https://pyre-check.org/>`_, and `Pytype <https://github.com/google/pytype>`_ can check type hints in Python source code. diff --git a/Doc/howto/pyporting.rst b/Doc/howto/pyporting.rst index add1c11be534..baea3e85c3b8 100644 --- a/Doc/howto/pyporting.rst +++ b/Doc/howto/pyporting.rst @@ -438,7 +438,7 @@ to make sure everything functions as expected in both versions of Python. .. _Futurize: https://python-future.org/automatic_conversion.html .. _importlib2: https://pypi.org/project/importlib2 .. _Modernize: https://python-modernize.readthedocs.io/ -.. _mypy: http://mypy-lang.org/ +.. _mypy: https://mypy-lang.org/ .. _Porting to Python 3: http://python3porting.com/ .. _Pylint: https://pypi.org/project/pylint diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 170a3df8197b..3644c17c6b37 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -515,7 +515,7 @@ Opening network connections specifies requirements for algorithms that reduce this user-visible delay and provides an algorithm. - For more information: https://tools.ietf.org/html/rfc6555 + For more information: https://datatracker.ietf.org/doc/html/rfc6555 .. versionchanged:: 3.11 diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index a96fc8b8ff7e..bea862d7967c 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -438,7 +438,7 @@ Constructor functions also accept the following tree hashing parameters: :alt: Explanation of tree mode parameters. See section 2.10 in `BLAKE2 specification -<https://blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree +<https://www.blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree hashing. @@ -624,7 +624,7 @@ on the hash function used in digital signatures. by the signer. (`NIST SP-800-106 "Randomized Hashing for Digital Signatures" - <https://csrc.nist.gov/publications/detail/sp/800-106/final>`_) + <https://csrc.nist.gov/publications/detail/sp/800-106/archive/2009-02-25>`_) In BLAKE2 the salt is processed as a one-time input to the hash function during initialization, rather than as an input to each compression function. @@ -633,7 +633,7 @@ initialization, rather than as an input to each compression function. *Salted hashing* (or just hashing) with BLAKE2 or any other general-purpose cryptographic hash function, such as SHA-256, is not suitable for hashing - passwords. See `BLAKE2 FAQ <https://blake2.net/#qa>`_ for more + passwords. See `BLAKE2 FAQ <https://www.blake2.net/#qa>`_ for more information. .. @@ -769,9 +769,9 @@ Domain Dedication 1.0 Universal: * *Alexandr Sokolovskiy* -.. _BLAKE2: https://blake2.net +.. _BLAKE2: https://www.blake2.net .. _HMAC: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code -.. _BLAKE: https://131002.net/blake/ +.. _BLAKE: https://web.archive.org/web/20200918190133/https://131002.net/blake/ .. _SHA-3: https://en.wikipedia.org/wiki/NIST_hash_function_competition .. _ChaCha: https://cr.yp.to/chacha.html .. _pyblake2: https://pythonhosted.org/pyblake2/ @@ -787,7 +787,7 @@ Domain Dedication 1.0 Universal: Module :mod:`base64` Another way to encode binary hashes for non-binary environments. - https://blake2.net + https://www.blake2.net Official BLAKE2 website. https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 7b7ab860da8d..19e5bee34e84 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -4364,7 +4364,7 @@ written in Python, such as a mail server's external command delivery program. :attr:`!children_system`, and :attr:`!elapsed` in that order. See the Unix manual page - :manpage:`times(2)` and `times(3) <https://www.freebsd.org/cgi/man.cgi?time(3)>`_ manual page on Unix or `the GetProcessTimes MSDN + :manpage:`times(2)` and `times(3) <https://man.freebsd.org/cgi/man.cgi?time(3)>`_ manual page on Unix or `the GetProcessTimes MSDN <https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes>`_ on Windows. On Windows, only :attr:`!user` and :attr:`!system` are known; the other attributes are zero. diff --git a/Doc/library/plistlib.rst b/Doc/library/plistlib.rst index 7aad15ec91a0..732ef3536863 100644 --- a/Doc/library/plistlib.rst +++ b/Doc/library/plistlib.rst @@ -46,7 +46,7 @@ or :class:`datetime.datetime` objects. .. seealso:: - `PList manual page <https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/>`_ + `PList manual page <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/PropertyLists/>`_ Apple's documentation of the file format. diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst index e7bf45d7d569..a5324c82c634 100644 --- a/Doc/library/resource.rst +++ b/Doc/library/resource.rst @@ -244,7 +244,7 @@ platform. used by all of this user id's processes. This limit is enforced only if bit 1 of the vm.overcommit sysctl is set. Please see - `tuning(7) <https://www.freebsd.org/cgi/man.cgi?query=tuning&sektion=7>`__ + `tuning(7) <https://man.freebsd.org/cgi/man.cgi?query=tuning&sektion=7>`__ for a complete description of this sysctl. .. availability:: FreeBSD. diff --git a/Doc/library/select.rst b/Doc/library/select.rst index 2890706bab72..b0891b0c8f58 100644 --- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -505,7 +505,7 @@ Kqueue Objects Kevent Objects -------------- -https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 +https://man.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2 .. attribute:: kevent.ident diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 6ac08fd6548e..289dd0b51dea 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1814,7 +1814,7 @@ to speed up repeated connections from the same clients. .. versionadded:: 3.3 .. seealso:: - `SSL/TLS & Perfect Forward Secrecy <https://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy>`_ + `SSL/TLS & Perfect Forward Secrecy <https://vincent.bernat.ch/en/blog/2011-ssl-perfect-forward-secrecy>`_ Vincent Bernat. .. method:: SSLContext.wrap_socket(sock, server_side=False, \ diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index 78c4bc521fdd..03867b3d391a 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -22,7 +22,7 @@ This module provides functions for calculating mathematical statistics of numeric (:class:`~numbers.Real`-valued) data. The module is not intended to be a competitor to third-party libraries such -as `NumPy <https://numpy.org>`_, `SciPy <https://www.scipy.org/>`_, or +as `NumPy <https://numpy.org>`_, `SciPy <https://scipy.org/>`_, or proprietary full-featured statistics packages aimed at professional statisticians such as Minitab, SAS and Matlab. It is aimed at the level of graphing and scientific calculators. diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 12f247462fa6..9db13d58c625 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -602,4 +602,4 @@ The :mod:`struct` module also defines the following type: .. _ieee 754 standard: https://en.wikipedia.org/wiki/IEEE_754-2008_revision -.. _IETF RFC 1700: https://tools.ietf.org/html/rfc1700 +.. _IETF RFC 1700: https://datatracker.ietf.org/doc/html/rfc1700 diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 3d1506f553ad..6f90e6b42216 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -781,7 +781,7 @@ always available. additional garbage collector overhead if the object is managed by the garbage collector. - See `recursive sizeof recipe <https://code.activestate.com/recipes/577504>`_ + See `recursive sizeof recipe <https://code.activestate.com/recipes/577504/>`_ for an example of using :func:`getsizeof` recursively to find the size of containers and all their contents. diff --git a/Doc/library/unittest.mock-examples.rst b/Doc/library/unittest.mock-examples.rst index f9a207bad690..895b9f9f0767 100644 --- a/Doc/library/unittest.mock-examples.rst +++ b/Doc/library/unittest.mock-examples.rst @@ -1074,7 +1074,7 @@ subclass. Sometimes this is inconvenient. For example, `one user <https://code.google.com/archive/p/mock/issues/105>`_ is subclassing mock to created a `Twisted adaptor -<https://twistedmatrix.com/documents/11.0.0/api/twisted.python.components.html>`_. +<https://twisted.org/documents/11.0.0/api/twisted.python.components.html>`_. Having this applied to attributes too actually causes errors. ``Mock`` (in all its flavours) uses a method called ``_get_child_mock`` to create diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 82fded4ab002..c2ed7acaf5f0 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -72,7 +72,7 @@ test runner a GUI tool for test discovery and execution. This is intended largely for ease of use for those new to unit testing. For production environments it is recommended that tests be driven by a continuous integration system such as - `Buildbot <https://buildbot.net/>`_, `Jenkins <https://jenkins.io/>`_, + `Buildbot <https://buildbot.net/>`_, `Jenkins <https://www.jenkins.io/>`_, `GitHub Actions <https://github.com/features/actions>`_, or `AppVeyor <https://www.appveyor.com/>`_. diff --git a/Doc/library/xmlrpc.client.rst b/Doc/library/xmlrpc.client.rst index bd2c49a6edab..146c4fd76823 100644 --- a/Doc/library/xmlrpc.client.rst +++ b/Doc/library/xmlrpc.client.rst @@ -161,7 +161,7 @@ between conformable Python objects and XML on the wire. .. seealso:: - `XML-RPC HOWTO <https://www.tldp.org/HOWTO/XML-RPC-HOWTO/index.html>`_ + `XML-RPC HOWTO <https://tldp.org/HOWTO/XML-RPC-HOWTO/index.html>`_ A good description of XML-RPC operation and client software in several languages. Contains pretty much everything an XML-RPC client developer needs to know. diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 9e8e9c3cc205..f4867575447c 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -128,7 +128,7 @@ The module defines the following items: Documentation on the ZIP file format by Phil Katz, the creator of the format and algorithms used. - `Info-ZIP Home Page <http://www.info-zip.org/>`_ + `Info-ZIP Home Page <https://infozip.sourceforge.net/>`_ Information about the Info-ZIP project's ZIP archive programs and development libraries. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 3f0c99cd09eb..277b9e5aa247 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1563,7 +1563,7 @@ Basic customization This is intended to provide protection against a denial-of-service caused by carefully chosen inputs that exploit the worst case performance of a dict insertion, O(n\ :sup:`2`) complexity. See - http://www.ocert.org/advisories/ocert-2011-003.html for details. + http://ocert.org/advisories/ocert-2011-003.html for details. Changing hash values affects the iteration order of sets. Python has never made guarantees about this ordering diff --git a/Doc/reference/introduction.rst b/Doc/reference/introduction.rst index 914a11556c94..81f0a5c5d438 100644 --- a/Doc/reference/introduction.rst +++ b/Doc/reference/introduction.rst @@ -74,7 +74,7 @@ PyPy and a Just in Time compiler. One of the goals of the project is to encourage experimentation with the language itself by making it easier to modify the interpreter (since it is written in Python). Additional information is - available on `the PyPy project's home page <https://pypy.org/>`_. + available on `the PyPy project's home page <https://www.pypy.org/>`_. Each of these implementations varies in some way from the language as documented in this manual, or introduces specific information beyond what's covered in the diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 01f3af39173b..ecc877f5020d 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -367,7 +367,7 @@ Miscellaneous options Hash randomization is intended to provide protection against a denial-of-service caused by carefully chosen inputs that exploit the worst case performance of a dict construction, O(n\ :sup:`2`) complexity. See - http://www.ocert.org/advisories/ocert-2011-003.html for details. + http://ocert.org/advisories/ocert-2011-003.html for details. :envvar:`PYTHONHASHSEED` allows you to set a fixed value for the hash seed secret. diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 9ae0270eaee7..69cd5c92d884 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -66,7 +66,7 @@ number of standard Unix command line editors, :program:`vim` and :program:`BBEdit` or :program:`TextWrangler` from Bare Bones Software (see http://www.barebones.com/products/bbedit/index.html) are good choices, as is :program:`TextMate` (see https://macromates.com/). Other editors include -:program:`Gvim` (https://macvim-dev.github.io/macvim/) and :program:`Aquamacs` +:program:`Gvim` (https://macvim.org/macvim/) and :program:`Aquamacs` (http://aquamacs.org/). To run your script from the Terminal window you must make sure that diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 1591982da52f..f51a5247b639 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -528,7 +528,7 @@ Besides the standard CPython distribution, there are modified packages including additional functionality. The following is a list of popular versions and their key features: -`ActivePython <https://www.activestate.com/activepython/>`_ +`ActivePython <https://www.activestate.com/products/python/>`_ Installer with multi-platform compatibility, documentation, PyWin32 `Anaconda <https://www.anaconda.com/download/>`_ diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index 6b16dfd4685b..cd9fa89ca8a9 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -933,7 +933,7 @@ using it:: parser.parse( 'hamlet.xml' ) For more information, consult the Python documentation, or the XML HOWTO at -http://pyxml.sourceforge.net/topics/howto/xml-howto.html. +https://pyxml.sourceforge.net/topics/howto/xml-howto.html. DOM Support diff --git a/Doc/whatsnew/2.1.rst b/Doc/whatsnew/2.1.rst index 0136de587740..676da702b396 100644 --- a/Doc/whatsnew/2.1.rst +++ b/Doc/whatsnew/2.1.rst @@ -613,7 +613,7 @@ New and Improved Modules framework based on running embedded examples in docstrings and comparing the results against the expected output. PyUnit, contributed by Steve Purcell, is a unit testing framework inspired by JUnit, which was in turn an adaptation of - Kent Beck's Smalltalk testing framework. See http://pyunit.sourceforge.net/ for + Kent Beck's Smalltalk testing framework. See https://pyunit.sourceforge.net/ for more information about PyUnit. * The :mod:`difflib` module contains a class, :class:`SequenceMatcher`, which diff --git a/Doc/whatsnew/2.2.rst b/Doc/whatsnew/2.2.rst index 0c3bfda19339..82aff0be1ed3 100644 --- a/Doc/whatsnew/2.2.rst +++ b/Doc/whatsnew/2.2.rst @@ -632,10 +632,10 @@ queen threatens another) and the Knight's Tour (a route that takes a knight to every square of an $NxN$ chessboard without visiting any square twice). The idea of generators comes from other programming languages, especially Icon -(https://www.cs.arizona.edu/icon/), where the idea of generators is central. In +(https://www2.cs.arizona.edu/icon/), where the idea of generators is central. In Icon, every expression and function call behaves like a generator. One example from "An Overview of the Icon Programming Language" at -https://www.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks +https://www2.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks like:: sentence := "Store it in the neighboring harbor" diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index c6e2003e92f1..af489d7cb45c 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -218,10 +218,10 @@ queen threatens another) and the Knight's Tour (a route that takes a knight to every square of an $NxN$ chessboard without visiting any square twice). The idea of generators comes from other programming languages, especially Icon -(https://www.cs.arizona.edu/icon/), where the idea of generators is central. In +(https://www2.cs.arizona.edu/icon/), where the idea of generators is central. In Icon, every expression and function call behaves like a generator. One example from "An Overview of the Icon Programming Language" at -https://www.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks +https://www2.cs.arizona.edu/icon/docs/ipd266.htm gives an idea of what this looks like:: sentence := "Store it in the neighboring harbor" @@ -1332,7 +1332,7 @@ complete list of changes, or look through the CVS logs for all the details. (Contributed by Kevin O'Connor.) * The IDLE integrated development environment has been updated using the code - from the IDLEfork project (http://idlefork.sourceforge.net). The most notable feature is + from the IDLEfork project (https://idlefork.sourceforge.net). The most notable feature is that the code being developed is now executed in a subprocess, meaning that there's no longer any need for manual ``reload()`` operations. IDLE's core code has been incorporated into the standard library as the :mod:`idlelib` package. diff --git a/Doc/whatsnew/2.4.rst b/Doc/whatsnew/2.4.rst index 63e819876ce3..98dc83fe935d 100644 --- a/Doc/whatsnew/2.4.rst +++ b/Doc/whatsnew/2.4.rst @@ -756,7 +756,7 @@ API that perform ASCII-only conversions, ignoring the locale setting: :c:expr:`double` to an ASCII string. The code for these functions came from the GLib library -(https://developer.gnome.org/glib/stable/), whose developers kindly +(https://developer-old.gnome.org/glib/2.26/), whose developers kindly relicensed the relevant functions and donated them to the Python Software Foundation. The :mod:`locale` module can now change the numeric locale, letting extensions such as GTK+ produce the correct results. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 4ee2aacb108a..84bb651e68ee 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1433,7 +1433,7 @@ one, :func:`math.trunc`, that's been backported to Python 2.6. `Scheme's numerical tower <https://www.gnu.org/software/guile/manual/html_node/Numerical-Tower.html#Numerical-Tower>`__, from the Guile manual. - `Scheme's number datatypes <https://schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2>`__ from the R5RS Scheme specification. + `Scheme's number datatypes <https://conservatory.scheme.org/schemers/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2>`__ from the R5RS Scheme specification. The :mod:`fractions` Module @@ -2363,7 +2363,7 @@ changes, or look through the Subversion logs for all the details. negotiation itself. (Patch contributed by Bill Fenner; :issue:`829951`.) -* The :mod:`socket` module now supports TIPC (http://tipc.sourceforge.net/), +* The :mod:`socket` module now supports TIPC (https://tipc.sourceforge.net/), a high-performance non-IP-based protocol designed for use in clustered environments. TIPC addresses are 4- or 5-tuples. (Contributed by Alberto Bertogli; :issue:`1646`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 378315b36c6e..95fd8b6c9727 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -222,7 +222,7 @@ The copy of the :ref:`launcher` included with Python 3.11 has been significantly updated. It now supports company/tag syntax as defined in :pep:`514` using the ``-V:<company>/<tag>`` argument instead of the limited ``-<major>.<minor>``. This allows launching distributions other than ``PythonCore``, -the one hosted on `python.org <https://python.org>`_. +the one hosted on `python.org <https://www.python.org>`_. When using ``-V:`` selectors, either company or tag can be omitted, but all installs will be searched. For example, ``-V:OtherPython/`` will select the @@ -2483,7 +2483,7 @@ Porting to Python 3.11 #endif Or use the `pythoncapi_compat project - <https://github.com/python/pythoncapi_compat>`__ to get these two + <https://github.com/python/pythoncapi-compat>`__ to get these two functions on older Python versions. * Changes of the :c:type:`PyThreadState` structure members: @@ -2535,8 +2535,8 @@ Porting to Python 3.11 } #endif - Or use `the pythoncapi_compat project - <https://github.com/python/pythoncapi_compat>`__ to get these functions + Or use `the pythoncapi-compat project + <https://github.com/python/pythoncapi-compat>`__ to get these functions on old Python functions. * Distributors are encouraged to build Python with the optimized Blake2 diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 3becd3f71928..8e2f9e2716c4 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -783,8 +783,8 @@ functools (Contributed by Raymond Hettinger and incorporating design ideas from Jim Baker, Miki Tebeka, and Nick Coghlan; see `recipe 498245 - <https://code.activestate.com/recipes/498245>`_\, `recipe 577479 - <https://code.activestate.com/recipes/577479>`_\, :issue:`10586`, and + <https://code.activestate.com/recipes/498245/>`_\, `recipe 577479 + <https://code.activestate.com/recipes/577479/>`_\, :issue:`10586`, and :issue:`10593`.) * The :func:`functools.wraps` decorator now adds a :attr:`__wrapped__` attribute @@ -2601,7 +2601,7 @@ Also, there were a number of updates to the Mac OS X build, see for details. For users running a 32/64-bit build, there is a known problem with the default Tcl/Tk on Mac OS X 10.6. Accordingly, we recommend installing an updated alternative such as -`ActiveState Tcl/Tk 8.5.9 <https://www.activestate.com/activetcl/downloads>`_\. +`ActiveState Tcl/Tk 8.5.9 <https://web.archive.org/web/20101208191259/https://www.activestate.com/activetcl/downloads>`_\. See https://www.python.org/download/mac/tcltk/ for additional details. Porting to Python 3.2 diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 96a632577b2c..74cfa8385c4c 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1892,7 +1892,7 @@ socket * The :class:`~socket.socket` class now supports the PF_RDS protocol family (https://en.wikipedia.org/wiki/Reliable_Datagram_Sockets and - https://oss.oracle.com/projects/rds/). + `https://oss.oracle.com/projects/rds <https://web.archive.org/web/20130115155505/https://oss.oracle.com/projects/rds/>`__). * The :class:`~socket.socket` class now supports the ``PF_SYSTEM`` protocol family on OS X. (Contributed by Michael Goderbauer in :issue:`13777`.) diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index f9cceecbcbb9..fb64135e1ee3 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -425,7 +425,7 @@ are declared in the annotations:: While these annotations are available at runtime through the usual :attr:`__annotations__` attribute, *no automatic type checking happens at runtime*. Instead, it is assumed that a separate off-line type checker -(e.g. `mypy <http://mypy-lang.org>`_) will be used for on-demand +(e.g. `mypy <https://mypy-lang.org>`_) will be used for on-demand source code analysis. The type system supports unions, generic types, and a special type @@ -2212,7 +2212,7 @@ for details.) The :c:member:`PyTypeObject.tp_finalize` slot is now part of the stable ABI. Windows builds now require Microsoft Visual C++ 14.0, which -is available as part of `Visual Studio 2015 <https://www.visualstudio.com/>`_. +is available as part of `Visual Studio 2015 <https://visualstudio.microsoft.com/en/vs/older-downloads/#visual-studio-2015-and-other-products>`_. Extension modules now include a platform information tag in their filename on some platforms (the tag is optional, and CPython will import extensions without diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index f138fa5c0e9f..e303e6cba966 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -238,7 +238,7 @@ and the ``__annotations__`` attribute. and Guido van Rossum. Implemented by Ivan Levkivskyi. Tools that use or will use the new syntax: - `mypy <http://www.mypy-lang.org/>`_, + `mypy <https://www.mypy-lang.org/>`_, `pytype <https://github.com/google/pytype>`_, PyCharm, etc. diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 4e2dbe3b539f..e99a9f7634c5 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2226,7 +2226,7 @@ The benchmarks were measured on an `Intel? Core? i7-4960HQ processor <https://ark.intel.com/content/www/us/en/ark/products/76088/intel-core-i7-4960hq-processor-6m-cache-up-to-3-80-ghz.html>`_ running the macOS 64-bit builds found at -`python.org <https://www.python.org/downloads/mac-osx/>`_. +`python.org <https://www.python.org/downloads/macos/>`_. The benchmark script displays timings in nanoseconds. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index e974ee3a3f73..fd86db963023 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -849,7 +849,7 @@ in nanoseconds. The benchmarks were measured on an `Intel? Core? i7-4960HQ processor <https://ark.intel.com/content/www/us/en/ark/products/76088/intel-core-i7-4960hq-processor-6m-cache-up-to-3-80-ghz.html>`_ running the macOS 64-bit builds found at -`python.org <https://www.python.org/downloads/mac-osx/>`_. +`python.org <https://www.python.org/downloads/macos/>`_. Deprecated diff --git a/Misc/NEWS.d/3.7.0a1.rst b/Misc/NEWS.d/3.7.0a1.rst index e99c45ec7fda..24a1c4c83e64 100644 --- a/Misc/NEWS.d/3.7.0a1.rst +++ b/Misc/NEWS.d/3.7.0a1.rst @@ -6255,7 +6255,7 @@ Fix python-gdb.py didn't support new dict implementation. .. section: Tools/Demos The pybench and pystone microbenchmark have been removed from Tools. Please -use the new Python benchmark suite https://github.com/python/performance +use the new Python benchmark suite https://github.com/python/pyperformance which is more reliable and includes a portable version of pybench working on Python 2 and Python 3. From webhook-mailer at python.org Tue May 2 11:05:49 2023 From: webhook-mailer at python.org (corona10) Date: Tue, 02 May 2023 15:05:49 -0000 Subject: [Python-checkins] gh-84436: Add integration C API tests for immortal objects (gh-103962) Message-ID: <mailman.106.1683039950.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d81ca7ec029ba05084751c8df64292bb48f4f30f commit: d81ca7ec029ba05084751c8df64292bb48f4f30f branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-03T00:05:30+09:00 summary: gh-84436: Add integration C API tests for immortal objects (gh-103962) files: A Lib/test/test_capi/test_immortal.py A Modules/_testcapi/immortal.c M Modules/Setup.stdlib.in M Modules/_testcapi/parts.h M Modules/_testcapimodule.c M PCbuild/_testcapi.vcxproj diff --git a/Lib/test/test_capi/test_immortal.py b/Lib/test/test_capi/test_immortal.py new file mode 100644 index 000000000000..ef5d32b7f019 --- /dev/null +++ b/Lib/test/test_capi/test_immortal.py @@ -0,0 +1,16 @@ +import unittest +from test.support import import_helper + +_testcapi = import_helper.import_module('_testcapi') + + +class TestCAPI(unittest.TestCase): + def test_immortal_builtins(self): + _testcapi.test_immortal_builtins() + + def test_immortal_small_ints(self): + _testcapi.test_immortal_small_ints() + + +if __name__ == "__main__": + unittest.main() diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index fe1b9f8f5380..a90c1e96ef02 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE at _xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE at _testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE at _testinternalcapi _testinternalcapi.c - at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c + at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c _testcapi/immortal.c @MODULE__TESTCLINIC_TRUE at _testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/immortal.c b/Modules/_testcapi/immortal.c new file mode 100644 index 000000000000..10e1733d08a9 --- /dev/null +++ b/Modules/_testcapi/immortal.c @@ -0,0 +1,47 @@ +#include "parts.h" + +int verify_immortality(PyObject *object) +{ + assert(_Py_IsImmortal(object)); + Py_ssize_t old_count = Py_REFCNT(object); + for (int j = 0; j < 10000; j++) { + Py_DECREF(object); + } + Py_ssize_t current_count = Py_REFCNT(object); + return old_count == current_count; +} + +static PyObject * +test_immortal_builtins(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *objects[] = {Py_True, Py_False, Py_None, Py_Ellipsis}; + Py_ssize_t n = Py_ARRAY_LENGTH(objects); + for (Py_ssize_t i = 0; i < n; i++) { + assert(verify_immortality(objects[i])); + } + Py_RETURN_NONE; +} + +static PyObject * +test_immortal_small_ints(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + for (int i = -5; i <= 256; i++) { + assert(verify_immortality(PyLong_FromLong(i))); + } + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_immortal_builtins", test_immortal_builtins, METH_NOARGS}, + {"test_immortal_small_ints", test_immortal_small_ints, METH_NOARGS}, + {NULL}, +}; + +int +_PyTestCapi_Init_Immortal(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + return 0; +} diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index 60ec81dad2ba..4d2d6832a827 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -39,6 +39,7 @@ int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module); +int _PyTestCapi_Init_Immortal(PyObject *module); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index a5d23b1b3d50..30b8b6c6b3a8 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4313,6 +4313,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_PyOS(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Immortal(m) < 0) { + return NULL; + } #ifndef LIMITED_API_AVAILABLE PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False); diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 439cd687fda6..21941247eb96 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -110,6 +110,7 @@ <ClCompile Include="..\Modules\_testcapi\exceptions.c" /> <ClCompile Include="..\Modules\_testcapi\code.c" /> <ClCompile Include="..\Modules\_testcapi\pyos.c" /> + <ClCompile Include="..\Modules\_testcapi\immortal.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc" /> From webhook-mailer at python.org Tue May 2 14:08:27 2023 From: webhook-mailer at python.org (barneygale) Date: Tue, 02 May 2023 18:08:27 -0000 Subject: [Python-checkins] GH-103525: Improve exception message from `pathlib.PurePath()` (GH-103526) Message-ID: <mailman.107.1683050909.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8611e7bf5ceace998fefcbf26ab1c5d5bc8a0e2a commit: 8611e7bf5ceace998fefcbf26ab1c5d5bc8a0e2a branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-02T19:08:19+01:00 summary: GH-103525: Improve exception message from `pathlib.PurePath()` (GH-103526) Check that arguments are strings before calling `os.path.join()`. Also improve performance of `PurePath(PurePath(...))` while we're in the area: we now use the *unnormalized* string path of such arguments. Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: A Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index f43f01ef41a9..8eb08949fa9b 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -300,18 +300,27 @@ def __reduce__(self): return (self.__class__, self.parts) def __init__(self, *args): - if not args: - path = '' - elif len(args) == 1: - path = os.fspath(args[0]) + paths = [] + for arg in args: + if isinstance(arg, PurePath): + path = arg._raw_path + else: + try: + path = os.fspath(arg) + except TypeError: + path = arg + if not isinstance(path, str): + raise TypeError( + "argument should be a str or an os.PathLike " + "object where __fspath__ returns a str, " + f"not {type(path).__name__!r}") + paths.append(path) + if len(paths) == 0: + self._raw_path = '' + elif len(paths) == 1: + self._raw_path = paths[0] else: - path = self._flavour.join(*args) - if not isinstance(path, str): - raise TypeError( - "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 + self._raw_path = self._flavour.join(*paths) @classmethod def _parse_path(cls, path): @@ -620,7 +629,7 @@ def joinpath(self, *args): paths) or a totally different path (if one of the arguments is anchored). """ - return self.__class__(self._raw_path, *args) + return self.__class__(self, *args) def __truediv__(self, key): try: @@ -630,7 +639,7 @@ def __truediv__(self, key): def __rtruediv__(self, key): try: - return type(self)(key, self._raw_path) + return type(self)(key, self) except TypeError: return NotImplemented @@ -864,7 +873,7 @@ def absolute(self): cwd = self._flavour.abspath(self.drive) else: cwd = os.getcwd() - return type(self)(cwd, self._raw_path) + return type(self)(cwd, self) def resolve(self, strict=False): """ diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 76cfadeedcea..8b5b61a818bb 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -81,9 +81,9 @@ def test_bytes(self): r"where __fspath__ returns a str, not 'bytes'") with self.assertRaisesRegex(TypeError, message): P(b'a') - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, message): P(b'a', 'b') - with self.assertRaises(TypeError): + with self.assertRaisesRegex(TypeError, message): P('a', b'b') with self.assertRaises(TypeError): P('a').joinpath(b'b') diff --git a/Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst b/Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst new file mode 100644 index 000000000000..1414cb07dd91 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst @@ -0,0 +1,2 @@ +Fix misleading exception message when mixed ``str`` and ``bytes`` arguments +are supplied to :class:`pathlib.PurePath` and :class:`~pathlib.Path`. From webhook-mailer at python.org Tue May 2 14:13:54 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 02 May 2023 18:13:54 -0000 Subject: [Python-checkins] gh-65022: Fix description of tuple return value in copyreg (#103892) Message-ID: <mailman.108.1683051235.13550.python-checkins@python.org> https://github.com/python/cpython/commit/587f2f018051049cf5d9de3e12ed5aa7644404dc commit: 587f2f018051049cf5d9de3e12ed5aa7644404dc branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-02T11:13:47-07:00 summary: gh-65022: Fix description of tuple return value in copyreg (#103892) files: M Doc/library/copyreg.rst diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index 2107215c0c19..afc3e66f0bf7 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -29,7 +29,7 @@ Such constructors may be factory functions or class instances. Declares that *function* should be used as a "reduction" function for objects of type *type*. *function* must return either a string or a tuple - containing two or five elements. See the :attr:`~pickle.Pickler.dispatch_table` + containing between two and six elements. See the :attr:`~pickle.Pickler.dispatch_table` for more details on the interface of *function*. The *constructor_ob* parameter is a legacy feature and is now ignored, but if From webhook-mailer at python.org Tue May 2 14:18:49 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 02 May 2023 18:18:49 -0000 Subject: [Python-checkins] [3.11] gh-65022: Fix description of tuple return value in copyreg (GH-103892) (#104098) Message-ID: <mailman.109.1683051531.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f9231a09be4105281c8063a535e2f42db5a38307 commit: f9231a09be4105281c8063a535e2f42db5a38307 branch: 3.11 author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-02T11:18:41-07:00 summary: [3.11] gh-65022: Fix description of tuple return value in copyreg (GH-103892) (#104098) (cherry picked from commit 587f2f018051049cf5d9de3e12ed5aa7644404dc) files: M Doc/library/copyreg.rst diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index 866b180f4bc3..afc3e66f0bf7 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -28,8 +28,8 @@ Such constructors may be factory functions or class instances. .. function:: pickle(type, function, constructor_ob=None) Declares that *function* should be used as a "reduction" function for objects - of type *type*. *function* should return either a string or a tuple - containing two or three elements. See the :attr:`~pickle.Pickler.dispatch_table` + of type *type*. *function* must return either a string or a tuple + containing between two and six elements. See the :attr:`~pickle.Pickler.dispatch_table` for more details on the interface of *function*. The *constructor_ob* parameter is a legacy feature and is now ignored, but if From webhook-mailer at python.org Tue May 2 14:24:09 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 02 May 2023 18:24:09 -0000 Subject: [Python-checkins] [3.11] gh-103590: do not wrap a single exception raised from a try-except* (#104094) Message-ID: <mailman.110.1683051850.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5386730cdd3f2da88e485220dc9fb606f5082430 commit: 5386730cdd3f2da88e485220dc9fb606f5082430 branch: 3.11 author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-02T19:24:02+01:00 summary: [3.11] gh-103590: do not wrap a single exception raised from a try-except* (#104094) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst M Doc/reference/compound_stmts.rst M Lib/test/test_except_star.py M Objects/exceptions.c diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index f0a8936c35bf..54228b8a4e60 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -365,6 +365,10 @@ Any remaining exceptions that were not handled by any :keyword:`!except*` clause are re-raised at the end, combined into an exception group along with all exceptions that were raised from within :keyword:`!except*` clauses. +From version 3.11.4, when the entire :exc:`ExceptionGroup` is handled and +only one exception is raised from an :keyword:`!except*` clause, this +exception is no longer wrapped to form a new :exc:`ExceptionGroup`. + If the raised exception is not an exception group and its type matches one of the :keyword:`!except*` clauses, it is caught and wrapped by an exception group with an empty message string. :: diff --git a/Lib/test/test_except_star.py b/Lib/test/test_except_star.py index c5167c5bba38..6d6f6043b83b 100644 --- a/Lib/test/test_except_star.py +++ b/Lib/test/test_except_star.py @@ -636,18 +636,17 @@ def test_raise_handle_all_raise_one_named(self): raise orig except* (TypeError, ValueError) as e: raise SyntaxError(3) - except BaseException as e: + except SyntaxError as e: exc = e - self.assertExceptionIsLike( - exc, ExceptionGroup("", [SyntaxError(3)])) + self.assertExceptionIsLike(exc, SyntaxError(3)) self.assertExceptionIsLike( - exc.exceptions[0].__context__, + exc.__context__, ExceptionGroup("eg", [TypeError(1), ValueError(2)])) self.assertMetadataNotEqual(orig, exc) - self.assertMetadataEqual(orig, exc.exceptions[0].__context__) + self.assertMetadataEqual(orig, exc.__context__) def test_raise_handle_all_raise_one_unnamed(self): orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) @@ -656,18 +655,17 @@ def test_raise_handle_all_raise_one_unnamed(self): raise orig except* (TypeError, ValueError) as e: raise SyntaxError(3) - except ExceptionGroup as e: + except SyntaxError as e: exc = e - self.assertExceptionIsLike( - exc, ExceptionGroup("", [SyntaxError(3)])) + self.assertExceptionIsLike(exc, SyntaxError(3)) self.assertExceptionIsLike( - exc.exceptions[0].__context__, + exc.__context__, ExceptionGroup("eg", [TypeError(1), ValueError(2)])) self.assertMetadataNotEqual(orig, exc) - self.assertMetadataEqual(orig, exc.exceptions[0].__context__) + self.assertMetadataEqual(orig, exc.__context__) def test_raise_handle_all_raise_two_named(self): orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) @@ -791,23 +789,22 @@ def test_raise_handle_all_raise_one_named(self): raise orig except* (TypeError, ValueError) as e: raise SyntaxError(3) from e - except BaseException as e: + except SyntaxError as e: exc = e - self.assertExceptionIsLike( - exc, ExceptionGroup("", [SyntaxError(3)])) + self.assertExceptionIsLike(exc, SyntaxError(3)) self.assertExceptionIsLike( - exc.exceptions[0].__context__, + exc.__context__, ExceptionGroup("eg", [TypeError(1), ValueError(2)])) self.assertExceptionIsLike( - exc.exceptions[0].__cause__, + exc.__cause__, ExceptionGroup("eg", [TypeError(1), ValueError(2)])) self.assertMetadataNotEqual(orig, exc) - self.assertMetadataEqual(orig, exc.exceptions[0].__context__) - self.assertMetadataEqual(orig, exc.exceptions[0].__cause__) + self.assertMetadataEqual(orig, exc.__context__) + self.assertMetadataEqual(orig, exc.__cause__) def test_raise_handle_all_raise_one_unnamed(self): orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) @@ -817,23 +814,22 @@ def test_raise_handle_all_raise_one_unnamed(self): except* (TypeError, ValueError) as e: e = sys.exception() raise SyntaxError(3) from e - except ExceptionGroup as e: + except SyntaxError as e: exc = e - self.assertExceptionIsLike( - exc, ExceptionGroup("", [SyntaxError(3)])) + self.assertExceptionIsLike(exc, SyntaxError(3)) self.assertExceptionIsLike( - exc.exceptions[0].__context__, + exc.__context__, ExceptionGroup("eg", [TypeError(1), ValueError(2)])) self.assertExceptionIsLike( - exc.exceptions[0].__cause__, + exc.__cause__, ExceptionGroup("eg", [TypeError(1), ValueError(2)])) self.assertMetadataNotEqual(orig, exc) - self.assertMetadataEqual(orig, exc.exceptions[0].__context__) - self.assertMetadataEqual(orig, exc.exceptions[0].__cause__) + self.assertMetadataEqual(orig, exc.__context__) + self.assertMetadataEqual(orig, exc.__cause__) def test_raise_handle_all_raise_two_named(self): orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst new file mode 100644 index 000000000000..af733a8207a2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst @@ -0,0 +1 @@ +Do not wrap a single exception raised from a ``try-except*`` construct in an :exc:`ExceptionGroup`. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 4fba9b0a6248..a95b75205b87 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1423,7 +1423,12 @@ _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs) if (res < 0) { goto done; } - result = _PyExc_CreateExceptionGroup("", raised_list); + if (PyList_GET_SIZE(raised_list) > 1) { + result = _PyExc_CreateExceptionGroup("", raised_list); + } + else { + result = Py_NewRef(PyList_GetItem(raised_list, 0)); + } if (result == NULL) { goto done; } From webhook-mailer at python.org Tue May 2 16:13:39 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 02 May 2023 20:13:39 -0000 Subject: [Python-checkins] gh-103822: [Calendar] change return value to enum for day and month APIs (GH-103827) Message-ID: <mailman.111.1683058420.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1f5384434dce013b5dcf7e7ea3ec5312d13bba72 commit: 1f5384434dce013b5dcf7e7ea3ec5312d13bba72 branch: main author: Prince Roshan <princekrroshan01 at gmail.com> committer: ethanfurman <ethan at stoneleaf.us> date: 2023-05-02T13:13:31-07:00 summary: gh-103822: [Calendar] change return value to enum for day and month APIs (GH-103827) files: A Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst M Lib/calendar.py diff --git a/Lib/calendar.py b/Lib/calendar.py index bbd4fea3b88c..ea56f12ccc41 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -83,7 +83,6 @@ class Day(IntEnum): SUNDAY = 6 - # Number of days per month (except for February in leap years) mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] @@ -156,7 +155,7 @@ def weekday(year, month, day): """Return weekday (0-6 ~ Mon-Sun) for year, month (1-12), day (1-31).""" if not datetime.MINYEAR <= year <= datetime.MAXYEAR: year = 2000 + year % 400 - return datetime.date(year, month, day).weekday() + return Day(datetime.date(year, month, day).weekday()) def monthrange(year, month): diff --git a/Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst b/Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst new file mode 100644 index 000000000000..3daf9cc09380 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst @@ -0,0 +1 @@ +Update the return type of ``weekday`` to the newly added Day attribute From webhook-mailer at python.org Tue May 2 17:51:25 2023 From: webhook-mailer at python.org (barneygale) Date: Tue, 02 May 2023 21:51:25 -0000 Subject: [Python-checkins] GH-104104: Optimize `pathlib.Path.glob()` by avoiding repeated calls to `os.path.normcase()` (GH-104105) Message-ID: <mailman.112.1683064286.13550.python-checkins@python.org> https://github.com/python/cpython/commit/47770a1e91d096fd1c689eb0c78b0f9e76b43639 commit: 47770a1e91d096fd1c689eb0c78b0f9e76b43639 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-02T22:51:18+01:00 summary: GH-104104: Optimize `pathlib.Path.glob()` by avoiding repeated calls to `os.path.normcase()` (GH-104105) Use `re.IGNORECASE` to implement case-insensitive matching. This restores behaviour from before GH-31691. files: A Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst M Lib/pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 8eb08949fa9b..61e7f3e4430c 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -59,6 +59,9 @@ def _is_wildcard_pattern(pat): # be looked up directly as a file. return "*" in pat or "?" in pat or "[" in pat +def _is_case_sensitive(flavour): + return flavour.normcase('Aa') == 'Aa' + # # Globbing helpers # @@ -100,15 +103,14 @@ def select_from(self, parent_path): is_dir = path_cls.is_dir exists = path_cls.exists scandir = path_cls._scandir - normcase = path_cls._flavour.normcase if not is_dir(parent_path): return iter([]) - return self._select_from(parent_path, is_dir, exists, scandir, normcase) + return self._select_from(parent_path, is_dir, exists, scandir) class _TerminatingSelector: - def _select_from(self, parent_path, is_dir, exists, scandir, normcase): + def _select_from(self, parent_path, is_dir, exists, scandir): yield parent_path @@ -118,11 +120,11 @@ def __init__(self, name, child_parts, flavour): self.name = name _Selector.__init__(self, child_parts, flavour) - def _select_from(self, parent_path, is_dir, exists, scandir, normcase): + def _select_from(self, parent_path, is_dir, exists, scandir): try: path = parent_path._make_child_relpath(self.name) if (is_dir if self.dironly else exists)(path): - for p in self.successor._select_from(path, is_dir, exists, scandir, normcase): + for p in self.successor._select_from(path, is_dir, exists, scandir): yield p except PermissionError: return @@ -131,10 +133,11 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase): class _WildcardSelector(_Selector): def __init__(self, pat, child_parts, flavour): - self.match = re.compile(fnmatch.translate(flavour.normcase(pat))).fullmatch + flags = re.NOFLAG if _is_case_sensitive(flavour) else re.IGNORECASE + self.match = re.compile(fnmatch.translate(pat), flags=flags).fullmatch _Selector.__init__(self, child_parts, flavour) - def _select_from(self, parent_path, is_dir, exists, scandir, normcase): + def _select_from(self, parent_path, is_dir, exists, scandir): try: # We must close the scandir() object before proceeding to # avoid exhausting file descriptors when globbing deep trees. @@ -153,9 +156,9 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase): raise continue name = entry.name - if self.match(normcase(name)): + if self.match(name): path = parent_path._make_child_relpath(name) - for p in self.successor._select_from(path, is_dir, exists, scandir, normcase): + for p in self.successor._select_from(path, is_dir, exists, scandir): yield p except PermissionError: return @@ -187,13 +190,13 @@ def _iterate_directories(self, parent_path, is_dir, scandir): except PermissionError: return - def _select_from(self, parent_path, is_dir, exists, scandir, normcase): + def _select_from(self, parent_path, is_dir, exists, scandir): try: yielded = set() try: successor_select = self.successor._select_from for starting_point in self._iterate_directories(parent_path, is_dir, scandir): - for p in successor_select(starting_point, is_dir, exists, scandir, normcase): + for p in successor_select(starting_point, is_dir, exists, scandir): if p not in yielded: yield p yielded.add(p) diff --git a/Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst b/Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst new file mode 100644 index 000000000000..935a0e2a2bff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst @@ -0,0 +1,2 @@ +Improve performance of :meth:`pathlib.Path.glob` by using +:data:`re.IGNORECASE` to implement case-insensitive matching. From webhook-mailer at python.org Tue May 2 19:16:34 2023 From: webhook-mailer at python.org (barneygale) Date: Tue, 02 May 2023 23:16:34 -0000 Subject: [Python-checkins] GH-104102: Optimize `pathlib.Path.glob()` handling of `../` pattern segments (GH-104103) Message-ID: <mailman.113.1683069395.13550.python-checkins@python.org> https://github.com/python/cpython/commit/65a49c6553a27cc36eebb4b79f409c3cb4450d8c commit: 65a49c6553a27cc36eebb4b79f409c3cb4450d8c branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-02T23:16:04Z summary: GH-104102: Optimize `pathlib.Path.glob()` handling of `../` pattern segments (GH-104103) These segments do not require a `stat()` call, as the selector's `_select_from()` method is called after we've established that the parent is a directory. files: A Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 61e7f3e4430c..c69089f4e1bc 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -74,6 +74,8 @@ def _make_selector(pattern_parts, flavour): return _TerminatingSelector() if pat == '**': cls = _RecursiveWildcardSelector + elif pat == '..': + cls = _ParentSelector elif '**' in pat: raise ValueError("Invalid pattern: '**' can only be an entire path component") elif _is_wildcard_pattern(pat): @@ -114,6 +116,16 @@ def _select_from(self, parent_path, is_dir, exists, scandir): yield parent_path +class _ParentSelector(_Selector): + def __init__(self, name, child_parts, flavour): + _Selector.__init__(self, child_parts, flavour) + + def _select_from(self, parent_path, is_dir, exists, scandir): + path = parent_path._make_child_relpath('..') + for p in self.successor._select_from(path, is_dir, exists, scandir): + yield p + + class _PreciseSelector(_Selector): def __init__(self, name, child_parts, flavour): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 8b5b61a818bb..9902b7242205 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1892,8 +1892,13 @@ def test_glob_dotdot(self): P = self.cls p = P(BASE) self.assertEqual(set(p.glob("..")), { P(BASE, "..") }) + self.assertEqual(set(p.glob("../..")), { P(BASE, "..", "..") }) + self.assertEqual(set(p.glob("dirA/..")), { P(BASE, "dirA", "..") }) self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") }) + self.assertEqual(set(p.glob("dirA/../file*/..")), set()) self.assertEqual(set(p.glob("../xyzzy")), set()) + self.assertEqual(set(p.glob("xyzzy/..")), set()) + self.assertEqual(set(p.glob("/".join([".."] * 50))), { P(BASE, *[".."] * 50)}) @os_helper.skip_unless_symlink def test_glob_permissions(self): diff --git a/Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst b/Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst new file mode 100644 index 000000000000..7101de908a50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst @@ -0,0 +1,2 @@ +Improve performance of :meth:`pathlib.Path.glob` when evaluating patterns +that contain ``'../'`` segments. From webhook-mailer at python.org Tue May 2 22:00:25 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 03 May 2023 02:00:25 -0000 Subject: [Python-checkins] GH-103963: Make dis display names of args for intrinsics opcodes (#104029) Message-ID: <mailman.114.1683079225.13550.python-checkins@python.org> https://github.com/python/cpython/commit/872cbc613245db7a1fc5e6656ed0135d2e115f50 commit: 872cbc613245db7a1fc5e6656ed0135d2e115f50 branch: main author: Juhi Chandalia <jkchandalia at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-02T19:00:17-07:00 summary: GH-103963: Make dis display names of args for intrinsics opcodes (#104029) files: A Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst M Include/internal/pycore_intrinsics.h M Lib/dis.py M Lib/opcode.py M Lib/test/test_dis.py M Tools/build/generate_opcode_h.py diff --git a/Include/internal/pycore_intrinsics.h b/Include/internal/pycore_intrinsics.h index 46a52740eb8a..3902059a04b9 100644 --- a/Include/internal/pycore_intrinsics.h +++ b/Include/internal/pycore_intrinsics.h @@ -1,26 +1,24 @@ +// Auto-generated by Tools/build/generate_opcode_h.py from Lib/opcode.py /* Unary Functions: */ +#define INTRINSIC_1_INVALID 0 +#define INTRINSIC_PRINT 1 +#define INTRINSIC_IMPORT_STAR 2 +#define INTRINSIC_STOPITERATION_ERROR 3 +#define INTRINSIC_ASYNC_GEN_WRAP 4 +#define INTRINSIC_UNARY_POSITIVE 5 +#define INTRINSIC_LIST_TO_TUPLE 6 -#define INTRINSIC_PRINT 1 -#define INTRINSIC_IMPORT_STAR 2 -#define INTRINSIC_STOPITERATION_ERROR 3 -#define INTRINSIC_ASYNC_GEN_WRAP 4 -#define INTRINSIC_UNARY_POSITIVE 5 -#define INTRINSIC_LIST_TO_TUPLE 6 - -#define MAX_INTRINSIC_1 6 +#define MAX_INTRINSIC_1 6 /* Binary Functions: */ +#define INTRINSIC_2_INVALID 0 +#define INTRINSIC_PREP_RERAISE_STAR 1 -#define INTRINSIC_PREP_RERAISE_STAR 1 - -#define MAX_INTRINSIC_2 1 - +#define MAX_INTRINSIC_2 1 typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value); typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2); - extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[]; extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[]; - diff --git a/Lib/dis.py b/Lib/dis.py index 85c109584bf9..3a8e6ac3bf5a 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -11,6 +11,8 @@ _cache_format, _inline_cache_entries, _nb_ops, + _intrinsic_1_descs, + _intrinsic_2_descs, _specializations, _specialized_instructions, ) @@ -42,6 +44,8 @@ SEND = opmap['SEND'] LOAD_ATTR = opmap['LOAD_ATTR'] LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR'] +CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1'] +CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2'] CACHE = opmap["CACHE"] @@ -506,6 +510,10 @@ def _get_instructions_bytes(code, varname_from_oparg=None, if arg & (1<<i)) elif deop == BINARY_OP: _, argrepr = _nb_ops[arg] + elif deop == CALL_INTRINSIC_1: + argrepr = _intrinsic_1_descs[arg] + elif deop == CALL_INTRINSIC_2: + argrepr = _intrinsic_2_descs[arg] yield Instruction(_all_opname[op], op, arg, argval, argrepr, offset, starts_line, is_jump_target, positions) diff --git a/Lib/opcode.py b/Lib/opcode.py index aef8407948df..ad54bd27fba3 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -306,6 +306,21 @@ def pseudo_op(name, op, real_ops): ("NB_INPLACE_XOR", "^="), ] +_intrinsic_1_descs = [ + "INTRINSIC_1_INVALID", + "INTRINSIC_PRINT", + "INTRINSIC_IMPORT_STAR", + "INTRINSIC_STOPITERATION_ERROR", + "INTRINSIC_ASYNC_GEN_WRAP", + "INTRINSIC_UNARY_POSITIVE", + "INTRINSIC_LIST_TO_TUPLE", +] + +_intrinsic_2_descs = [ + 'INTRINSIC_2_INVALID', + 'INTRINSIC_PREP_RERAISE_STAR', + ] + _specializations = { "BINARY_OP": [ "BINARY_OP_ADD_FLOAT", diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 5262c5c257cb..2f5d67fde861 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -247,6 +247,35 @@ def wrap_func_w_kwargs(): """ % (wrap_func_w_kwargs.__code__.co_firstlineno, wrap_func_w_kwargs.__code__.co_firstlineno + 1) +dis_intrinsic_1_2 = """\ + 0 RESUME 0 + + 1 LOAD_CONST 0 (0) + LOAD_CONST 1 (('*',)) + IMPORT_NAME 0 (math) + CALL_INTRINSIC_1 2 (INTRINSIC_IMPORT_STAR) + POP_TOP + RETURN_CONST 2 (None) +""" + +dis_intrinsic_1_5 = """\ + 0 RESUME 0 + + 1 LOAD_NAME 0 (a) + CALL_INTRINSIC_1 5 (INTRINSIC_UNARY_POSITIVE) + RETURN_VALUE +""" + +dis_intrinsic_1_6 = """\ + 0 RESUME 0 + + 1 BUILD_LIST 0 + LOAD_NAME 0 (a) + LIST_EXTEND 1 + CALL_INTRINSIC_1 6 (INTRINSIC_LIST_TO_TUPLE) + RETURN_VALUE +""" + _BIG_LINENO_FORMAT = """\ 1 RESUME 0 @@ -549,7 +578,7 @@ async def _asyncwith(c): >> COPY 3 POP_EXCEPT RERAISE 1 - >> CALL_INTRINSIC_1 3 + >> CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) RERAISE 1 ExceptionTable: 12 rows @@ -942,6 +971,16 @@ def test_kw_names(self): # Test that value is displayed for KW_NAMES self.do_disassembly_test(wrap_func_w_kwargs, dis_kw_names) + def test_intrinsic_1(self): + # Test that argrepr is displayed for CALL_INTRINSIC_1 + self.do_disassembly_test("from math import *", dis_intrinsic_1_2) + self.do_disassembly_test("+a", dis_intrinsic_1_5) + self.do_disassembly_test("(*a,)", dis_intrinsic_1_6) + + def test_intrinsic_2(self): + self.assertIn("CALL_INTRINSIC_2 1 (INTRINSIC_PREP_RERAISE_STAR)", + self.get_disassembly("try: pass\nexcept* Exception: x")) + def test_big_linenos(self): def func(count): namespace = {} diff --git a/Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst b/Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst new file mode 100644 index 000000000000..cb06ad5d22e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst @@ -0,0 +1 @@ +Make :mod:`dis` display the names of the args for :opcode:`CALL_INTRINSIC_*`. diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 645b9f1de117..adcbaf2b8e08 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -52,6 +52,18 @@ #endif // !Py_INTERNAL_OPCODE_H """ +intrinsic_header = f""" +// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE} + +""".lstrip() + +intrinsic_footer = """ +typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value); +typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2); +extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[]; +extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[]; +""" + DEFINE = "#define {:<38} {:>3}\n" UINT32_MASK = (1<<32)-1 @@ -67,7 +79,9 @@ def write_int_array_from_ops(name, ops, out): assert bits == 0 out.write(f"}};\n") -def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/internal/pycore_opcode.h'): +def main(opcode_py, outfile='Include/opcode.h', + internaloutfile='Include/internal/pycore_opcode.h', + intrinsicoutfile='Include/internal/pycore_intrinsics.h'): opcode = {} if hasattr(tokenize, 'open'): fp = tokenize.open(opcode_py) # Python 3.2+ @@ -107,9 +121,11 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna opname_including_specialized[next_op] = name used[next_op] = True - with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj: + with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj, open( + intrinsicoutfile, "w") as nobj: fobj.write(header) iobj.write(internal_header) + nobj.write(intrinsic_header) for name in opname: if name in opmap: @@ -172,6 +188,22 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna for i, (op, _) in enumerate(opcode["_nb_ops"]): fobj.write(DEFINE.format(op, i)) + nobj.write("/* Unary Functions: */") + nobj.write("\n") + for i, op in enumerate(opcode["_intrinsic_1_descs"]): + nobj.write(DEFINE.format(op, i)) + nobj.write("\n") + nobj.write(DEFINE.format("MAX_INTRINSIC_1", i)) + + nobj.write("\n\n") + nobj.write("/* Binary Functions: */\n") + for i, op in enumerate(opcode["_intrinsic_2_descs"]): + nobj.write(DEFINE.format(op, i)) + nobj.write("\n") + nobj.write(DEFINE.format("MAX_INTRINSIC_2", i)) + + nobj.write(intrinsic_footer) + fobj.write("\n") fobj.write("/* Defined in Lib/opcode.py */\n") fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}") From webhook-mailer at python.org Tue May 2 23:30:10 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 03 May 2023 03:30:10 -0000 Subject: [Python-checkins] gh-94673: More Per-Interpreter Fields for Builtin Static Types (gh-103912) Message-ID: <mailman.115.1683084612.13550.python-checkins@python.org> https://github.com/python/cpython/commit/de64e7561680fdc5358001e9488091e75d4174a3 commit: de64e7561680fdc5358001e9488091e75d4174a3 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-02T21:30:03-06:00 summary: gh-94673: More Per-Interpreter Fields for Builtin Static Types (gh-103912) his involves moving tp_dict, tp_bases, and tp_mro to PyInterpreterState, in the same way we did for tp_subclasses. Those three fields are effectively const for builtin static types (unlike tp_subclasses). In theory we only need to make their values immortal, along with their contents. However, that isn't such a simple proposition. (See gh-103823.) In the meantime the simplest solution is to move the fields into the interpreter. One alternative is to statically allocate the values, but that's its own can of worms. files: M Include/internal/pycore_typeobject.h M Modules/_abc.c M Modules/gcmodule.c M Objects/structseq.c M Objects/typeobject.c diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index f865e51aeba5..6a5ab7e63f85 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -44,6 +44,13 @@ struct type_cache { typedef struct { PyTypeObject *type; + int readying; + int ready; + // XXX tp_dict, tp_bases, and tp_mro can probably be statically + // allocated, instead of dynamically and stored on the interpreter. + PyObject *tp_dict; + PyObject *tp_bases; + PyObject *tp_mro; PyObject *tp_subclasses; /* We never clean up weakrefs for static builtin types since they will effectively never get triggered. However, there diff --git a/Modules/_abc.c b/Modules/_abc.c index 997b618d557a..9694331339aa 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -7,6 +7,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_object.h" // _PyType_GetSubclasses() #include "pycore_runtime.h" // _Py_ID() +#include "pycore_typeobject.h" // _PyType_GetMRO() #include "clinic/_abc.c.h" /*[clinic input] diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 8a4d1a439828..f4d5186ff155 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2174,23 +2174,6 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp) } -static void -gc_fini_untrack(PyGC_Head *list) -{ - PyGC_Head *gc; - for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(list)) { - PyObject *op = FROM_GC(gc); - _PyObject_GC_UNTRACK(op); - // gh-92036: If a deallocator function expect the object to be tracked - // by the GC (ex: func_dealloc()), it can crash if called on an object - // which is no longer tracked by the GC. Leak one strong reference on - // purpose so the object is never deleted and its deallocator is not - // called. - Py_INCREF(op); - } -} - - void _PyGC_Fini(PyInterpreterState *interp) { @@ -2198,17 +2181,9 @@ _PyGC_Fini(PyInterpreterState *interp) Py_CLEAR(gcstate->garbage); Py_CLEAR(gcstate->callbacks); - if (!_Py_IsMainInterpreter(interp)) { - // bpo-46070: Explicitly untrack all objects currently tracked by the - // GC. Otherwise, if an object is used later by another interpreter, - // calling PyObject_GC_UnTrack() on the object crashs if the previous - // or the next object of the PyGC_Head structure became a dangling - // pointer. - for (int i = 0; i < NUM_GENERATIONS; i++) { - PyGC_Head *gen = GEN_HEAD(gcstate, i); - gc_fini_untrack(gen); - } - } + /* We expect that none of this interpreters objects are shared + with other interpreters. + See https://github.com/python/cpython/issues/90228. */ } /* for debugging */ diff --git a/Objects/structseq.c b/Objects/structseq.c index f63660acb639..8b1895957101 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -511,7 +511,6 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, Py_ssize_t n_members = count_members(desc, &n_unnamed_members); PyMemberDef *members = NULL; - int initialized = 1; if ((type->tp_flags & Py_TPFLAGS_READY) == 0) { assert(type->tp_name == NULL); assert(type->tp_members == NULL); @@ -524,7 +523,6 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, initialize_static_fields(type, desc, members, tp_flags); _Py_SetImmortal(type); - initialized = 0; } #ifndef NDEBUG else { @@ -543,13 +541,10 @@ _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp, desc->name); goto error; } - // This should be dropped if tp_dict is made per-interpreter. - if (initialized) { - return 0; - } if (initialize_structseq_dict( - desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) { + desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) + { goto error; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a9d3a69263fb..cf0efe199b28 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -167,29 +167,93 @@ static_builtin_state_clear(PyInterpreterState *interp, PyTypeObject *self) /* end static builtin helpers */ +static inline void +start_readying(PyTypeObject *type) +{ + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = static_builtin_state_get(interp, type); + assert(state != NULL); + assert(!state->readying); + state->readying = 1; + return; + } + assert((type->tp_flags & Py_TPFLAGS_READYING) == 0); + type->tp_flags |= Py_TPFLAGS_READYING; +} + +static inline void +stop_readying(PyTypeObject *type) +{ + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = static_builtin_state_get(interp, type); + assert(state != NULL); + assert(state->readying); + state->readying = 0; + return; + } + assert(type->tp_flags & Py_TPFLAGS_READYING); + type->tp_flags &= ~Py_TPFLAGS_READYING; +} + +static inline int +is_readying(PyTypeObject *type) +{ + if (type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = static_builtin_state_get(interp, type); + assert(state != NULL); + return state->readying; + } + return (type->tp_flags & Py_TPFLAGS_READYING) != 0; +} + + /* accessors for objects stored on PyTypeObject */ static inline PyObject * lookup_tp_dict(PyTypeObject *self) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + return state->tp_dict; + } return self->tp_dict; } PyObject * _PyType_GetDict(PyTypeObject *self) { + /* It returns a borrowed reference. */ return lookup_tp_dict(self); } static inline void set_tp_dict(PyTypeObject *self, PyObject *dict) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + state->tp_dict = dict; + return; + } self->tp_dict = dict; } static inline void clear_tp_dict(PyTypeObject *self) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + Py_CLEAR(state->tp_dict); + return; + } Py_CLEAR(self->tp_dict); } @@ -197,24 +261,45 @@ clear_tp_dict(PyTypeObject *self) static inline PyObject * lookup_tp_bases(PyTypeObject *self) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + return state->tp_bases; + } return self->tp_bases; } PyObject * _PyType_GetBases(PyTypeObject *self) { + /* It returns a borrowed reference. */ return lookup_tp_bases(self); } static inline void set_tp_bases(PyTypeObject *self, PyObject *bases) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + state->tp_bases = bases; + return; + } self->tp_bases = bases; } static inline void clear_tp_bases(PyTypeObject *self) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + Py_CLEAR(state->tp_bases); + return; + } Py_CLEAR(self->tp_bases); } @@ -222,24 +307,45 @@ clear_tp_bases(PyTypeObject *self) static inline PyObject * lookup_tp_mro(PyTypeObject *self) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + return state->tp_mro; + } return self->tp_mro; } PyObject * _PyType_GetMRO(PyTypeObject *self) { + /* It returns a borrowed reference. */ return lookup_tp_mro(self); } static inline void set_tp_mro(PyTypeObject *self, PyObject *mro) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + state->tp_mro = mro; + return; + } self->tp_mro = mro; } static inline void clear_tp_mro(PyTypeObject *self) { + if (self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + static_builtin_state *state = _PyStaticType_GetState(interp, self); + assert(state != NULL); + Py_CLEAR(state->tp_mro); + return; + } Py_CLEAR(self->tp_mro); } @@ -408,7 +514,7 @@ _PyType_CheckConsistency(PyTypeObject *type) CHECK(Py_REFCNT(type) >= 1); CHECK(PyType_Check(type)); - CHECK(!(type->tp_flags & Py_TPFLAGS_READYING)); + CHECK(!is_readying(type)); CHECK(lookup_tp_dict(type) != NULL); if (type->tp_flags & Py_TPFLAGS_HAVE_GC) { @@ -809,7 +915,6 @@ static PyMemberDef type_members[] = { {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY}, {"__dictoffset__", T_PYSSIZET, offsetof(PyTypeObject, tp_dictoffset), READONLY}, - {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY}, {0} }; @@ -1023,7 +1128,21 @@ type_set_abstractmethods(PyTypeObject *type, PyObject *value, void *context) static PyObject * type_get_bases(PyTypeObject *type, void *context) { - return Py_NewRef(lookup_tp_bases(type)); + PyObject *bases = lookup_tp_bases(type); + if (bases == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(bases); +} + +static PyObject * +type_get_mro(PyTypeObject *type, void *context) +{ + PyObject *mro = lookup_tp_mro(type); + if (mro == NULL) { + Py_RETURN_NONE; + } + return Py_NewRef(mro); } static PyTypeObject *best_base(PyObject *); @@ -1402,6 +1521,7 @@ static PyGetSetDef type_getsets[] = { {"__name__", (getter)type_name, (setter)type_set_name, NULL}, {"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL}, {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, + {"__mro__", (getter)type_get_mro, NULL, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL}, {"__abstractmethods__", (getter)type_abstractmethods, (setter)type_set_abstractmethods, NULL}, @@ -4342,7 +4462,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error) /* Look in tp_dict of types in MRO */ PyObject *mro = lookup_tp_mro(type); if (mro == NULL) { - if ((type->tp_flags & Py_TPFLAGS_READYING) == 0) { + if (!is_readying(type)) { if (PyType_Ready(type) < 0) { *error = -1; return NULL; @@ -4692,11 +4812,11 @@ static void clear_static_type_objects(PyInterpreterState *interp, PyTypeObject *type) { if (_Py_IsMainInterpreter(interp)) { - clear_tp_dict(type); - clear_tp_bases(type); - clear_tp_mro(type); Py_CLEAR(type->tp_cache); } + clear_tp_dict(type); + clear_tp_bases(type); + clear_tp_mro(type); clear_static_tp_subclasses(type); } @@ -6684,6 +6804,10 @@ type_ready_pre_checks(PyTypeObject *type) static int type_ready_set_bases(PyTypeObject *type) { + if (lookup_tp_bases(type) != NULL) { + return 0; + } + /* Initialize tp_base (defaults to BaseObject unless that's us) */ PyTypeObject *base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { @@ -6997,7 +7121,7 @@ type_ready_add_subclasses(PyTypeObject *type) // Set tp_new and the "__new__" key in the type dictionary. // Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag. static int -type_ready_set_new(PyTypeObject *type) +type_ready_set_new(PyTypeObject *type, int rerunbuiltin) { PyTypeObject *base = type->tp_base; /* The condition below could use some explanation. @@ -7019,10 +7143,12 @@ type_ready_set_new(PyTypeObject *type) if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) { if (type->tp_new != NULL) { - // If "__new__" key does not exists in the type dictionary, - // set it to tp_new_wrapper(). - if (add_tp_new_wrapper(type) < 0) { - return -1; + if (!rerunbuiltin || base == NULL || type->tp_new != base->tp_new) { + // If "__new__" key does not exists in the type dictionary, + // set it to tp_new_wrapper(). + if (add_tp_new_wrapper(type) < 0) { + return -1; + } } } else { @@ -7096,11 +7222,10 @@ type_ready_post_checks(PyTypeObject *type) static int -type_ready(PyTypeObject *type) +type_ready(PyTypeObject *type, int rerunbuiltin) { - _PyObject_ASSERT((PyObject *)type, - (type->tp_flags & Py_TPFLAGS_READYING) == 0); - type->tp_flags |= Py_TPFLAGS_READYING; + _PyObject_ASSERT((PyObject *)type, !is_readying(type)); + start_readying(type); if (type_ready_pre_checks(type) < 0) { goto error; @@ -7125,17 +7250,19 @@ type_ready(PyTypeObject *type) if (type_ready_mro(type) < 0) { goto error; } - if (type_ready_set_new(type) < 0) { + if (type_ready_set_new(type, rerunbuiltin) < 0) { goto error; } if (type_ready_fill_dict(type) < 0) { goto error; } - if (type_ready_inherit(type) < 0) { - goto error; - } - if (type_ready_preheader(type) < 0) { - goto error; + if (!rerunbuiltin) { + if (type_ready_inherit(type) < 0) { + goto error; + } + if (type_ready_preheader(type) < 0) { + goto error; + } } if (type_ready_set_hash(type) < 0) { goto error; @@ -7143,21 +7270,24 @@ type_ready(PyTypeObject *type) if (type_ready_add_subclasses(type) < 0) { goto error; } - if (type_ready_managed_dict(type) < 0) { - goto error; - } - if (type_ready_post_checks(type) < 0) { - goto error; + if (!rerunbuiltin) { + if (type_ready_managed_dict(type) < 0) { + goto error; + } + if (type_ready_post_checks(type) < 0) { + goto error; + } } /* All done -- set the ready flag */ - type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY; + type->tp_flags = type->tp_flags | Py_TPFLAGS_READY; + stop_readying(type); assert(_PyType_CheckConsistency(type)); return 0; error: - type->tp_flags &= ~Py_TPFLAGS_READYING; + stop_readying(type); return -1; } @@ -7175,7 +7305,7 @@ PyType_Ready(PyTypeObject *type) type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; } - return type_ready(type); + return type_ready(type, 0); } int @@ -7186,35 +7316,26 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_DICT)); assert(!(self->tp_flags & Py_TPFLAGS_MANAGED_WEAKREF)); -#ifndef NDEBUG int ismain = _Py_IsMainInterpreter(interp); -#endif - if (self->tp_flags & Py_TPFLAGS_READY) { + if ((self->tp_flags & Py_TPFLAGS_READY) == 0) { + assert(ismain); + + self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN; + self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; + + assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG); + self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++; + self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; + } + else { assert(!ismain); assert(self->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN); assert(self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG); - - static_builtin_state_init(interp, self); - - /* Per-interpreter tp_subclasses is done lazily. - Otherwise we would initialize it here. */ - - assert(_PyType_CheckConsistency(self)); - return 0; } - assert(ismain); - - self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN; - self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; - - assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG); - self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++; - self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; - static_builtin_state_init(interp, self); - int res = type_ready(self); + int res = type_ready(self, !ismain); if (res < 0) { static_builtin_state_clear(interp, self); } From webhook-mailer at python.org Tue May 2 23:40:07 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 03 May 2023 03:40:07 -0000 Subject: [Python-checkins] gh-104109: Expose Py_NewInterpreterFromConfig() in the Public C-API (gh-104110) Message-ID: <mailman.116.1683085208.13550.python-checkins@python.org> https://github.com/python/cpython/commit/292076a9aa29aba1023340a0d24252a7b27a454e commit: 292076a9aa29aba1023340a0d24252a7b27a454e branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-02T21:40:00-06:00 summary: gh-104109: Expose Py_NewInterpreterFromConfig() in the Public C-API (gh-104110) We also expose PyInterpreterConfig. This is part of the PEP 684 (per-interpreter GIL) implementation. We will add docs as soon as we can. FYI, I'm adding the new config field for per-interpreter GIL in gh-99114. files: A Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst M Include/cpython/initconfig.h M Include/cpython/pylifecycle.h M Modules/_testcapimodule.c M Modules/_xxsubinterpretersmodule.c M Python/pylifecycle.c diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index 79c1023baa9a..9c1783d272f1 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -252,7 +252,7 @@ typedef struct { int allow_threads; int allow_daemon_threads; int check_multi_interp_extensions; -} _PyInterpreterConfig; +} PyInterpreterConfig; #define _PyInterpreterConfig_INIT \ { \ diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index 79d55711319e..08569ee683ce 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -62,9 +62,9 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); -PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig( +PyAPI_FUNC(PyStatus) Py_NewInterpreterFromConfig( PyThreadState **tstate_p, - const _PyInterpreterConfig *config); + const PyInterpreterConfig *config); typedef void (*atexit_datacallbackfunc)(void *); PyAPI_FUNC(int) _Py_AtExit( diff --git a/Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst b/Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst new file mode 100644 index 000000000000..2ffc0fa81c01 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst @@ -0,0 +1,5 @@ +We've added ``Py_NewInterpreterFromConfig()`` and ``PyInterpreterConfig`` to +the public C-API (but not the stable ABI; not yet at least). The new +function may be used to create a new interpreter with various features +configured. The function was added to support PEP 684 (per-interpreter +GIL). diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 30b8b6c6b3a8..47e0ed9be8e7 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1538,7 +1538,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) PyThreadState_Swap(NULL); - const _PyInterpreterConfig config = { + const PyInterpreterConfig config = { .use_main_obmalloc = use_main_obmalloc, .allow_fork = allow_fork, .allow_exec = allow_exec, @@ -1546,7 +1546,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, }; - PyStatus status = _Py_NewInterpreterFromConfig(&substate, &config); + PyStatus status = Py_NewInterpreterFromConfig(&substate, &config); if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 884fb0d31f2b..95273ab278d9 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -513,12 +513,12 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) // Create and initialize the new interpreter. PyThreadState *save_tstate = _PyThreadState_GET(); - const _PyInterpreterConfig config = isolated - ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT - : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; + const PyInterpreterConfig config = isolated + ? (PyInterpreterConfig)_PyInterpreterConfig_INIT + : (PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; // XXX Possible GILState issues? PyThreadState *tstate = NULL; - PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); + PyStatus status = Py_NewInterpreterFromConfig(&tstate, &config); PyThreadState_Swap(save_tstate); if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index b8a115236900..b9add89b9c6c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -546,7 +546,8 @@ pycore_init_runtime(_PyRuntimeState *runtime, static PyStatus -init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *config) +init_interp_settings(PyInterpreterState *interp, + const PyInterpreterConfig *config) { assert(interp->feature_flags == 0); @@ -631,7 +632,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } - const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; + const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; status = init_interp_settings(interp, &config); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1991,7 +1992,7 @@ Py_Finalize(void) */ static PyStatus -new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) +new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) { PyStatus status; @@ -2079,8 +2080,8 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) } PyStatus -_Py_NewInterpreterFromConfig(PyThreadState **tstate_p, - const _PyInterpreterConfig *config) +Py_NewInterpreterFromConfig(PyThreadState **tstate_p, + const PyInterpreterConfig *config) { return new_interpreter(tstate_p, config); } @@ -2089,8 +2090,8 @@ PyThreadState * Py_NewInterpreter(void) { PyThreadState *tstate = NULL; - const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; - PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); + const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; + PyStatus status = new_interpreter(&tstate, &config); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } From webhook-mailer at python.org Tue May 2 23:42:07 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 03 May 2023 03:42:07 -0000 Subject: [Python-checkins] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (#104067) Message-ID: <mailman.117.1683085328.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c7c3a60c88de61a79ded9fdaf6bc6a29da4efb9a commit: c7c3a60c88de61a79ded9fdaf6bc6a29da4efb9a branch: main author: Ethan Furman <ethan at stoneleaf.us> committer: gpshead <greg at krypto.org> date: 2023-05-03T03:42:00Z summary: gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (#104067) Do not expose the local server's on-disk location from `SimpleHTTPRequestHandler` when generating a directory index. (unnecessary information disclosure) --------- Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index 971f08046d50..a245ffb30786 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -791,7 +791,7 @@ def list_directory(self, path): displaypath = urllib.parse.unquote(self.path, errors='surrogatepass') except UnicodeDecodeError: - displaypath = urllib.parse.unquote(path) + displaypath = urllib.parse.unquote(self.path) displaypath = html.escape(displaypath, quote=False) enc = sys.getfilesystemencoding() title = f'Directory listing for {displaypath}' diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index cbcf94136ac4..0382b5ec448d 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -418,6 +418,14 @@ def test_undecodable_filename(self): self.check_status_and_reason(response, HTTPStatus.OK, data=os_helper.TESTFN_UNDECODABLE) + def test_undecodable_parameter(self): + # sanity check using a valid parameter + response = self.request(self.base_url + '/?x=123').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + # now the bogus encoding + response = self.request(self.base_url + '/?x=%bb').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. diff --git a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst new file mode 100644 index 000000000000..969deb26bfeb --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst @@ -0,0 +1,2 @@ +Do not expose the local on-disk location in directory indexes +produced by :class:`http.client.SimpleHTTPRequestHandler`. From webhook-mailer at python.org Tue May 2 23:50:17 2023 From: webhook-mailer at python.org (barneygale) Date: Wed, 03 May 2023 03:50:17 -0000 Subject: [Python-checkins] GH-89769: `pathlib.Path.glob()`: do not follow symlinks when checking for precise match (GH-29655) Message-ID: <mailman.118.1683085818.13550.python-checkins@python.org> https://github.com/python/cpython/commit/af886ffa0612124598b5e8174c3b1be0f60eab38 commit: af886ffa0612124598b5e8174c3b1be0f60eab38 branch: main author: andrei kulakov <andrei.avk at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-03T04:50:10+01:00 summary: GH-89769: `pathlib.Path.glob()`: do not follow symlinks when checking for precise match (GH-29655) Co-authored-by: Barney Gale <barney.gale at gmail.com> files: A Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst M Doc/library/pathlib.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 8e91936680fa..4847ac24c775 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -819,9 +819,14 @@ call fails (for example because the path doesn't exist). .. versionchanged:: 3.10 The *follow_symlinks* parameter was added. -.. method:: Path.exists() +.. method:: Path.exists(*, follow_symlinks=True) - Whether the path points to an existing file or directory:: + Return ``True`` if the path points to an existing file or directory. + + This method normally follows symlinks; to check if a symlink exists, add + the argument ``follow_symlinks=False``. + + :: >>> Path('.').exists() True @@ -832,10 +837,8 @@ call fails (for example because the path doesn't exist). >>> Path('nonexistentfile').exists() False - .. note:: - If the path points to a symlink, :meth:`exists` returns whether the - symlink *points to* an existing file or directory. - + .. versionchanged:: 3.12 + The *follow_symlinks* parameter was added. .. method:: Path.expanduser() diff --git a/Lib/pathlib.py b/Lib/pathlib.py index c69089f4e1bc..dee19d1f89ad 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -135,7 +135,8 @@ def __init__(self, name, child_parts, flavour): def _select_from(self, parent_path, is_dir, exists, scandir): try: path = parent_path._make_child_relpath(self.name) - if (is_dir if self.dironly else exists)(path): + follow = is_dir(path) if self.dironly else exists(path, follow_symlinks=False) + if follow: for p in self.successor._select_from(path, is_dir, exists, scandir): yield p except PermissionError: @@ -1122,12 +1123,15 @@ def hardlink_to(self, target): # Convenience functions for querying the stat results - def exists(self): + def exists(self, *, follow_symlinks=True): """ Whether this path exists. + + This method normally follows symlinks; to check whether a symlink exists, + add the argument follow_symlinks=False. """ try: - self.stat() + self.stat(follow_symlinks=follow_symlinks) except OSError as e: if not _ignore_error(e): raise diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 9902b7242205..620d480e37e2 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1700,6 +1700,8 @@ def test_exists(self): self.assertIs(True, (p / 'linkB').exists()) self.assertIs(True, (p / 'linkB' / 'fileB').exists()) self.assertIs(False, (p / 'linkA' / 'bah').exists()) + self.assertIs(False, (p / 'brokenLink').exists()) + self.assertIs(True, (p / 'brokenLink').exists(follow_symlinks=False)) self.assertIs(False, (p / 'foo').exists()) self.assertIs(False, P('/xyzzy').exists()) self.assertIs(False, P(BASE + '\udfff').exists()) @@ -1806,6 +1808,8 @@ def _check(glob, expected): _check(p.glob("*/fileB"), ['dirB/fileB']) else: _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) + if os_helper.can_symlink(): + _check(p.glob("brokenLink"), ['brokenLink']) if not os_helper.can_symlink(): _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"]) diff --git a/Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst b/Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst new file mode 100644 index 000000000000..531f47292200 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst @@ -0,0 +1,5 @@ +Fixed the bug in :meth:`pathlib.Path.glob` -- previously a dangling symlink +would not be found by this method when the pattern is an exact match, but +would be found when the pattern contains a wildcard or the recursive +wildcard (``**``). With this change, a dangling symlink will be found in +both cases. From webhook-mailer at python.org Wed May 3 00:27:13 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 03 May 2023 04:27:13 -0000 Subject: [Python-checkins] [3.11] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104123) Message-ID: <mailman.119.1683088034.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4536b2ec18d0e58e8e4b3167643966c8438775af commit: 4536b2ec18d0e58e8e4b3167643966c8438775af branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-03T04:27:04Z summary: [3.11] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104123) gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) Do not expose the local server's on-disk location from `SimpleHTTPRequestHandler` when generating a directory index. (unnecessary information disclosure) --------- (cherry picked from commit c7c3a60c88de61a79ded9fdaf6bc6a29da4efb9a) Co-authored-by: Ethan Furman <ethan at stoneleaf.us> Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index eef7cbb3ec75..3a6ac977693d 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -790,7 +790,7 @@ def list_directory(self, path): displaypath = urllib.parse.unquote(self.path, errors='surrogatepass') except UnicodeDecodeError: - displaypath = urllib.parse.unquote(path) + displaypath = urllib.parse.unquote(self.path) displaypath = html.escape(displaypath, quote=False) enc = sys.getfilesystemencoding() title = f'Directory listing for {displaypath}' diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index cbcf94136ac4..0382b5ec448d 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -418,6 +418,14 @@ def test_undecodable_filename(self): self.check_status_and_reason(response, HTTPStatus.OK, data=os_helper.TESTFN_UNDECODABLE) + def test_undecodable_parameter(self): + # sanity check using a valid parameter + response = self.request(self.base_url + '/?x=123').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + # now the bogus encoding + response = self.request(self.base_url + '/?x=%bb').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. diff --git a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst new file mode 100644 index 000000000000..969deb26bfeb --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst @@ -0,0 +1,2 @@ +Do not expose the local on-disk location in directory indexes +produced by :class:`http.client.SimpleHTTPRequestHandler`. From webhook-mailer at python.org Wed May 3 01:09:11 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 03 May 2023 05:09:11 -0000 Subject: [Python-checkins] gh-101100: Fix Sphinx warnings in `curses` and `curses.ascii` modules (#103457) Message-ID: <mailman.120.1683090552.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5b05b013ff13032ffc4db07108a507c08b3a604d commit: 5b05b013ff13032ffc4db07108a507c08b3a604d branch: main author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-02T23:09:04-06:00 summary: gh-101100: Fix Sphinx warnings in `curses` and `curses.ascii` modules (#103457) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/howto/curses.rst M Doc/library/curses.ascii.rst M Doc/library/curses.rst diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst index 83d80471ffc8..a3068d86d85b 100644 --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -4,6 +4,8 @@ Curses Programming with Python ********************************** +.. currentmodule:: curses + :Author: A.M. Kuchling, Eric S. Raymond :Release: 2.04 @@ -65,7 +67,7 @@ The Python module is a fairly simple wrapper over the C functions provided by curses; if you're already familiar with curses programming in C, it's really easy to transfer that knowledge to Python. The biggest difference is that the Python interface makes things simpler by merging different C functions such as -:c:func:`addstr`, :c:func:`mvaddstr`, and :c:func:`mvwaddstr` into a single +:c:func:`!addstr`, :c:func:`!mvaddstr`, and :c:func:`!mvwaddstr` into a single :meth:`~curses.window.addstr` method. You'll see this covered in more detail later. @@ -82,7 +84,7 @@ Before doing anything, curses must be initialized. This is done by calling the :func:`~curses.initscr` function, which will determine the terminal type, send any required setup codes to the terminal, and create various internal data structures. If successful, -:func:`initscr` returns a window object representing the entire +:func:`!initscr` returns a window object representing the entire screen; this is usually called ``stdscr`` after the name of the corresponding C variable. :: @@ -151,8 +153,8 @@ importing the :func:`curses.wrapper` function and using it like this:: The :func:`~curses.wrapper` function takes a callable object and does the initializations described above, also initializing colors if color -support is present. :func:`wrapper` then runs your provided callable. -Once the callable returns, :func:`wrapper` will restore the original +support is present. :func:`!wrapper` then runs your provided callable. +Once the callable returns, :func:`!wrapper` will restore the original state of the terminal. The callable is called inside a :keyword:`try`...\ :keyword:`except` that catches exceptions, restores the state of the terminal, and then re-raises the exception. Therefore @@ -200,7 +202,7 @@ This is because curses was originally written with slow 300-baud terminal connections in mind; with these terminals, minimizing the time required to redraw the screen was very important. Instead curses accumulates changes to the screen and displays them in the most -efficient manner when you call :meth:`refresh`. For example, if your +efficient manner when you call :meth:`!refresh`. For example, if your program displays some text in a window and then clears the window, there's no need to send the original text because they're never visible. @@ -210,7 +212,7 @@ really complicate programming with curses much. Most programs go into a flurry of activity, and then pause waiting for a keypress or some other action on the part of the user. All you have to do is to be sure that the screen has been redrawn before pausing to wait for user input, by first calling -``stdscr.refresh()`` or the :meth:`refresh` method of some other relevant +:meth:`!stdscr.refresh` or the :meth:`!refresh` method of some other relevant window. A pad is a special case of a window; it can be larger than the actual display @@ -234,7 +236,7 @@ displayed. :: # : filled with pad content. pad.refresh( 0,0, 5,5, 20,75) -The :meth:`refresh` call displays a section of the pad in the rectangle +The :meth:`!refresh` call displays a section of the pad in the rectangle extending from coordinate (5,5) to coordinate (20,75) on the screen; the upper left corner of the displayed section is coordinate (0,0) on the pad. Beyond that difference, pads are exactly like ordinary windows and support the same @@ -242,7 +244,7 @@ methods. If you have multiple windows and pads on screen there is a more efficient way to update the screen and prevent annoying screen flicker -as each part of the screen gets updated. :meth:`refresh` actually +as each part of the screen gets updated. :meth:`!refresh` actually does two things: 1) Calls the :meth:`~curses.window.noutrefresh` method of each window @@ -251,8 +253,8 @@ does two things: 2) Calls the function :func:`~curses.doupdate` function to change the physical screen to match the desired state recorded in the data structure. -Instead you can call :meth:`noutrefresh` on a number of windows to -update the data structure, and then call :func:`doupdate` to update +Instead you can call :meth:`!noutrefresh` on a number of windows to +update the data structure, and then call :func:`!doupdate` to update the screen. @@ -261,11 +263,11 @@ Displaying Text From a C programmer's point of view, curses may sometimes look like a twisty maze of functions, all subtly different. For example, -:c:func:`addstr` displays a string at the current cursor location in -the ``stdscr`` window, while :c:func:`mvaddstr` moves to a given y,x -coordinate first before displaying the string. :c:func:`waddstr` is just -like :c:func:`addstr`, but allows specifying a window to use instead of -using ``stdscr`` by default. :c:func:`mvwaddstr` allows specifying both +:c:func:`!addstr` displays a string at the current cursor location in +the ``stdscr`` window, while :c:func:`!mvaddstr` moves to a given y,x +coordinate first before displaying the string. :c:func:`!waddstr` is just +like :c:func:`!addstr`, but allows specifying a window to use instead of +using ``stdscr`` by default. :c:func:`!mvwaddstr` allows specifying both a window and a coordinate. Fortunately the Python interface hides all these details. ``stdscr`` @@ -298,7 +300,7 @@ the next subsection. The :meth:`~curses.window.addstr` method takes a Python string or bytestring as the value to be displayed. The contents of bytestrings are sent to the terminal as-is. Strings are encoded to bytes using -the value of the window's :attr:`encoding` attribute; this defaults to +the value of the window's :attr:`~window.encoding` attribute; this defaults to the default system encoding as returned by :func:`locale.getencoding`. The :meth:`~curses.window.addch` methods take a character, which can be @@ -444,15 +446,15 @@ There are two methods for getting input from a window: It's possible to not wait for the user using the :meth:`~curses.window.nodelay` window method. After ``nodelay(True)``, -:meth:`getch` and :meth:`getkey` for the window become -non-blocking. To signal that no input is ready, :meth:`getch` returns -``curses.ERR`` (a value of -1) and :meth:`getkey` raises an exception. +:meth:`!getch` and :meth:`!getkey` for the window become +non-blocking. To signal that no input is ready, :meth:`!getch` returns +``curses.ERR`` (a value of -1) and :meth:`!getkey` raises an exception. There's also a :func:`~curses.halfdelay` function, which can be used to (in -effect) set a timer on each :meth:`getch`; if no input becomes +effect) set a timer on each :meth:`!getch`; if no input becomes available within a specified delay (measured in tenths of a second), curses raises an exception. -The :meth:`getch` method returns an integer; if it's between 0 and 255, it +The :meth:`!getch` method returns an integer; if it's between 0 and 255, it represents the ASCII code of the key pressed. Values greater than 255 are special keys such as Page Up, Home, or the cursor keys. You can compare the value returned to constants such as :const:`curses.KEY_PPAGE`, diff --git a/Doc/library/curses.ascii.rst b/Doc/library/curses.ascii.rst index e1d1171927c9..410b76e77c02 100644 --- a/Doc/library/curses.ascii.rst +++ b/Doc/library/curses.ascii.rst @@ -15,81 +15,81 @@ The :mod:`curses.ascii` module supplies name constants for ASCII characters and functions to test membership in various ASCII character classes. The constants supplied are names for control characters as follows: -+--------------+----------------------------------------------+ -| Name | Meaning | -+==============+==============================================+ -| :const:`NUL` | | -+--------------+----------------------------------------------+ -| :const:`SOH` | Start of heading, console interrupt | -+--------------+----------------------------------------------+ -| :const:`STX` | Start of text | -+--------------+----------------------------------------------+ -| :const:`ETX` | End of text | -+--------------+----------------------------------------------+ -| :const:`EOT` | End of transmission | -+--------------+----------------------------------------------+ -| :const:`ENQ` | Enquiry, goes with :const:`ACK` flow control | -+--------------+----------------------------------------------+ -| :const:`ACK` | Acknowledgement | -+--------------+----------------------------------------------+ -| :const:`BEL` | Bell | -+--------------+----------------------------------------------+ -| :const:`BS` | Backspace | -+--------------+----------------------------------------------+ -| :const:`TAB` | Tab | -+--------------+----------------------------------------------+ -| :const:`HT` | Alias for :const:`TAB`: "Horizontal tab" | -+--------------+----------------------------------------------+ -| :const:`LF` | Line feed | -+--------------+----------------------------------------------+ -| :const:`NL` | Alias for :const:`LF`: "New line" | -+--------------+----------------------------------------------+ -| :const:`VT` | Vertical tab | -+--------------+----------------------------------------------+ -| :const:`FF` | Form feed | -+--------------+----------------------------------------------+ -| :const:`CR` | Carriage return | -+--------------+----------------------------------------------+ -| :const:`SO` | Shift-out, begin alternate character set | -+--------------+----------------------------------------------+ -| :const:`SI` | Shift-in, resume default character set | -+--------------+----------------------------------------------+ -| :const:`DLE` | Data-link escape | -+--------------+----------------------------------------------+ -| :const:`DC1` | XON, for flow control | -+--------------+----------------------------------------------+ -| :const:`DC2` | Device control 2, block-mode flow control | -+--------------+----------------------------------------------+ -| :const:`DC3` | XOFF, for flow control | -+--------------+----------------------------------------------+ -| :const:`DC4` | Device control 4 | -+--------------+----------------------------------------------+ -| :const:`NAK` | Negative acknowledgement | -+--------------+----------------------------------------------+ -| :const:`SYN` | Synchronous idle | -+--------------+----------------------------------------------+ -| :const:`ETB` | End transmission block | -+--------------+----------------------------------------------+ -| :const:`CAN` | Cancel | -+--------------+----------------------------------------------+ -| :const:`EM` | End of medium | -+--------------+----------------------------------------------+ -| :const:`SUB` | Substitute | -+--------------+----------------------------------------------+ -| :const:`ESC` | Escape | -+--------------+----------------------------------------------+ -| :const:`FS` | File separator | -+--------------+----------------------------------------------+ -| :const:`GS` | Group separator | -+--------------+----------------------------------------------+ -| :const:`RS` | Record separator, block-mode terminator | -+--------------+----------------------------------------------+ -| :const:`US` | Unit separator | -+--------------+----------------------------------------------+ -| :const:`SP` | Space | -+--------------+----------------------------------------------+ -| :const:`DEL` | Delete | -+--------------+----------------------------------------------+ ++---------------+----------------------------------------------+ +| Name | Meaning | ++===============+==============================================+ +| .. data:: NUL | | ++---------------+----------------------------------------------+ +| .. data:: SOH | Start of heading, console interrupt | ++---------------+----------------------------------------------+ +| .. data:: STX | Start of text | ++---------------+----------------------------------------------+ +| .. data:: ETX | End of text | ++---------------+----------------------------------------------+ +| .. data:: EOT | End of transmission | ++---------------+----------------------------------------------+ +| .. data:: ENQ | Enquiry, goes with :const:`ACK` flow control | ++---------------+----------------------------------------------+ +| .. data:: ACK | Acknowledgement | ++---------------+----------------------------------------------+ +| .. data:: BEL | Bell | ++---------------+----------------------------------------------+ +| .. data:: BS | Backspace | ++---------------+----------------------------------------------+ +| .. data:: TAB | Tab | ++---------------+----------------------------------------------+ +| .. data:: HT | Alias for :const:`TAB`: "Horizontal tab" | ++---------------+----------------------------------------------+ +| .. data:: LF | Line feed | ++---------------+----------------------------------------------+ +| .. data:: NL | Alias for :const:`LF`: "New line" | ++---------------+----------------------------------------------+ +| .. data:: VT | Vertical tab | ++---------------+----------------------------------------------+ +| .. data:: FF | Form feed | ++---------------+----------------------------------------------+ +| .. data:: CR | Carriage return | ++---------------+----------------------------------------------+ +| .. data:: SO | Shift-out, begin alternate character set | ++---------------+----------------------------------------------+ +| .. data:: SI | Shift-in, resume default character set | ++---------------+----------------------------------------------+ +| .. data:: DLE | Data-link escape | ++---------------+----------------------------------------------+ +| .. data:: DC1 | XON, for flow control | ++---------------+----------------------------------------------+ +| .. data:: DC2 | Device control 2, block-mode flow control | ++---------------+----------------------------------------------+ +| .. data:: DC3 | XOFF, for flow control | ++---------------+----------------------------------------------+ +| .. data:: DC4 | Device control 4 | ++---------------+----------------------------------------------+ +| .. data:: NAK | Negative acknowledgement | ++---------------+----------------------------------------------+ +| .. data:: SYN | Synchronous idle | ++---------------+----------------------------------------------+ +| .. data:: ETB | End transmission block | ++---------------+----------------------------------------------+ +| .. data:: CAN | Cancel | ++---------------+----------------------------------------------+ +| .. data:: EM | End of medium | ++---------------+----------------------------------------------+ +| .. data:: SUB | Substitute | ++---------------+----------------------------------------------+ +| .. data:: ESC | Escape | ++---------------+----------------------------------------------+ +| .. data:: FS | File separator | ++---------------+----------------------------------------------+ +| .. data:: GS | Group separator | ++---------------+----------------------------------------------+ +| .. data:: RS | Record separator, block-mode terminator | ++---------------+----------------------------------------------+ +| .. data:: US | Unit separator | ++---------------+----------------------------------------------+ +| .. data:: SP | Space | ++---------------+----------------------------------------------+ +| .. data:: DEL | Delete | ++---------------+----------------------------------------------+ Note that many of these have little practical significance in modern usage. The mnemonics derive from teleprinter conventions that predate digital computers. diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index f50b51c3780e..cf208f3ba0db 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -107,7 +107,7 @@ The module :mod:`curses` defines the following functions: Return the attribute value for displaying text in the specified color pair. Only the first 256 color pairs are supported. This attribute value can be combined with :const:`A_STANDOUT`, :const:`A_REVERSE`, - and the other :const:`A_\*` attributes. :func:`pair_number` is the counterpart + and the other :const:`!A_\*` attributes. :func:`pair_number` is the counterpart to this function. @@ -223,7 +223,7 @@ The module :mod:`curses` defines the following functions: .. function:: getwin(file) - Read window related data stored in the file by an earlier :func:`putwin` call. + Read window related data stored in the file by an earlier :func:`window.putwin` call. The routine then creates and initializes a new window using that data, returning the new window object. @@ -1323,9 +1323,9 @@ The :mod:`curses` module defines the following data members: .. data:: version +.. data:: __version__ - A bytes object representing the current version of the module. Also available as - :const:`__version__`. + A bytes object representing the current version of the module. .. data:: ncurses_version @@ -1339,51 +1339,55 @@ The :mod:`curses` module defines the following data members: .. versionadded:: 3.8 +.. data:: COLORS + + The maximum number of colors the terminal can support. + +.. data:: COLOR_PAIRS + + The maximum number of color pairs the terminal can support. Some constants are available to specify character cell attributes. The exact constants available are system dependent. -+------------------+-------------------------------+ -| Attribute | Meaning | -+==================+===============================+ -| ``A_ALTCHARSET`` | Alternate character set mode | -+------------------+-------------------------------+ -| ``A_BLINK`` | Blink mode | -+------------------+-------------------------------+ -| ``A_BOLD`` | Bold mode | -+------------------+-------------------------------+ -| ``A_DIM`` | Dim mode | -+------------------+-------------------------------+ -| ``A_INVIS`` | Invisible or blank mode | -+------------------+-------------------------------+ -| ``A_ITALIC`` | Italic mode | -+------------------+-------------------------------+ -| ``A_NORMAL`` | Normal attribute | -+------------------+-------------------------------+ -| ``A_PROTECT`` | Protected mode | -+------------------+-------------------------------+ -| ``A_REVERSE`` | Reverse background and | -| | foreground colors | -+------------------+-------------------------------+ -| ``A_STANDOUT`` | Standout mode | -+------------------+-------------------------------+ -| ``A_UNDERLINE`` | Underline mode | -+------------------+-------------------------------+ -| ``A_HORIZONTAL`` | Horizontal highlight | -+------------------+-------------------------------+ -| ``A_LEFT`` | Left highlight | -+------------------+-------------------------------+ -| ``A_LOW`` | Low highlight | -+------------------+-------------------------------+ -| ``A_RIGHT`` | Right highlight | -+------------------+-------------------------------+ -| ``A_TOP`` | Top highlight | -+------------------+-------------------------------+ -| ``A_VERTICAL`` | Vertical highlight | -+------------------+-------------------------------+ -| ``A_CHARTEXT`` | Bit-mask to extract a | -| | character | -+------------------+-------------------------------+ ++------------------------+-------------------------------+ +| Attribute | Meaning | ++========================+===============================+ +| .. data:: A_ALTCHARSET | Alternate character set mode | ++------------------------+-------------------------------+ +| .. data:: A_BLINK | Blink mode | ++------------------------+-------------------------------+ +| .. data:: A_BOLD | Bold mode | ++------------------------+-------------------------------+ +| .. data:: A_DIM | Dim mode | ++------------------------+-------------------------------+ +| .. data:: A_INVIS | Invisible or blank mode | ++------------------------+-------------------------------+ +| .. data:: A_ITALIC | Italic mode | ++------------------------+-------------------------------+ +| .. data:: A_NORMAL | Normal attribute | ++------------------------+-------------------------------+ +| .. data:: A_PROTECT | Protected mode | ++------------------------+-------------------------------+ +| .. data:: A_REVERSE | Reverse background and | +| | foreground colors | ++------------------------+-------------------------------+ +| .. data:: A_STANDOUT | Standout mode | ++------------------------+-------------------------------+ +| .. data:: A_UNDERLINE | Underline mode | ++------------------------+-------------------------------+ +| .. data:: A_HORIZONTAL | Horizontal highlight | ++------------------------+-------------------------------+ +| .. data:: A_LEFT | Left highlight | ++------------------------+-------------------------------+ +| .. data:: A_LOW | Low highlight | ++------------------------+-------------------------------+ +| .. data:: A_RIGHT | Right highlight | ++------------------------+-------------------------------+ +| .. data:: A_TOP | Top highlight | ++------------------------+-------------------------------+ +| .. data:: A_VERTICAL | Vertical highlight | ++------------------------+-------------------------------+ .. versionadded:: 3.7 ``A_ITALIC`` was added. @@ -1391,220 +1395,220 @@ The exact constants available are system dependent. Several constants are available to extract corresponding attributes returned by some methods. -+------------------+-------------------------------+ -| Bit-mask | Meaning | -+==================+===============================+ -| ``A_ATTRIBUTES`` | Bit-mask to extract | -| | attributes | -+------------------+-------------------------------+ -| ``A_CHARTEXT`` | Bit-mask to extract a | -| | character | -+------------------+-------------------------------+ -| ``A_COLOR`` | Bit-mask to extract | -| | color-pair field information | -+------------------+-------------------------------+ ++-------------------------+-------------------------------+ +| Bit-mask | Meaning | ++=========================+===============================+ +| .. data:: A_ATTRIBUTES | Bit-mask to extract | +| | attributes | ++-------------------------+-------------------------------+ +| .. data:: A_CHARTEXT | Bit-mask to extract a | +| | character | ++-------------------------+-------------------------------+ +| .. data:: A_COLOR | Bit-mask to extract | +| | color-pair field information | ++-------------------------+-------------------------------+ Keys are referred to by integer constants with names starting with ``KEY_``. The exact keycaps available are system dependent. .. XXX this table is far too large! should it be alphabetized? -+-------------------+--------------------------------------------+ -| Key constant | Key | -+===================+============================================+ -| ``KEY_MIN`` | Minimum key value | -+-------------------+--------------------------------------------+ -| ``KEY_BREAK`` | Break key (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_DOWN`` | Down-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_UP`` | Up-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_LEFT`` | Left-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_RIGHT`` | Right-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_HOME`` | Home key (upward+left arrow) | -+-------------------+--------------------------------------------+ -| ``KEY_BACKSPACE`` | Backspace (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_F0`` | Function keys. Up to 64 function keys are | -| | supported. | -+-------------------+--------------------------------------------+ -| ``KEY_Fn`` | Value of function key *n* | -+-------------------+--------------------------------------------+ -| ``KEY_DL`` | Delete line | -+-------------------+--------------------------------------------+ -| ``KEY_IL`` | Insert line | -+-------------------+--------------------------------------------+ -| ``KEY_DC`` | Delete character | -+-------------------+--------------------------------------------+ -| ``KEY_IC`` | Insert char or enter insert mode | -+-------------------+--------------------------------------------+ -| ``KEY_EIC`` | Exit insert char mode | -+-------------------+--------------------------------------------+ -| ``KEY_CLEAR`` | Clear screen | -+-------------------+--------------------------------------------+ -| ``KEY_EOS`` | Clear to end of screen | -+-------------------+--------------------------------------------+ -| ``KEY_EOL`` | Clear to end of line | -+-------------------+--------------------------------------------+ -| ``KEY_SF`` | Scroll 1 line forward | -+-------------------+--------------------------------------------+ -| ``KEY_SR`` | Scroll 1 line backward (reverse) | -+-------------------+--------------------------------------------+ -| ``KEY_NPAGE`` | Next page | -+-------------------+--------------------------------------------+ -| ``KEY_PPAGE`` | Previous page | -+-------------------+--------------------------------------------+ -| ``KEY_STAB`` | Set tab | -+-------------------+--------------------------------------------+ -| ``KEY_CTAB`` | Clear tab | -+-------------------+--------------------------------------------+ -| ``KEY_CATAB`` | Clear all tabs | -+-------------------+--------------------------------------------+ -| ``KEY_ENTER`` | Enter or send (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_SRESET`` | Soft (partial) reset (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_RESET`` | Reset or hard reset (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_PRINT`` | Print | -+-------------------+--------------------------------------------+ -| ``KEY_LL`` | Home down or bottom (lower left) | -+-------------------+--------------------------------------------+ -| ``KEY_A1`` | Upper left of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_A3`` | Upper right of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_B2`` | Center of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_C1`` | Lower left of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_C3`` | Lower right of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_BTAB`` | Back tab | -+-------------------+--------------------------------------------+ -| ``KEY_BEG`` | Beg (beginning) | -+-------------------+--------------------------------------------+ -| ``KEY_CANCEL`` | Cancel | -+-------------------+--------------------------------------------+ -| ``KEY_CLOSE`` | Close | -+-------------------+--------------------------------------------+ -| ``KEY_COMMAND`` | Cmd (command) | -+-------------------+--------------------------------------------+ -| ``KEY_COPY`` | Copy | -+-------------------+--------------------------------------------+ -| ``KEY_CREATE`` | Create | -+-------------------+--------------------------------------------+ -| ``KEY_END`` | End | -+-------------------+--------------------------------------------+ -| ``KEY_EXIT`` | Exit | -+-------------------+--------------------------------------------+ -| ``KEY_FIND`` | Find | -+-------------------+--------------------------------------------+ -| ``KEY_HELP`` | Help | -+-------------------+--------------------------------------------+ -| ``KEY_MARK`` | Mark | -+-------------------+--------------------------------------------+ -| ``KEY_MESSAGE`` | Message | -+-------------------+--------------------------------------------+ -| ``KEY_MOVE`` | Move | -+-------------------+--------------------------------------------+ -| ``KEY_NEXT`` | Next | -+-------------------+--------------------------------------------+ -| ``KEY_OPEN`` | Open | -+-------------------+--------------------------------------------+ -| ``KEY_OPTIONS`` | Options | -+-------------------+--------------------------------------------+ -| ``KEY_PREVIOUS`` | Prev (previous) | -+-------------------+--------------------------------------------+ -| ``KEY_REDO`` | Redo | -+-------------------+--------------------------------------------+ -| ``KEY_REFERENCE`` | Ref (reference) | -+-------------------+--------------------------------------------+ -| ``KEY_REFRESH`` | Refresh | -+-------------------+--------------------------------------------+ -| ``KEY_REPLACE`` | Replace | -+-------------------+--------------------------------------------+ -| ``KEY_RESTART`` | Restart | -+-------------------+--------------------------------------------+ -| ``KEY_RESUME`` | Resume | -+-------------------+--------------------------------------------+ -| ``KEY_SAVE`` | Save | -+-------------------+--------------------------------------------+ -| ``KEY_SBEG`` | Shifted Beg (beginning) | -+-------------------+--------------------------------------------+ -| ``KEY_SCANCEL`` | Shifted Cancel | -+-------------------+--------------------------------------------+ -| ``KEY_SCOMMAND`` | Shifted Command | -+-------------------+--------------------------------------------+ -| ``KEY_SCOPY`` | Shifted Copy | -+-------------------+--------------------------------------------+ -| ``KEY_SCREATE`` | Shifted Create | -+-------------------+--------------------------------------------+ -| ``KEY_SDC`` | Shifted Delete char | -+-------------------+--------------------------------------------+ -| ``KEY_SDL`` | Shifted Delete line | -+-------------------+--------------------------------------------+ -| ``KEY_SELECT`` | Select | -+-------------------+--------------------------------------------+ -| ``KEY_SEND`` | Shifted End | -+-------------------+--------------------------------------------+ -| ``KEY_SEOL`` | Shifted Clear line | -+-------------------+--------------------------------------------+ -| ``KEY_SEXIT`` | Shifted Exit | -+-------------------+--------------------------------------------+ -| ``KEY_SFIND`` | Shifted Find | -+-------------------+--------------------------------------------+ -| ``KEY_SHELP`` | Shifted Help | -+-------------------+--------------------------------------------+ -| ``KEY_SHOME`` | Shifted Home | -+-------------------+--------------------------------------------+ -| ``KEY_SIC`` | Shifted Input | -+-------------------+--------------------------------------------+ -| ``KEY_SLEFT`` | Shifted Left arrow | -+-------------------+--------------------------------------------+ -| ``KEY_SMESSAGE`` | Shifted Message | -+-------------------+--------------------------------------------+ -| ``KEY_SMOVE`` | Shifted Move | -+-------------------+--------------------------------------------+ -| ``KEY_SNEXT`` | Shifted Next | -+-------------------+--------------------------------------------+ -| ``KEY_SOPTIONS`` | Shifted Options | -+-------------------+--------------------------------------------+ -| ``KEY_SPREVIOUS`` | Shifted Prev | -+-------------------+--------------------------------------------+ -| ``KEY_SPRINT`` | Shifted Print | -+-------------------+--------------------------------------------+ -| ``KEY_SREDO`` | Shifted Redo | -+-------------------+--------------------------------------------+ -| ``KEY_SREPLACE`` | Shifted Replace | -+-------------------+--------------------------------------------+ -| ``KEY_SRIGHT`` | Shifted Right arrow | -+-------------------+--------------------------------------------+ -| ``KEY_SRSUME`` | Shifted Resume | -+-------------------+--------------------------------------------+ -| ``KEY_SSAVE`` | Shifted Save | -+-------------------+--------------------------------------------+ -| ``KEY_SSUSPEND`` | Shifted Suspend | -+-------------------+--------------------------------------------+ -| ``KEY_SUNDO`` | Shifted Undo | -+-------------------+--------------------------------------------+ -| ``KEY_SUSPEND`` | Suspend | -+-------------------+--------------------------------------------+ -| ``KEY_UNDO`` | Undo | -+-------------------+--------------------------------------------+ -| ``KEY_MOUSE`` | Mouse event has occurred | -+-------------------+--------------------------------------------+ -| ``KEY_RESIZE`` | Terminal resize event | -+-------------------+--------------------------------------------+ -| ``KEY_MAX`` | Maximum key value | -+-------------------+--------------------------------------------+ ++-------------------------+--------------------------------------------+ +| Key constant | Key | ++=========================+============================================+ +| .. data:: KEY_MIN | Minimum key value | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BREAK | Break key (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_DOWN | Down-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_UP | Up-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_LEFT | Left-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RIGHT | Right-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_HOME | Home key (upward+left arrow) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BACKSPACE | Backspace (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_F0 | Function keys. Up to 64 function keys are | +| | supported. | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_Fn | Value of function key *n* | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_DL | Delete line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_IL | Insert line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_DC | Delete character | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_IC | Insert char or enter insert mode | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EIC | Exit insert char mode | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CLEAR | Clear screen | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EOS | Clear to end of screen | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EOL | Clear to end of line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SF | Scroll 1 line forward | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SR | Scroll 1 line backward (reverse) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_NPAGE | Next page | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_PPAGE | Previous page | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_STAB | Set tab | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CTAB | Clear tab | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CATAB | Clear all tabs | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_ENTER | Enter or send (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SRESET | Soft (partial) reset (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESET | Reset or hard reset (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_PRINT | Print | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_LL | Home down or bottom (lower left) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_A1 | Upper left of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_A3 | Upper right of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_B2 | Center of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_C1 | Lower left of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_C3 | Lower right of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BTAB | Back tab | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BEG | Beg (beginning) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CANCEL | Cancel | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CLOSE | Close | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_COMMAND | Cmd (command) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_COPY | Copy | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CREATE | Create | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_END | End | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EXIT | Exit | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_FIND | Find | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_HELP | Help | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MARK | Mark | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MESSAGE | Message | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MOVE | Move | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_NEXT | Next | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_OPEN | Open | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_OPTIONS | Options | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_PREVIOUS | Prev (previous) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REDO | Redo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REFERENCE | Ref (reference) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REFRESH | Refresh | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REPLACE | Replace | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESTART | Restart | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESUME | Resume | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SAVE | Save | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SBEG | Shifted Beg (beginning) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCANCEL | Shifted Cancel | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCOMMAND | Shifted Command | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCOPY | Shifted Copy | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCREATE | Shifted Create | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SDC | Shifted Delete char | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SDL | Shifted Delete line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SELECT | Select | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SEND | Shifted End | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SEOL | Shifted Clear line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SEXIT | Shifted Exit | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SFIND | Shifted Find | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SHELP | Shifted Help | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SHOME | Shifted Home | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SIC | Shifted Input | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SLEFT | Shifted Left arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SMESSAGE | Shifted Message | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SMOVE | Shifted Move | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SNEXT | Shifted Next | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SOPTIONS | Shifted Options | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SPREVIOUS | Shifted Prev | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SPRINT | Shifted Print | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SREDO | Shifted Redo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SREPLACE | Shifted Replace | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SRIGHT | Shifted Right arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SRSUME | Shifted Resume | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SSAVE | Shifted Save | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SSUSPEND | Shifted Suspend | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SUNDO | Shifted Undo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SUSPEND | Suspend | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_UNDO | Undo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MOUSE | Mouse event has occurred | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESIZE | Terminal resize event | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MAX | Maximum key value | ++-------------------------+--------------------------------------------+ On VT100s and their software emulations, such as X terminal emulators, there are -normally at least four function keys (:const:`KEY_F1`, :const:`KEY_F2`, -:const:`KEY_F3`, :const:`KEY_F4`) available, and the arrow keys mapped to +normally at least four function keys (:const:`KEY_F1 <KEY_Fn>`, :const:`KEY_F2 <KEY_Fn>`, +:const:`KEY_F3 <KEY_Fn>`, :const:`KEY_F4 <KEY_Fn>`) available, and the arrow keys mapped to :const:`KEY_UP`, :const:`KEY_DOWN`, :const:`KEY_LEFT` and :const:`KEY_RIGHT` in the obvious way. If your machine has a PC keyboard, it is safe to expect arrow keys and twelve function keys (older PC keyboards may have only ten function @@ -1635,117 +1639,143 @@ falls back on a crude printable ASCII approximation. These are available only after :func:`initscr` has been called. -+------------------+------------------------------------------+ -| ACS code | Meaning | -+==================+==========================================+ -| ``ACS_BBSS`` | alternate name for upper right corner | -+------------------+------------------------------------------+ -| ``ACS_BLOCK`` | solid square block | -+------------------+------------------------------------------+ -| ``ACS_BOARD`` | board of squares | -+------------------+------------------------------------------+ -| ``ACS_BSBS`` | alternate name for horizontal line | -+------------------+------------------------------------------+ -| ``ACS_BSSB`` | alternate name for upper left corner | -+------------------+------------------------------------------+ -| ``ACS_BSSS`` | alternate name for top tee | -+------------------+------------------------------------------+ -| ``ACS_BTEE`` | bottom tee | -+------------------+------------------------------------------+ -| ``ACS_BULLET`` | bullet | -+------------------+------------------------------------------+ -| ``ACS_CKBOARD`` | checker board (stipple) | -+------------------+------------------------------------------+ -| ``ACS_DARROW`` | arrow pointing down | -+------------------+------------------------------------------+ -| ``ACS_DEGREE`` | degree symbol | -+------------------+------------------------------------------+ -| ``ACS_DIAMOND`` | diamond | -+------------------+------------------------------------------+ -| ``ACS_GEQUAL`` | greater-than-or-equal-to | -+------------------+------------------------------------------+ -| ``ACS_HLINE`` | horizontal line | -+------------------+------------------------------------------+ -| ``ACS_LANTERN`` | lantern symbol | -+------------------+------------------------------------------+ -| ``ACS_LARROW`` | left arrow | -+------------------+------------------------------------------+ -| ``ACS_LEQUAL`` | less-than-or-equal-to | -+------------------+------------------------------------------+ -| ``ACS_LLCORNER`` | lower left-hand corner | -+------------------+------------------------------------------+ -| ``ACS_LRCORNER`` | lower right-hand corner | -+------------------+------------------------------------------+ -| ``ACS_LTEE`` | left tee | -+------------------+------------------------------------------+ -| ``ACS_NEQUAL`` | not-equal sign | -+------------------+------------------------------------------+ -| ``ACS_PI`` | letter pi | -+------------------+------------------------------------------+ -| ``ACS_PLMINUS`` | plus-or-minus sign | -+------------------+------------------------------------------+ -| ``ACS_PLUS`` | big plus sign | -+------------------+------------------------------------------+ -| ``ACS_RARROW`` | right arrow | -+------------------+------------------------------------------+ -| ``ACS_RTEE`` | right tee | -+------------------+------------------------------------------+ -| ``ACS_S1`` | scan line 1 | -+------------------+------------------------------------------+ -| ``ACS_S3`` | scan line 3 | -+------------------+------------------------------------------+ -| ``ACS_S7`` | scan line 7 | -+------------------+------------------------------------------+ -| ``ACS_S9`` | scan line 9 | -+------------------+------------------------------------------+ -| ``ACS_SBBS`` | alternate name for lower right corner | -+------------------+------------------------------------------+ -| ``ACS_SBSB`` | alternate name for vertical line | -+------------------+------------------------------------------+ -| ``ACS_SBSS`` | alternate name for right tee | -+------------------+------------------------------------------+ -| ``ACS_SSBB`` | alternate name for lower left corner | -+------------------+------------------------------------------+ -| ``ACS_SSBS`` | alternate name for bottom tee | -+------------------+------------------------------------------+ -| ``ACS_SSSB`` | alternate name for left tee | -+------------------+------------------------------------------+ -| ``ACS_SSSS`` | alternate name for crossover or big plus | -+------------------+------------------------------------------+ -| ``ACS_STERLING`` | pound sterling | -+------------------+------------------------------------------+ -| ``ACS_TTEE`` | top tee | -+------------------+------------------------------------------+ -| ``ACS_UARROW`` | up arrow | -+------------------+------------------------------------------+ -| ``ACS_ULCORNER`` | upper left corner | -+------------------+------------------------------------------+ -| ``ACS_URCORNER`` | upper right corner | -+------------------+------------------------------------------+ -| ``ACS_VLINE`` | vertical line | -+------------------+------------------------------------------+ ++------------------------+------------------------------------------+ +| ACS code | Meaning | ++========================+==========================================+ +| .. data:: ACS_BBSS | alternate name for upper right corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_BLOCK | solid square block | ++------------------------+------------------------------------------+ +| .. data:: ACS_BOARD | board of squares | ++------------------------+------------------------------------------+ +| .. data:: ACS_BSBS | alternate name for horizontal line | ++------------------------+------------------------------------------+ +| .. data:: ACS_BSSB | alternate name for upper left corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_BSSS | alternate name for top tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_BTEE | bottom tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_BULLET | bullet | ++------------------------+------------------------------------------+ +| .. data:: ACS_CKBOARD | checker board (stipple) | ++------------------------+------------------------------------------+ +| .. data:: ACS_DARROW | arrow pointing down | ++------------------------+------------------------------------------+ +| .. data:: ACS_DEGREE | degree symbol | ++------------------------+------------------------------------------+ +| .. data:: ACS_DIAMOND | diamond | ++------------------------+------------------------------------------+ +| .. data:: ACS_GEQUAL | greater-than-or-equal-to | ++------------------------+------------------------------------------+ +| .. data:: ACS_HLINE | horizontal line | ++------------------------+------------------------------------------+ +| .. data:: ACS_LANTERN | lantern symbol | ++------------------------+------------------------------------------+ +| .. data:: ACS_LARROW | left arrow | ++------------------------+------------------------------------------+ +| .. data:: ACS_LEQUAL | less-than-or-equal-to | ++------------------------+------------------------------------------+ +| .. data:: ACS_LLCORNER | lower left-hand corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_LRCORNER | lower right-hand corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_LTEE | left tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_NEQUAL | not-equal sign | ++------------------------+------------------------------------------+ +| .. data:: ACS_PI | letter pi | ++------------------------+------------------------------------------+ +| .. data:: ACS_PLMINUS | plus-or-minus sign | ++------------------------+------------------------------------------+ +| .. data:: ACS_PLUS | big plus sign | ++------------------------+------------------------------------------+ +| .. data:: ACS_RARROW | right arrow | ++------------------------+------------------------------------------+ +| .. data:: ACS_RTEE | right tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_S1 | scan line 1 | ++------------------------+------------------------------------------+ +| .. data:: ACS_S3 | scan line 3 | ++------------------------+------------------------------------------+ +| .. data:: ACS_S7 | scan line 7 | ++------------------------+------------------------------------------+ +| .. data:: ACS_S9 | scan line 9 | ++------------------------+------------------------------------------+ +| .. data:: ACS_SBBS | alternate name for lower right corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_SBSB | alternate name for vertical line | ++------------------------+------------------------------------------+ +| .. data:: ACS_SBSS | alternate name for right tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSBB | alternate name for lower left corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSBS | alternate name for bottom tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSSB | alternate name for left tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSSS | alternate name for crossover or big plus | ++------------------------+------------------------------------------+ +| .. data:: ACS_STERLING | pound sterling | ++------------------------+------------------------------------------+ +| .. data:: ACS_TTEE | top tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_UARROW | up arrow | ++------------------------+------------------------------------------+ +| .. data:: ACS_ULCORNER | upper left corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_URCORNER | upper right corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_VLINE | vertical line | ++------------------------+------------------------------------------+ + +The following table lists mouse button constants used by :meth:`getmouse`: + ++----------------------------------+---------------------------------------------+ +| Mouse button constant | Meaning | ++==================================+=============================================+ +| .. data:: BUTTONn_PRESSED | Mouse button *n* pressed | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_RELEASED | Mouse button *n* released | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_CLICKED | Mouse button *n* clicked | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_DOUBLE_CLICKED | Mouse button *n* double clicked | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_TRIPLE_CLICKED | Mouse button *n* triple clicked | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTON_SHIFT | Shift was down during button state change | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTON_CTRL | Control was down during button state change | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTON_ALT | Control was down during button state change | ++----------------------------------+---------------------------------------------+ + + .. versionchanged:: 3.10 + The ``BUTTON5_*`` constants are now exposed if they are provided by the + underlying curses library. The following table lists the predefined colors: -+-------------------+----------------------------+ -| Constant | Color | -+===================+============================+ -| ``COLOR_BLACK`` | Black | -+-------------------+----------------------------+ -| ``COLOR_BLUE`` | Blue | -+-------------------+----------------------------+ -| ``COLOR_CYAN`` | Cyan (light greenish blue) | -+-------------------+----------------------------+ -| ``COLOR_GREEN`` | Green | -+-------------------+----------------------------+ -| ``COLOR_MAGENTA`` | Magenta (purplish red) | -+-------------------+----------------------------+ -| ``COLOR_RED`` | Red | -+-------------------+----------------------------+ -| ``COLOR_WHITE`` | White | -+-------------------+----------------------------+ -| ``COLOR_YELLOW`` | Yellow | -+-------------------+----------------------------+ ++-------------------------+----------------------------+ +| Constant | Color | ++=========================+============================+ +| .. data:: COLOR_BLACK | Black | ++-------------------------+----------------------------+ +| .. data:: COLOR_BLUE | Blue | ++-------------------------+----------------------------+ +| .. data:: COLOR_CYAN | Cyan (light greenish blue) | ++-------------------------+----------------------------+ +| .. data:: COLOR_GREEN | Green | ++-------------------------+----------------------------+ +| .. data:: COLOR_MAGENTA | Magenta (purplish red) | ++-------------------------+----------------------------+ +| .. data:: COLOR_RED | Red | ++-------------------------+----------------------------+ +| .. data:: COLOR_WHITE | White | ++-------------------------+----------------------------+ +| .. data:: COLOR_YELLOW | Yellow | ++-------------------------+----------------------------+ :mod:`curses.textpad` --- Text input widget for curses programs @@ -1851,19 +1881,19 @@ You can instantiate a :class:`Textbox` object as follows: Move operations do nothing if the cursor is at an edge where the movement is not possible. The following synonyms are supported where possible: - +------------------------+------------------+ - | Constant | Keystroke | - +========================+==================+ - | :const:`KEY_LEFT` | :kbd:`Control-B` | - +------------------------+------------------+ - | :const:`KEY_RIGHT` | :kbd:`Control-F` | - +------------------------+------------------+ - | :const:`KEY_UP` | :kbd:`Control-P` | - +------------------------+------------------+ - | :const:`KEY_DOWN` | :kbd:`Control-N` | - +------------------------+------------------+ - | :const:`KEY_BACKSPACE` | :kbd:`Control-h` | - +------------------------+------------------+ + +--------------------------------+------------------+ + | Constant | Keystroke | + +================================+==================+ + | :const:`~curses.KEY_LEFT` | :kbd:`Control-B` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_RIGHT` | :kbd:`Control-F` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_UP` | :kbd:`Control-P` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_DOWN` | :kbd:`Control-N` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_BACKSPACE` | :kbd:`Control-h` | + +--------------------------------+------------------+ All other keystrokes are treated as a command to insert the given character and move right (with line wrapping). From webhook-mailer at python.org Wed May 3 01:20:58 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 03 May 2023 05:20:58 -0000 Subject: [Python-checkins] [3.11] gh-101100: Fix Sphinx warnings in `curses` and `curses.ascii` modules (GH-103457) (#104124) Message-ID: <mailman.121.1683091259.13550.python-checkins@python.org> https://github.com/python/cpython/commit/365e0772c9d9be9bd70379afa0bf01ecb9bbe744 commit: 365e0772c9d9be9bd70379afa0bf01ecb9bbe744 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-02T23:20:50-06:00 summary: [3.11] gh-101100: Fix Sphinx warnings in `curses` and `curses.ascii` modules (GH-103457) (#104124) Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/howto/curses.rst M Doc/library/curses.ascii.rst M Doc/library/curses.rst diff --git a/Doc/howto/curses.rst b/Doc/howto/curses.rst index 83d80471ffc8..a3068d86d85b 100644 --- a/Doc/howto/curses.rst +++ b/Doc/howto/curses.rst @@ -4,6 +4,8 @@ Curses Programming with Python ********************************** +.. currentmodule:: curses + :Author: A.M. Kuchling, Eric S. Raymond :Release: 2.04 @@ -65,7 +67,7 @@ The Python module is a fairly simple wrapper over the C functions provided by curses; if you're already familiar with curses programming in C, it's really easy to transfer that knowledge to Python. The biggest difference is that the Python interface makes things simpler by merging different C functions such as -:c:func:`addstr`, :c:func:`mvaddstr`, and :c:func:`mvwaddstr` into a single +:c:func:`!addstr`, :c:func:`!mvaddstr`, and :c:func:`!mvwaddstr` into a single :meth:`~curses.window.addstr` method. You'll see this covered in more detail later. @@ -82,7 +84,7 @@ Before doing anything, curses must be initialized. This is done by calling the :func:`~curses.initscr` function, which will determine the terminal type, send any required setup codes to the terminal, and create various internal data structures. If successful, -:func:`initscr` returns a window object representing the entire +:func:`!initscr` returns a window object representing the entire screen; this is usually called ``stdscr`` after the name of the corresponding C variable. :: @@ -151,8 +153,8 @@ importing the :func:`curses.wrapper` function and using it like this:: The :func:`~curses.wrapper` function takes a callable object and does the initializations described above, also initializing colors if color -support is present. :func:`wrapper` then runs your provided callable. -Once the callable returns, :func:`wrapper` will restore the original +support is present. :func:`!wrapper` then runs your provided callable. +Once the callable returns, :func:`!wrapper` will restore the original state of the terminal. The callable is called inside a :keyword:`try`...\ :keyword:`except` that catches exceptions, restores the state of the terminal, and then re-raises the exception. Therefore @@ -200,7 +202,7 @@ This is because curses was originally written with slow 300-baud terminal connections in mind; with these terminals, minimizing the time required to redraw the screen was very important. Instead curses accumulates changes to the screen and displays them in the most -efficient manner when you call :meth:`refresh`. For example, if your +efficient manner when you call :meth:`!refresh`. For example, if your program displays some text in a window and then clears the window, there's no need to send the original text because they're never visible. @@ -210,7 +212,7 @@ really complicate programming with curses much. Most programs go into a flurry of activity, and then pause waiting for a keypress or some other action on the part of the user. All you have to do is to be sure that the screen has been redrawn before pausing to wait for user input, by first calling -``stdscr.refresh()`` or the :meth:`refresh` method of some other relevant +:meth:`!stdscr.refresh` or the :meth:`!refresh` method of some other relevant window. A pad is a special case of a window; it can be larger than the actual display @@ -234,7 +236,7 @@ displayed. :: # : filled with pad content. pad.refresh( 0,0, 5,5, 20,75) -The :meth:`refresh` call displays a section of the pad in the rectangle +The :meth:`!refresh` call displays a section of the pad in the rectangle extending from coordinate (5,5) to coordinate (20,75) on the screen; the upper left corner of the displayed section is coordinate (0,0) on the pad. Beyond that difference, pads are exactly like ordinary windows and support the same @@ -242,7 +244,7 @@ methods. If you have multiple windows and pads on screen there is a more efficient way to update the screen and prevent annoying screen flicker -as each part of the screen gets updated. :meth:`refresh` actually +as each part of the screen gets updated. :meth:`!refresh` actually does two things: 1) Calls the :meth:`~curses.window.noutrefresh` method of each window @@ -251,8 +253,8 @@ does two things: 2) Calls the function :func:`~curses.doupdate` function to change the physical screen to match the desired state recorded in the data structure. -Instead you can call :meth:`noutrefresh` on a number of windows to -update the data structure, and then call :func:`doupdate` to update +Instead you can call :meth:`!noutrefresh` on a number of windows to +update the data structure, and then call :func:`!doupdate` to update the screen. @@ -261,11 +263,11 @@ Displaying Text From a C programmer's point of view, curses may sometimes look like a twisty maze of functions, all subtly different. For example, -:c:func:`addstr` displays a string at the current cursor location in -the ``stdscr`` window, while :c:func:`mvaddstr` moves to a given y,x -coordinate first before displaying the string. :c:func:`waddstr` is just -like :c:func:`addstr`, but allows specifying a window to use instead of -using ``stdscr`` by default. :c:func:`mvwaddstr` allows specifying both +:c:func:`!addstr` displays a string at the current cursor location in +the ``stdscr`` window, while :c:func:`!mvaddstr` moves to a given y,x +coordinate first before displaying the string. :c:func:`!waddstr` is just +like :c:func:`!addstr`, but allows specifying a window to use instead of +using ``stdscr`` by default. :c:func:`!mvwaddstr` allows specifying both a window and a coordinate. Fortunately the Python interface hides all these details. ``stdscr`` @@ -298,7 +300,7 @@ the next subsection. The :meth:`~curses.window.addstr` method takes a Python string or bytestring as the value to be displayed. The contents of bytestrings are sent to the terminal as-is. Strings are encoded to bytes using -the value of the window's :attr:`encoding` attribute; this defaults to +the value of the window's :attr:`~window.encoding` attribute; this defaults to the default system encoding as returned by :func:`locale.getencoding`. The :meth:`~curses.window.addch` methods take a character, which can be @@ -444,15 +446,15 @@ There are two methods for getting input from a window: It's possible to not wait for the user using the :meth:`~curses.window.nodelay` window method. After ``nodelay(True)``, -:meth:`getch` and :meth:`getkey` for the window become -non-blocking. To signal that no input is ready, :meth:`getch` returns -``curses.ERR`` (a value of -1) and :meth:`getkey` raises an exception. +:meth:`!getch` and :meth:`!getkey` for the window become +non-blocking. To signal that no input is ready, :meth:`!getch` returns +``curses.ERR`` (a value of -1) and :meth:`!getkey` raises an exception. There's also a :func:`~curses.halfdelay` function, which can be used to (in -effect) set a timer on each :meth:`getch`; if no input becomes +effect) set a timer on each :meth:`!getch`; if no input becomes available within a specified delay (measured in tenths of a second), curses raises an exception. -The :meth:`getch` method returns an integer; if it's between 0 and 255, it +The :meth:`!getch` method returns an integer; if it's between 0 and 255, it represents the ASCII code of the key pressed. Values greater than 255 are special keys such as Page Up, Home, or the cursor keys. You can compare the value returned to constants such as :const:`curses.KEY_PPAGE`, diff --git a/Doc/library/curses.ascii.rst b/Doc/library/curses.ascii.rst index e1d1171927c9..410b76e77c02 100644 --- a/Doc/library/curses.ascii.rst +++ b/Doc/library/curses.ascii.rst @@ -15,81 +15,81 @@ The :mod:`curses.ascii` module supplies name constants for ASCII characters and functions to test membership in various ASCII character classes. The constants supplied are names for control characters as follows: -+--------------+----------------------------------------------+ -| Name | Meaning | -+==============+==============================================+ -| :const:`NUL` | | -+--------------+----------------------------------------------+ -| :const:`SOH` | Start of heading, console interrupt | -+--------------+----------------------------------------------+ -| :const:`STX` | Start of text | -+--------------+----------------------------------------------+ -| :const:`ETX` | End of text | -+--------------+----------------------------------------------+ -| :const:`EOT` | End of transmission | -+--------------+----------------------------------------------+ -| :const:`ENQ` | Enquiry, goes with :const:`ACK` flow control | -+--------------+----------------------------------------------+ -| :const:`ACK` | Acknowledgement | -+--------------+----------------------------------------------+ -| :const:`BEL` | Bell | -+--------------+----------------------------------------------+ -| :const:`BS` | Backspace | -+--------------+----------------------------------------------+ -| :const:`TAB` | Tab | -+--------------+----------------------------------------------+ -| :const:`HT` | Alias for :const:`TAB`: "Horizontal tab" | -+--------------+----------------------------------------------+ -| :const:`LF` | Line feed | -+--------------+----------------------------------------------+ -| :const:`NL` | Alias for :const:`LF`: "New line" | -+--------------+----------------------------------------------+ -| :const:`VT` | Vertical tab | -+--------------+----------------------------------------------+ -| :const:`FF` | Form feed | -+--------------+----------------------------------------------+ -| :const:`CR` | Carriage return | -+--------------+----------------------------------------------+ -| :const:`SO` | Shift-out, begin alternate character set | -+--------------+----------------------------------------------+ -| :const:`SI` | Shift-in, resume default character set | -+--------------+----------------------------------------------+ -| :const:`DLE` | Data-link escape | -+--------------+----------------------------------------------+ -| :const:`DC1` | XON, for flow control | -+--------------+----------------------------------------------+ -| :const:`DC2` | Device control 2, block-mode flow control | -+--------------+----------------------------------------------+ -| :const:`DC3` | XOFF, for flow control | -+--------------+----------------------------------------------+ -| :const:`DC4` | Device control 4 | -+--------------+----------------------------------------------+ -| :const:`NAK` | Negative acknowledgement | -+--------------+----------------------------------------------+ -| :const:`SYN` | Synchronous idle | -+--------------+----------------------------------------------+ -| :const:`ETB` | End transmission block | -+--------------+----------------------------------------------+ -| :const:`CAN` | Cancel | -+--------------+----------------------------------------------+ -| :const:`EM` | End of medium | -+--------------+----------------------------------------------+ -| :const:`SUB` | Substitute | -+--------------+----------------------------------------------+ -| :const:`ESC` | Escape | -+--------------+----------------------------------------------+ -| :const:`FS` | File separator | -+--------------+----------------------------------------------+ -| :const:`GS` | Group separator | -+--------------+----------------------------------------------+ -| :const:`RS` | Record separator, block-mode terminator | -+--------------+----------------------------------------------+ -| :const:`US` | Unit separator | -+--------------+----------------------------------------------+ -| :const:`SP` | Space | -+--------------+----------------------------------------------+ -| :const:`DEL` | Delete | -+--------------+----------------------------------------------+ ++---------------+----------------------------------------------+ +| Name | Meaning | ++===============+==============================================+ +| .. data:: NUL | | ++---------------+----------------------------------------------+ +| .. data:: SOH | Start of heading, console interrupt | ++---------------+----------------------------------------------+ +| .. data:: STX | Start of text | ++---------------+----------------------------------------------+ +| .. data:: ETX | End of text | ++---------------+----------------------------------------------+ +| .. data:: EOT | End of transmission | ++---------------+----------------------------------------------+ +| .. data:: ENQ | Enquiry, goes with :const:`ACK` flow control | ++---------------+----------------------------------------------+ +| .. data:: ACK | Acknowledgement | ++---------------+----------------------------------------------+ +| .. data:: BEL | Bell | ++---------------+----------------------------------------------+ +| .. data:: BS | Backspace | ++---------------+----------------------------------------------+ +| .. data:: TAB | Tab | ++---------------+----------------------------------------------+ +| .. data:: HT | Alias for :const:`TAB`: "Horizontal tab" | ++---------------+----------------------------------------------+ +| .. data:: LF | Line feed | ++---------------+----------------------------------------------+ +| .. data:: NL | Alias for :const:`LF`: "New line" | ++---------------+----------------------------------------------+ +| .. data:: VT | Vertical tab | ++---------------+----------------------------------------------+ +| .. data:: FF | Form feed | ++---------------+----------------------------------------------+ +| .. data:: CR | Carriage return | ++---------------+----------------------------------------------+ +| .. data:: SO | Shift-out, begin alternate character set | ++---------------+----------------------------------------------+ +| .. data:: SI | Shift-in, resume default character set | ++---------------+----------------------------------------------+ +| .. data:: DLE | Data-link escape | ++---------------+----------------------------------------------+ +| .. data:: DC1 | XON, for flow control | ++---------------+----------------------------------------------+ +| .. data:: DC2 | Device control 2, block-mode flow control | ++---------------+----------------------------------------------+ +| .. data:: DC3 | XOFF, for flow control | ++---------------+----------------------------------------------+ +| .. data:: DC4 | Device control 4 | ++---------------+----------------------------------------------+ +| .. data:: NAK | Negative acknowledgement | ++---------------+----------------------------------------------+ +| .. data:: SYN | Synchronous idle | ++---------------+----------------------------------------------+ +| .. data:: ETB | End transmission block | ++---------------+----------------------------------------------+ +| .. data:: CAN | Cancel | ++---------------+----------------------------------------------+ +| .. data:: EM | End of medium | ++---------------+----------------------------------------------+ +| .. data:: SUB | Substitute | ++---------------+----------------------------------------------+ +| .. data:: ESC | Escape | ++---------------+----------------------------------------------+ +| .. data:: FS | File separator | ++---------------+----------------------------------------------+ +| .. data:: GS | Group separator | ++---------------+----------------------------------------------+ +| .. data:: RS | Record separator, block-mode terminator | ++---------------+----------------------------------------------+ +| .. data:: US | Unit separator | ++---------------+----------------------------------------------+ +| .. data:: SP | Space | ++---------------+----------------------------------------------+ +| .. data:: DEL | Delete | ++---------------+----------------------------------------------+ Note that many of these have little practical significance in modern usage. The mnemonics derive from teleprinter conventions that predate digital computers. diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 56311033d631..44dd9d32f148 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -110,7 +110,7 @@ The module :mod:`curses` defines the following functions: Return the attribute value for displaying text in the specified color pair. Only the first 256 color pairs are supported. This attribute value can be combined with :const:`A_STANDOUT`, :const:`A_REVERSE`, - and the other :const:`A_\*` attributes. :func:`pair_number` is the counterpart + and the other :const:`!A_\*` attributes. :func:`pair_number` is the counterpart to this function. @@ -226,7 +226,7 @@ The module :mod:`curses` defines the following functions: .. function:: getwin(file) - Read window related data stored in the file by an earlier :func:`putwin` call. + Read window related data stored in the file by an earlier :func:`window.putwin` call. The routine then creates and initializes a new window using that data, returning the new window object. @@ -1326,9 +1326,9 @@ The :mod:`curses` module defines the following data members: .. data:: version +.. data:: __version__ - A bytes object representing the current version of the module. Also available as - :const:`__version__`. + A bytes object representing the current version of the module. .. data:: ncurses_version @@ -1342,51 +1342,55 @@ The :mod:`curses` module defines the following data members: .. versionadded:: 3.8 +.. data:: COLORS + + The maximum number of colors the terminal can support. + +.. data:: COLOR_PAIRS + + The maximum number of color pairs the terminal can support. Some constants are available to specify character cell attributes. The exact constants available are system dependent. -+------------------+-------------------------------+ -| Attribute | Meaning | -+==================+===============================+ -| ``A_ALTCHARSET`` | Alternate character set mode | -+------------------+-------------------------------+ -| ``A_BLINK`` | Blink mode | -+------------------+-------------------------------+ -| ``A_BOLD`` | Bold mode | -+------------------+-------------------------------+ -| ``A_DIM`` | Dim mode | -+------------------+-------------------------------+ -| ``A_INVIS`` | Invisible or blank mode | -+------------------+-------------------------------+ -| ``A_ITALIC`` | Italic mode | -+------------------+-------------------------------+ -| ``A_NORMAL`` | Normal attribute | -+------------------+-------------------------------+ -| ``A_PROTECT`` | Protected mode | -+------------------+-------------------------------+ -| ``A_REVERSE`` | Reverse background and | -| | foreground colors | -+------------------+-------------------------------+ -| ``A_STANDOUT`` | Standout mode | -+------------------+-------------------------------+ -| ``A_UNDERLINE`` | Underline mode | -+------------------+-------------------------------+ -| ``A_HORIZONTAL`` | Horizontal highlight | -+------------------+-------------------------------+ -| ``A_LEFT`` | Left highlight | -+------------------+-------------------------------+ -| ``A_LOW`` | Low highlight | -+------------------+-------------------------------+ -| ``A_RIGHT`` | Right highlight | -+------------------+-------------------------------+ -| ``A_TOP`` | Top highlight | -+------------------+-------------------------------+ -| ``A_VERTICAL`` | Vertical highlight | -+------------------+-------------------------------+ -| ``A_CHARTEXT`` | Bit-mask to extract a | -| | character | -+------------------+-------------------------------+ ++------------------------+-------------------------------+ +| Attribute | Meaning | ++========================+===============================+ +| .. data:: A_ALTCHARSET | Alternate character set mode | ++------------------------+-------------------------------+ +| .. data:: A_BLINK | Blink mode | ++------------------------+-------------------------------+ +| .. data:: A_BOLD | Bold mode | ++------------------------+-------------------------------+ +| .. data:: A_DIM | Dim mode | ++------------------------+-------------------------------+ +| .. data:: A_INVIS | Invisible or blank mode | ++------------------------+-------------------------------+ +| .. data:: A_ITALIC | Italic mode | ++------------------------+-------------------------------+ +| .. data:: A_NORMAL | Normal attribute | ++------------------------+-------------------------------+ +| .. data:: A_PROTECT | Protected mode | ++------------------------+-------------------------------+ +| .. data:: A_REVERSE | Reverse background and | +| | foreground colors | ++------------------------+-------------------------------+ +| .. data:: A_STANDOUT | Standout mode | ++------------------------+-------------------------------+ +| .. data:: A_UNDERLINE | Underline mode | ++------------------------+-------------------------------+ +| .. data:: A_HORIZONTAL | Horizontal highlight | ++------------------------+-------------------------------+ +| .. data:: A_LEFT | Left highlight | ++------------------------+-------------------------------+ +| .. data:: A_LOW | Low highlight | ++------------------------+-------------------------------+ +| .. data:: A_RIGHT | Right highlight | ++------------------------+-------------------------------+ +| .. data:: A_TOP | Top highlight | ++------------------------+-------------------------------+ +| .. data:: A_VERTICAL | Vertical highlight | ++------------------------+-------------------------------+ .. versionadded:: 3.7 ``A_ITALIC`` was added. @@ -1394,220 +1398,220 @@ The exact constants available are system dependent. Several constants are available to extract corresponding attributes returned by some methods. -+------------------+-------------------------------+ -| Bit-mask | Meaning | -+==================+===============================+ -| ``A_ATTRIBUTES`` | Bit-mask to extract | -| | attributes | -+------------------+-------------------------------+ -| ``A_CHARTEXT`` | Bit-mask to extract a | -| | character | -+------------------+-------------------------------+ -| ``A_COLOR`` | Bit-mask to extract | -| | color-pair field information | -+------------------+-------------------------------+ ++-------------------------+-------------------------------+ +| Bit-mask | Meaning | ++=========================+===============================+ +| .. data:: A_ATTRIBUTES | Bit-mask to extract | +| | attributes | ++-------------------------+-------------------------------+ +| .. data:: A_CHARTEXT | Bit-mask to extract a | +| | character | ++-------------------------+-------------------------------+ +| .. data:: A_COLOR | Bit-mask to extract | +| | color-pair field information | ++-------------------------+-------------------------------+ Keys are referred to by integer constants with names starting with ``KEY_``. The exact keycaps available are system dependent. .. XXX this table is far too large! should it be alphabetized? -+-------------------+--------------------------------------------+ -| Key constant | Key | -+===================+============================================+ -| ``KEY_MIN`` | Minimum key value | -+-------------------+--------------------------------------------+ -| ``KEY_BREAK`` | Break key (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_DOWN`` | Down-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_UP`` | Up-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_LEFT`` | Left-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_RIGHT`` | Right-arrow | -+-------------------+--------------------------------------------+ -| ``KEY_HOME`` | Home key (upward+left arrow) | -+-------------------+--------------------------------------------+ -| ``KEY_BACKSPACE`` | Backspace (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_F0`` | Function keys. Up to 64 function keys are | -| | supported. | -+-------------------+--------------------------------------------+ -| ``KEY_Fn`` | Value of function key *n* | -+-------------------+--------------------------------------------+ -| ``KEY_DL`` | Delete line | -+-------------------+--------------------------------------------+ -| ``KEY_IL`` | Insert line | -+-------------------+--------------------------------------------+ -| ``KEY_DC`` | Delete character | -+-------------------+--------------------------------------------+ -| ``KEY_IC`` | Insert char or enter insert mode | -+-------------------+--------------------------------------------+ -| ``KEY_EIC`` | Exit insert char mode | -+-------------------+--------------------------------------------+ -| ``KEY_CLEAR`` | Clear screen | -+-------------------+--------------------------------------------+ -| ``KEY_EOS`` | Clear to end of screen | -+-------------------+--------------------------------------------+ -| ``KEY_EOL`` | Clear to end of line | -+-------------------+--------------------------------------------+ -| ``KEY_SF`` | Scroll 1 line forward | -+-------------------+--------------------------------------------+ -| ``KEY_SR`` | Scroll 1 line backward (reverse) | -+-------------------+--------------------------------------------+ -| ``KEY_NPAGE`` | Next page | -+-------------------+--------------------------------------------+ -| ``KEY_PPAGE`` | Previous page | -+-------------------+--------------------------------------------+ -| ``KEY_STAB`` | Set tab | -+-------------------+--------------------------------------------+ -| ``KEY_CTAB`` | Clear tab | -+-------------------+--------------------------------------------+ -| ``KEY_CATAB`` | Clear all tabs | -+-------------------+--------------------------------------------+ -| ``KEY_ENTER`` | Enter or send (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_SRESET`` | Soft (partial) reset (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_RESET`` | Reset or hard reset (unreliable) | -+-------------------+--------------------------------------------+ -| ``KEY_PRINT`` | Print | -+-------------------+--------------------------------------------+ -| ``KEY_LL`` | Home down or bottom (lower left) | -+-------------------+--------------------------------------------+ -| ``KEY_A1`` | Upper left of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_A3`` | Upper right of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_B2`` | Center of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_C1`` | Lower left of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_C3`` | Lower right of keypad | -+-------------------+--------------------------------------------+ -| ``KEY_BTAB`` | Back tab | -+-------------------+--------------------------------------------+ -| ``KEY_BEG`` | Beg (beginning) | -+-------------------+--------------------------------------------+ -| ``KEY_CANCEL`` | Cancel | -+-------------------+--------------------------------------------+ -| ``KEY_CLOSE`` | Close | -+-------------------+--------------------------------------------+ -| ``KEY_COMMAND`` | Cmd (command) | -+-------------------+--------------------------------------------+ -| ``KEY_COPY`` | Copy | -+-------------------+--------------------------------------------+ -| ``KEY_CREATE`` | Create | -+-------------------+--------------------------------------------+ -| ``KEY_END`` | End | -+-------------------+--------------------------------------------+ -| ``KEY_EXIT`` | Exit | -+-------------------+--------------------------------------------+ -| ``KEY_FIND`` | Find | -+-------------------+--------------------------------------------+ -| ``KEY_HELP`` | Help | -+-------------------+--------------------------------------------+ -| ``KEY_MARK`` | Mark | -+-------------------+--------------------------------------------+ -| ``KEY_MESSAGE`` | Message | -+-------------------+--------------------------------------------+ -| ``KEY_MOVE`` | Move | -+-------------------+--------------------------------------------+ -| ``KEY_NEXT`` | Next | -+-------------------+--------------------------------------------+ -| ``KEY_OPEN`` | Open | -+-------------------+--------------------------------------------+ -| ``KEY_OPTIONS`` | Options | -+-------------------+--------------------------------------------+ -| ``KEY_PREVIOUS`` | Prev (previous) | -+-------------------+--------------------------------------------+ -| ``KEY_REDO`` | Redo | -+-------------------+--------------------------------------------+ -| ``KEY_REFERENCE`` | Ref (reference) | -+-------------------+--------------------------------------------+ -| ``KEY_REFRESH`` | Refresh | -+-------------------+--------------------------------------------+ -| ``KEY_REPLACE`` | Replace | -+-------------------+--------------------------------------------+ -| ``KEY_RESTART`` | Restart | -+-------------------+--------------------------------------------+ -| ``KEY_RESUME`` | Resume | -+-------------------+--------------------------------------------+ -| ``KEY_SAVE`` | Save | -+-------------------+--------------------------------------------+ -| ``KEY_SBEG`` | Shifted Beg (beginning) | -+-------------------+--------------------------------------------+ -| ``KEY_SCANCEL`` | Shifted Cancel | -+-------------------+--------------------------------------------+ -| ``KEY_SCOMMAND`` | Shifted Command | -+-------------------+--------------------------------------------+ -| ``KEY_SCOPY`` | Shifted Copy | -+-------------------+--------------------------------------------+ -| ``KEY_SCREATE`` | Shifted Create | -+-------------------+--------------------------------------------+ -| ``KEY_SDC`` | Shifted Delete char | -+-------------------+--------------------------------------------+ -| ``KEY_SDL`` | Shifted Delete line | -+-------------------+--------------------------------------------+ -| ``KEY_SELECT`` | Select | -+-------------------+--------------------------------------------+ -| ``KEY_SEND`` | Shifted End | -+-------------------+--------------------------------------------+ -| ``KEY_SEOL`` | Shifted Clear line | -+-------------------+--------------------------------------------+ -| ``KEY_SEXIT`` | Shifted Exit | -+-------------------+--------------------------------------------+ -| ``KEY_SFIND`` | Shifted Find | -+-------------------+--------------------------------------------+ -| ``KEY_SHELP`` | Shifted Help | -+-------------------+--------------------------------------------+ -| ``KEY_SHOME`` | Shifted Home | -+-------------------+--------------------------------------------+ -| ``KEY_SIC`` | Shifted Input | -+-------------------+--------------------------------------------+ -| ``KEY_SLEFT`` | Shifted Left arrow | -+-------------------+--------------------------------------------+ -| ``KEY_SMESSAGE`` | Shifted Message | -+-------------------+--------------------------------------------+ -| ``KEY_SMOVE`` | Shifted Move | -+-------------------+--------------------------------------------+ -| ``KEY_SNEXT`` | Shifted Next | -+-------------------+--------------------------------------------+ -| ``KEY_SOPTIONS`` | Shifted Options | -+-------------------+--------------------------------------------+ -| ``KEY_SPREVIOUS`` | Shifted Prev | -+-------------------+--------------------------------------------+ -| ``KEY_SPRINT`` | Shifted Print | -+-------------------+--------------------------------------------+ -| ``KEY_SREDO`` | Shifted Redo | -+-------------------+--------------------------------------------+ -| ``KEY_SREPLACE`` | Shifted Replace | -+-------------------+--------------------------------------------+ -| ``KEY_SRIGHT`` | Shifted Right arrow | -+-------------------+--------------------------------------------+ -| ``KEY_SRSUME`` | Shifted Resume | -+-------------------+--------------------------------------------+ -| ``KEY_SSAVE`` | Shifted Save | -+-------------------+--------------------------------------------+ -| ``KEY_SSUSPEND`` | Shifted Suspend | -+-------------------+--------------------------------------------+ -| ``KEY_SUNDO`` | Shifted Undo | -+-------------------+--------------------------------------------+ -| ``KEY_SUSPEND`` | Suspend | -+-------------------+--------------------------------------------+ -| ``KEY_UNDO`` | Undo | -+-------------------+--------------------------------------------+ -| ``KEY_MOUSE`` | Mouse event has occurred | -+-------------------+--------------------------------------------+ -| ``KEY_RESIZE`` | Terminal resize event | -+-------------------+--------------------------------------------+ -| ``KEY_MAX`` | Maximum key value | -+-------------------+--------------------------------------------+ ++-------------------------+--------------------------------------------+ +| Key constant | Key | ++=========================+============================================+ +| .. data:: KEY_MIN | Minimum key value | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BREAK | Break key (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_DOWN | Down-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_UP | Up-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_LEFT | Left-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RIGHT | Right-arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_HOME | Home key (upward+left arrow) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BACKSPACE | Backspace (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_F0 | Function keys. Up to 64 function keys are | +| | supported. | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_Fn | Value of function key *n* | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_DL | Delete line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_IL | Insert line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_DC | Delete character | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_IC | Insert char or enter insert mode | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EIC | Exit insert char mode | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CLEAR | Clear screen | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EOS | Clear to end of screen | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EOL | Clear to end of line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SF | Scroll 1 line forward | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SR | Scroll 1 line backward (reverse) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_NPAGE | Next page | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_PPAGE | Previous page | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_STAB | Set tab | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CTAB | Clear tab | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CATAB | Clear all tabs | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_ENTER | Enter or send (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SRESET | Soft (partial) reset (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESET | Reset or hard reset (unreliable) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_PRINT | Print | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_LL | Home down or bottom (lower left) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_A1 | Upper left of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_A3 | Upper right of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_B2 | Center of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_C1 | Lower left of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_C3 | Lower right of keypad | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BTAB | Back tab | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_BEG | Beg (beginning) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CANCEL | Cancel | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CLOSE | Close | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_COMMAND | Cmd (command) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_COPY | Copy | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_CREATE | Create | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_END | End | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_EXIT | Exit | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_FIND | Find | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_HELP | Help | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MARK | Mark | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MESSAGE | Message | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MOVE | Move | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_NEXT | Next | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_OPEN | Open | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_OPTIONS | Options | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_PREVIOUS | Prev (previous) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REDO | Redo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REFERENCE | Ref (reference) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REFRESH | Refresh | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_REPLACE | Replace | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESTART | Restart | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESUME | Resume | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SAVE | Save | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SBEG | Shifted Beg (beginning) | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCANCEL | Shifted Cancel | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCOMMAND | Shifted Command | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCOPY | Shifted Copy | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SCREATE | Shifted Create | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SDC | Shifted Delete char | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SDL | Shifted Delete line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SELECT | Select | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SEND | Shifted End | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SEOL | Shifted Clear line | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SEXIT | Shifted Exit | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SFIND | Shifted Find | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SHELP | Shifted Help | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SHOME | Shifted Home | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SIC | Shifted Input | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SLEFT | Shifted Left arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SMESSAGE | Shifted Message | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SMOVE | Shifted Move | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SNEXT | Shifted Next | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SOPTIONS | Shifted Options | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SPREVIOUS | Shifted Prev | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SPRINT | Shifted Print | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SREDO | Shifted Redo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SREPLACE | Shifted Replace | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SRIGHT | Shifted Right arrow | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SRSUME | Shifted Resume | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SSAVE | Shifted Save | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SSUSPEND | Shifted Suspend | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SUNDO | Shifted Undo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_SUSPEND | Suspend | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_UNDO | Undo | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MOUSE | Mouse event has occurred | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_RESIZE | Terminal resize event | ++-------------------------+--------------------------------------------+ +| .. data:: KEY_MAX | Maximum key value | ++-------------------------+--------------------------------------------+ On VT100s and their software emulations, such as X terminal emulators, there are -normally at least four function keys (:const:`KEY_F1`, :const:`KEY_F2`, -:const:`KEY_F3`, :const:`KEY_F4`) available, and the arrow keys mapped to +normally at least four function keys (:const:`KEY_F1 <KEY_Fn>`, :const:`KEY_F2 <KEY_Fn>`, +:const:`KEY_F3 <KEY_Fn>`, :const:`KEY_F4 <KEY_Fn>`) available, and the arrow keys mapped to :const:`KEY_UP`, :const:`KEY_DOWN`, :const:`KEY_LEFT` and :const:`KEY_RIGHT` in the obvious way. If your machine has a PC keyboard, it is safe to expect arrow keys and twelve function keys (older PC keyboards may have only ten function @@ -1638,117 +1642,143 @@ falls back on a crude printable ASCII approximation. These are available only after :func:`initscr` has been called. -+------------------+------------------------------------------+ -| ACS code | Meaning | -+==================+==========================================+ -| ``ACS_BBSS`` | alternate name for upper right corner | -+------------------+------------------------------------------+ -| ``ACS_BLOCK`` | solid square block | -+------------------+------------------------------------------+ -| ``ACS_BOARD`` | board of squares | -+------------------+------------------------------------------+ -| ``ACS_BSBS`` | alternate name for horizontal line | -+------------------+------------------------------------------+ -| ``ACS_BSSB`` | alternate name for upper left corner | -+------------------+------------------------------------------+ -| ``ACS_BSSS`` | alternate name for top tee | -+------------------+------------------------------------------+ -| ``ACS_BTEE`` | bottom tee | -+------------------+------------------------------------------+ -| ``ACS_BULLET`` | bullet | -+------------------+------------------------------------------+ -| ``ACS_CKBOARD`` | checker board (stipple) | -+------------------+------------------------------------------+ -| ``ACS_DARROW`` | arrow pointing down | -+------------------+------------------------------------------+ -| ``ACS_DEGREE`` | degree symbol | -+------------------+------------------------------------------+ -| ``ACS_DIAMOND`` | diamond | -+------------------+------------------------------------------+ -| ``ACS_GEQUAL`` | greater-than-or-equal-to | -+------------------+------------------------------------------+ -| ``ACS_HLINE`` | horizontal line | -+------------------+------------------------------------------+ -| ``ACS_LANTERN`` | lantern symbol | -+------------------+------------------------------------------+ -| ``ACS_LARROW`` | left arrow | -+------------------+------------------------------------------+ -| ``ACS_LEQUAL`` | less-than-or-equal-to | -+------------------+------------------------------------------+ -| ``ACS_LLCORNER`` | lower left-hand corner | -+------------------+------------------------------------------+ -| ``ACS_LRCORNER`` | lower right-hand corner | -+------------------+------------------------------------------+ -| ``ACS_LTEE`` | left tee | -+------------------+------------------------------------------+ -| ``ACS_NEQUAL`` | not-equal sign | -+------------------+------------------------------------------+ -| ``ACS_PI`` | letter pi | -+------------------+------------------------------------------+ -| ``ACS_PLMINUS`` | plus-or-minus sign | -+------------------+------------------------------------------+ -| ``ACS_PLUS`` | big plus sign | -+------------------+------------------------------------------+ -| ``ACS_RARROW`` | right arrow | -+------------------+------------------------------------------+ -| ``ACS_RTEE`` | right tee | -+------------------+------------------------------------------+ -| ``ACS_S1`` | scan line 1 | -+------------------+------------------------------------------+ -| ``ACS_S3`` | scan line 3 | -+------------------+------------------------------------------+ -| ``ACS_S7`` | scan line 7 | -+------------------+------------------------------------------+ -| ``ACS_S9`` | scan line 9 | -+------------------+------------------------------------------+ -| ``ACS_SBBS`` | alternate name for lower right corner | -+------------------+------------------------------------------+ -| ``ACS_SBSB`` | alternate name for vertical line | -+------------------+------------------------------------------+ -| ``ACS_SBSS`` | alternate name for right tee | -+------------------+------------------------------------------+ -| ``ACS_SSBB`` | alternate name for lower left corner | -+------------------+------------------------------------------+ -| ``ACS_SSBS`` | alternate name for bottom tee | -+------------------+------------------------------------------+ -| ``ACS_SSSB`` | alternate name for left tee | -+------------------+------------------------------------------+ -| ``ACS_SSSS`` | alternate name for crossover or big plus | -+------------------+------------------------------------------+ -| ``ACS_STERLING`` | pound sterling | -+------------------+------------------------------------------+ -| ``ACS_TTEE`` | top tee | -+------------------+------------------------------------------+ -| ``ACS_UARROW`` | up arrow | -+------------------+------------------------------------------+ -| ``ACS_ULCORNER`` | upper left corner | -+------------------+------------------------------------------+ -| ``ACS_URCORNER`` | upper right corner | -+------------------+------------------------------------------+ -| ``ACS_VLINE`` | vertical line | -+------------------+------------------------------------------+ ++------------------------+------------------------------------------+ +| ACS code | Meaning | ++========================+==========================================+ +| .. data:: ACS_BBSS | alternate name for upper right corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_BLOCK | solid square block | ++------------------------+------------------------------------------+ +| .. data:: ACS_BOARD | board of squares | ++------------------------+------------------------------------------+ +| .. data:: ACS_BSBS | alternate name for horizontal line | ++------------------------+------------------------------------------+ +| .. data:: ACS_BSSB | alternate name for upper left corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_BSSS | alternate name for top tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_BTEE | bottom tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_BULLET | bullet | ++------------------------+------------------------------------------+ +| .. data:: ACS_CKBOARD | checker board (stipple) | ++------------------------+------------------------------------------+ +| .. data:: ACS_DARROW | arrow pointing down | ++------------------------+------------------------------------------+ +| .. data:: ACS_DEGREE | degree symbol | ++------------------------+------------------------------------------+ +| .. data:: ACS_DIAMOND | diamond | ++------------------------+------------------------------------------+ +| .. data:: ACS_GEQUAL | greater-than-or-equal-to | ++------------------------+------------------------------------------+ +| .. data:: ACS_HLINE | horizontal line | ++------------------------+------------------------------------------+ +| .. data:: ACS_LANTERN | lantern symbol | ++------------------------+------------------------------------------+ +| .. data:: ACS_LARROW | left arrow | ++------------------------+------------------------------------------+ +| .. data:: ACS_LEQUAL | less-than-or-equal-to | ++------------------------+------------------------------------------+ +| .. data:: ACS_LLCORNER | lower left-hand corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_LRCORNER | lower right-hand corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_LTEE | left tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_NEQUAL | not-equal sign | ++------------------------+------------------------------------------+ +| .. data:: ACS_PI | letter pi | ++------------------------+------------------------------------------+ +| .. data:: ACS_PLMINUS | plus-or-minus sign | ++------------------------+------------------------------------------+ +| .. data:: ACS_PLUS | big plus sign | ++------------------------+------------------------------------------+ +| .. data:: ACS_RARROW | right arrow | ++------------------------+------------------------------------------+ +| .. data:: ACS_RTEE | right tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_S1 | scan line 1 | ++------------------------+------------------------------------------+ +| .. data:: ACS_S3 | scan line 3 | ++------------------------+------------------------------------------+ +| .. data:: ACS_S7 | scan line 7 | ++------------------------+------------------------------------------+ +| .. data:: ACS_S9 | scan line 9 | ++------------------------+------------------------------------------+ +| .. data:: ACS_SBBS | alternate name for lower right corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_SBSB | alternate name for vertical line | ++------------------------+------------------------------------------+ +| .. data:: ACS_SBSS | alternate name for right tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSBB | alternate name for lower left corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSBS | alternate name for bottom tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSSB | alternate name for left tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_SSSS | alternate name for crossover or big plus | ++------------------------+------------------------------------------+ +| .. data:: ACS_STERLING | pound sterling | ++------------------------+------------------------------------------+ +| .. data:: ACS_TTEE | top tee | ++------------------------+------------------------------------------+ +| .. data:: ACS_UARROW | up arrow | ++------------------------+------------------------------------------+ +| .. data:: ACS_ULCORNER | upper left corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_URCORNER | upper right corner | ++------------------------+------------------------------------------+ +| .. data:: ACS_VLINE | vertical line | ++------------------------+------------------------------------------+ + +The following table lists mouse button constants used by :meth:`getmouse`: + ++----------------------------------+---------------------------------------------+ +| Mouse button constant | Meaning | ++==================================+=============================================+ +| .. data:: BUTTONn_PRESSED | Mouse button *n* pressed | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_RELEASED | Mouse button *n* released | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_CLICKED | Mouse button *n* clicked | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_DOUBLE_CLICKED | Mouse button *n* double clicked | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTONn_TRIPLE_CLICKED | Mouse button *n* triple clicked | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTON_SHIFT | Shift was down during button state change | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTON_CTRL | Control was down during button state change | ++----------------------------------+---------------------------------------------+ +| .. data:: BUTTON_ALT | Control was down during button state change | ++----------------------------------+---------------------------------------------+ + + .. versionchanged:: 3.10 + The ``BUTTON5_*`` constants are now exposed if they are provided by the + underlying curses library. The following table lists the predefined colors: -+-------------------+----------------------------+ -| Constant | Color | -+===================+============================+ -| ``COLOR_BLACK`` | Black | -+-------------------+----------------------------+ -| ``COLOR_BLUE`` | Blue | -+-------------------+----------------------------+ -| ``COLOR_CYAN`` | Cyan (light greenish blue) | -+-------------------+----------------------------+ -| ``COLOR_GREEN`` | Green | -+-------------------+----------------------------+ -| ``COLOR_MAGENTA`` | Magenta (purplish red) | -+-------------------+----------------------------+ -| ``COLOR_RED`` | Red | -+-------------------+----------------------------+ -| ``COLOR_WHITE`` | White | -+-------------------+----------------------------+ -| ``COLOR_YELLOW`` | Yellow | -+-------------------+----------------------------+ ++-------------------------+----------------------------+ +| Constant | Color | ++=========================+============================+ +| .. data:: COLOR_BLACK | Black | ++-------------------------+----------------------------+ +| .. data:: COLOR_BLUE | Blue | ++-------------------------+----------------------------+ +| .. data:: COLOR_CYAN | Cyan (light greenish blue) | ++-------------------------+----------------------------+ +| .. data:: COLOR_GREEN | Green | ++-------------------------+----------------------------+ +| .. data:: COLOR_MAGENTA | Magenta (purplish red) | ++-------------------------+----------------------------+ +| .. data:: COLOR_RED | Red | ++-------------------------+----------------------------+ +| .. data:: COLOR_WHITE | White | ++-------------------------+----------------------------+ +| .. data:: COLOR_YELLOW | Yellow | ++-------------------------+----------------------------+ :mod:`curses.textpad` --- Text input widget for curses programs @@ -1854,19 +1884,19 @@ You can instantiate a :class:`Textbox` object as follows: Move operations do nothing if the cursor is at an edge where the movement is not possible. The following synonyms are supported where possible: - +------------------------+------------------+ - | Constant | Keystroke | - +========================+==================+ - | :const:`KEY_LEFT` | :kbd:`Control-B` | - +------------------------+------------------+ - | :const:`KEY_RIGHT` | :kbd:`Control-F` | - +------------------------+------------------+ - | :const:`KEY_UP` | :kbd:`Control-P` | - +------------------------+------------------+ - | :const:`KEY_DOWN` | :kbd:`Control-N` | - +------------------------+------------------+ - | :const:`KEY_BACKSPACE` | :kbd:`Control-h` | - +------------------------+------------------+ + +--------------------------------+------------------+ + | Constant | Keystroke | + +================================+==================+ + | :const:`~curses.KEY_LEFT` | :kbd:`Control-B` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_RIGHT` | :kbd:`Control-F` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_UP` | :kbd:`Control-P` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_DOWN` | :kbd:`Control-N` | + +--------------------------------+------------------+ + | :const:`~curses.KEY_BACKSPACE` | :kbd:`Control-h` | + +--------------------------------+------------------+ All other keystrokes are treated as a command to insert the given character and move right (with line wrapping). From webhook-mailer at python.org Wed May 3 03:00:56 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Wed, 03 May 2023 07:00:56 -0000 Subject: [Python-checkins] gh-82012: Deprecate bitwise inversion (~) of bool (#103487) Message-ID: <mailman.122.1683097257.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fdb3ef8c0f94c7e55870a585dc6499aca46f9f90 commit: fdb3ef8c0f94c7e55870a585dc6499aca46f9f90 branch: main author: Tim Hoffmann <2836374+timhoffm at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-03T00:00:42-07:00 summary: gh-82012: Deprecate bitwise inversion (~) of bool (#103487) The bitwise inversion operator on bool returns the bitwise inversion of the underlying int value; i.e. `~True == -2` such that `bool(~True) == True`. It's a common pitfall that users mistake `~` as negation operator and actually want `not`. Supporting `~` is an artifact of bool inheriting from int. Since there is no real use-case for the current behavior, let's deprecate `~` on bool and later raise an error. This removes a potential source errors for users. Full reasoning: https://github.com/python/cpython/issues/82012#issuecomment-1258705971 Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst M Doc/library/functions.rst M Doc/library/stdtypes.rst M Doc/whatsnew/3.12.rst M Lib/test/test_bool.py M Objects/boolobject.c diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index a5e86ef0f9eb..085a11c3caa7 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -147,7 +147,7 @@ are always available. They are listed here in alphabetical order. or omitted, this returns ``False``; otherwise, it returns ``True``. The :class:`bool` class is a subclass of :class:`int` (see :ref:`typesnumeric`). It cannot be subclassed further. Its only instances are ``False`` and - ``True`` (see :ref:`bltin-boolean-values`). + ``True`` (see :ref:`typebool`). .. index:: pair: Boolean; type diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 2360472b31f1..f6662b4336c2 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -802,6 +802,39 @@ number, :class:`float`, or :class:`complex`:: hash_value = -2 return hash_value +.. _typebool: + +Boolean Type - :class:`bool` +============================ + +Booleans represent truth values. The :class:`bool` type has exactly two +constant instances: ``True`` and ``False``. + +.. index:: + single: False + single: True + pair: Boolean; values + +The built-in function :func:`bool` converts any value to a boolean, if the +value can be interpreted as a truth value (see section :ref:`truth` above). + +For logical operations, use the :ref:`boolean operators <boolean>` ``and``, +``or`` and ``not``. +When applying the bitwise operators ``&``, ``|``, ``^`` to two booleans, they +return a bool equivalent to the logical operations "and", "or", "xor". However, +the logical operators ``and``, ``or`` and ``!=`` should be preferred +over ``&``, ``|`` and ``^``. + +.. deprecated:: 3.12 + + The use of the bitwise inversion operator ``~`` is deprecated and will + raise an error in Python 3.14. + +:class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In +many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, respectively. +However, relying on this is discouraged; explicitly convert using :func:`int` +instead. + .. _typeiter: Iterator Types @@ -5394,27 +5427,6 @@ information. There is exactly one ``NotImplemented`` object. It is written as ``NotImplemented``. -.. _bltin-boolean-values: - -Boolean Values --------------- - -Boolean values are the two constant objects ``False`` and ``True``. They are -used to represent truth values (although other values can also be considered -false or true). In numeric contexts (for example when used as the argument to -an arithmetic operator), they behave like the integers 0 and 1, respectively. -The built-in function :func:`bool` can be used to convert any value to a -Boolean, if the value can be interpreted as a truth value (see section -:ref:`truth` above). - -.. index:: - single: False - single: True - pair: Boolean; values - -They are written as ``False`` and ``True``, respectively. - - .. _typesinternal: Internal Objects diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a3fce7ccacf7..5f8a1f08026d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -710,6 +710,12 @@ Deprecated replaced by :data:`calendar.Month.JANUARY` and :data:`calendar.Month.FEBRUARY`. (Contributed by Prince Roshan in :gh:`103636`.) +* The bitwise inversion operator (``~``) on bool is deprecated. It will throw an + error in Python 3.14. Use ``not`` for logical negation of bools instead. + In the rare case that you really need the bitwise inversion of the underlying + ``int``, convert to int explicitly with ``~int(x)``. (Contributed by Tim Hoffmann + in :gh:`103487`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Lib/test/test_bool.py b/Lib/test/test_bool.py index 916e22a527a8..34ecb45f161d 100644 --- a/Lib/test/test_bool.py +++ b/Lib/test/test_bool.py @@ -58,8 +58,22 @@ def test_math(self): self.assertEqual(-True, -1) self.assertEqual(abs(True), 1) self.assertIsNot(abs(True), True) - self.assertEqual(~False, -1) - self.assertEqual(~True, -2) + with self.assertWarns(DeprecationWarning): + # We need to put the bool in a variable, because the constant + # ~False is evaluated at compile time due to constant folding; + # consequently the DeprecationWarning would be issued during + # module loading and not during test execution. + false = False + self.assertEqual(~false, -1) + with self.assertWarns(DeprecationWarning): + # also check that the warning is issued in case of constant + # folding at compile time + self.assertEqual(eval("~False"), -1) + with self.assertWarns(DeprecationWarning): + true = True + self.assertEqual(~true, -2) + with self.assertWarns(DeprecationWarning): + self.assertEqual(eval("~True"), -2) self.assertEqual(False+2, 2) self.assertEqual(True+2, 3) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst new file mode 100644 index 000000000000..819a2359bf6f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst @@ -0,0 +1,5 @@ +The bitwise inversion operator (``~``) on bool is deprecated. +It returns the bitwise inversion of the underlying ``int`` representation such that +``bool(~True) == True``, which can be confusing. Use ``not`` for logical negation +of bools. In the rare case that you really need the bitwise inversion of the underlying ``int``, +convert to int explicitly ``~int(x)``. diff --git a/Objects/boolobject.c b/Objects/boolobject.c index 597a76fa5cb1..0300f7bb4e3d 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -73,6 +73,22 @@ bool_vectorcall(PyObject *type, PyObject * const*args, /* Arithmetic operations redefined to return bool if both args are bool. */ +static PyObject * +bool_invert(PyObject *v) +{ + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "Bitwise inversion '~' on bool is deprecated. This " + "returns the bitwise inversion of the underlying int " + "object and is usually not what you expect from negating " + "a bool. Use the 'not' operator for boolean negation or " + "~int(x) if you really want the bitwise inversion of the " + "underlying int.", + 1) < 0) { + return NULL; + } + return PyLong_Type.tp_as_number->nb_invert(v); +} + static PyObject * bool_and(PyObject *a, PyObject *b) { @@ -119,7 +135,7 @@ static PyNumberMethods bool_as_number = { 0, /* nb_positive */ 0, /* nb_absolute */ 0, /* nb_bool */ - 0, /* nb_invert */ + (unaryfunc)bool_invert, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ bool_and, /* nb_and */ From webhook-mailer at python.org Wed May 3 03:20:07 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Wed, 03 May 2023 07:20:07 -0000 Subject: [Python-checkins] gh-104078: Improve performance of PyObject_HasAttrString (#104079) Message-ID: <mailman.123.1683098408.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8d34031068ece75667260f6526d3165efe34e054 commit: 8d34031068ece75667260f6526d3165efe34e054 branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-03T00:20:00-07:00 summary: gh-104078: Improve performance of PyObject_HasAttrString (#104079) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst M Objects/object.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst new file mode 100644 index 000000000000..6f24529bac3e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst @@ -0,0 +1 @@ +Improve the performance of :c:func:`PyObject_HasAttrString` diff --git a/Objects/object.c b/Objects/object.c index ee8690101d3c..c6ef59281648 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -918,13 +918,24 @@ PyObject_GetAttrString(PyObject *v, const char *name) int PyObject_HasAttrString(PyObject *v, const char *name) { - PyObject *res = PyObject_GetAttrString(v, name); - if (res != NULL) { - Py_DECREF(res); - return 1; + if (Py_TYPE(v)->tp_getattr != NULL) { + PyObject *res = (*Py_TYPE(v)->tp_getattr)(v, (char*)name); + if (res != NULL) { + Py_DECREF(res); + return 1; + } + PyErr_Clear(); + return 0; } - PyErr_Clear(); - return 0; + + PyObject *attr_name = PyUnicode_FromString(name); + if (attr_name == NULL) { + PyErr_Clear(); + return 0; + } + int ok = PyObject_HasAttr(v, attr_name); + Py_DECREF(attr_name); + return ok; } int From webhook-mailer at python.org Wed May 3 05:10:17 2023 From: webhook-mailer at python.org (Yhg1s) Date: Wed, 03 May 2023 09:10:17 -0000 Subject: [Python-checkins] GH-84976: Move Lib/datetime.py to Lib/_pydatetime Message-ID: <mailman.124.1683105019.13550.python-checkins@python.org> https://github.com/python/cpython/commit/65c4a2b326086875ecbedf032204d1ff24ba74d7 commit: 65c4a2b326086875ecbedf032204d1ff24ba74d7 branch: main author: Paul Ganssle <git at m.ganssle.io> committer: Yhg1s <thomas at python.org> date: 2023-05-03T03:09:45-06:00 summary: GH-84976: Move Lib/datetime.py to Lib/_pydatetime This breaks the tests, but we are keeping it as a separate commit so that the move operation and editing of the moved files are separate, for a cleaner history. files: A Lib/_pydatetime.py D Lib/datetime.py M Lib/test/datetimetester.py M Lib/test/test_datetime.py M Python/stdlib_module_names.h diff --git a/Lib/datetime.py b/Lib/_pydatetime.py similarity index 100% rename from Lib/datetime.py rename to Lib/_pydatetime.py diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index c5eb6e7f1643..fb07d2a5ad9b 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -39,6 +39,10 @@ # Needed by test_datetime import _strptime +try: + import _pydatetime +except ImportError: + pass # pickle_loads = {pickle.loads, pickle._loads} @@ -92,7 +96,7 @@ def test_divide_and_round(self): if '_Fast' in self.__class__.__name__: self.skipTest('Only run for Pure Python implementation') - dar = datetime_module._divide_and_round + dar = _pydatetime._divide_and_round self.assertEqual(dar(-10, -3), 3) self.assertEqual(dar(5, -2), -2) diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py index 7f9094fa7bd4..3859733a4fe6 100644 --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -8,10 +8,12 @@ def load_tests(loader, tests, pattern): try: - pure_tests = import_fresh_module(TESTS, fresh=['datetime', '_strptime'], - blocked=['_datetime']) - fast_tests = import_fresh_module(TESTS, fresh=['datetime', - '_datetime', '_strptime']) + pure_tests = import_fresh_module(TESTS, + fresh=['datetime', '_pydatetime', '_strptime'], + blocked=['_datetime']) + fast_tests = import_fresh_module(TESTS, + fresh=['datetime', '_strptime'], + blocked=['_pydatetime']) finally: # XXX: import_fresh_module() is supposed to leave sys.module cache untouched, # XXX: but it does not, so we have to cleanup ourselves. @@ -42,6 +44,8 @@ def setUpClass(cls_, module=module): cls_._save_sys_modules = sys.modules.copy() sys.modules[TESTS] = module sys.modules['datetime'] = module.datetime_module + if hasattr(module, '_pydatetime'): + sys.modules['_pydatetime'] = module._pydatetime sys.modules['_strptime'] = module._strptime @classmethod def tearDownClass(cls_): diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 27f42e5202e5..ed4a0ac2dd32 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -56,6 +56,7 @@ static const char* _Py_stdlib_module_names[] = { "_posixshmem", "_posixsubprocess", "_py_abc", +"_pydatetime", "_pydecimal", "_pyio", "_pylong", From webhook-mailer at python.org Wed May 3 05:51:54 2023 From: webhook-mailer at python.org (markshannon) Date: Wed, 03 May 2023 09:51:54 -0000 Subject: [Python-checkins] gh-103845: Remove line & instruction instrumentations before adding them back (GH-103851) Message-ID: <mailman.125.1683107515.13550.python-checkins@python.org> https://github.com/python/cpython/commit/bcea36f8db9ad4fd542b38997e065987e829cb9f commit: bcea36f8db9ad4fd542b38997e065987e829cb9f branch: main author: Tian Gao <gaogaotiantian at hotmail.com> committer: markshannon <mark at hotpy.org> date: 2023-05-03T10:51:47+01:00 summary: gh-103845: Remove line & instruction instrumentations before adding them back (GH-103851) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst 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 738ace923cc5..a493bb54d70d 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -876,6 +876,42 @@ def func3(): ('instruction', 'func3', 34), ('line', 'check_events', 11)]) + def test_with_restart(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)]) + + sys.monitoring.restart_events() + + 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)]) + class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase): def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst new file mode 100644 index 000000000000..e8434854cde6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst @@ -0,0 +1 @@ +Remove both line and instruction instrumentation before adding new ones for monitoring, to avoid newly added instrumentation being removed immediately. diff --git a/Python/instrumentation.c b/Python/instrumentation.c index c5bbbdacbb85..a14232406096 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1477,25 +1477,25 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) } } } - uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; + + // GH-103845: We need to remove both the line and instruction instrumentation before + // adding new ones, otherwise we may remove the newly added instrumentation. + uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE]; - if (new_line_tools | removed_line_tools) { + uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; + + if (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) { + if (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) { @@ -1505,6 +1505,31 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) if (removed_per_instruction_tools) { remove_per_instruction_tools(code, i, removed_per_instruction_tools); } + i += instruction_length(code, i); + } + } + + uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; + uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; + + if (new_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 (new_line_tools) { + add_line_tools(code, i, new_line_tools); + } + } + i += instruction_length(code, i); + } + } + if (new_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 (new_per_instruction_tools) { add_per_instruction_tools(code, i, new_per_instruction_tools); } From webhook-mailer at python.org Wed May 3 07:55:30 2023 From: webhook-mailer at python.org (warsaw) Date: Wed, 03 May 2023 11:55:30 -0000 Subject: [Python-checkins] gh-98040: Remove find_loader, find_module and other deprecated APIs (#98059) Message-ID: <mailman.126.1683114931.13550.python-checkins@python.org> https://github.com/python/cpython/commit/326997829d02458246dfd5b6d03297e2418bde52 commit: 326997829d02458246dfd5b6d03297e2418bde52 branch: main author: Barry Warsaw <barry at python.org> committer: warsaw <barry at python.org> date: 2023-05-03T04:55:22-07:00 summary: gh-98040: Remove find_loader, find_module and other deprecated APIs (#98059) * Remove deprecated classes from pkgutil * Remove some other PEP 302 obsolescence * Use find_spec instead of load_module * Remove more tests of PEP 302 obsolete APIs * Remove another bunch of tests using obsolete load_modules() * Remove deleted names from __all__ * Remove obsolete footnote * imp is removed * Remove `imp` from generated stdlib names * What's new and blurb * Update zipimport documentation for the removed methods * Fix some Windows tests * Remove any test (or part of a test) that references `find_module()`. * Use assertIsNone() / assertIsNotNone() consistently. * Update Doc/reference/import.rst * We don't need pkgutil._get_spec() any more either * test.test_importlib.fixtures.NullFinder * ...BadLoaderFinder.find_module * ...test_api.InvalidatingNullFinder.find_module * ...test.test_zipimport test of z.find_module * Suppress cross-references to find_loader and find_module * Suppress cross-references to Finder * Suppress cross-references to pkgutil.ImpImporter and pkgutil.ImpLoader --------- Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Adam Turner <9087854+aa-turner at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst M Doc/library/importlib.rst M Doc/library/pkgutil.rst M Doc/library/sys.rst M Doc/library/zipimport.rst M Doc/reference/import.rst M Doc/whatsnew/2.3.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.4.rst M Doc/whatsnew/3.7.rst M Lib/importlib/__init__.py M Lib/importlib/_bootstrap.py M Lib/importlib/_bootstrap_external.py M Lib/importlib/abc.py M Lib/pkgutil.py M Lib/pydoc.py M Lib/test/test_importlib/builtin/test_finder.py M Lib/test/test_importlib/extension/test_path_hook.py M Lib/test/test_importlib/fixtures.py M Lib/test/test_importlib/frozen/test_finder.py M Lib/test/test_importlib/frozen/test_loader.py M Lib/test/test_importlib/import_/test___loader__.py M Lib/test/test_importlib/import_/test___package__.py M Lib/test/test_importlib/import_/test_api.py M Lib/test/test_importlib/import_/test_caching.py M Lib/test/test_importlib/import_/test_meta_path.py M Lib/test/test_importlib/import_/test_path.py M Lib/test/test_importlib/source/test_case_sensitivity.py M Lib/test/test_importlib/source/test_finder.py M Lib/test/test_importlib/source/test_path_hook.py M Lib/test/test_importlib/test_abc.py M Lib/test/test_importlib/test_api.py M Lib/test/test_importlib/test_windows.py M Lib/test/test_importlib/util.py M Lib/test/test_pkgutil.py M Lib/test/test_zipimport.py diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 89efa64c6b52..65aaad0df9ee 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -127,28 +127,6 @@ Functions .. versionchanged:: 3.3 Parent packages are automatically imported. -.. function:: find_loader(name, path=None) - - Find the loader for a module, optionally within the specified *path*. If the - module is in :attr:`sys.modules`, then ``sys.modules[name].__loader__`` is - returned (unless the loader would be ``None`` or is not set, in which case - :exc:`ValueError` is raised). Otherwise a search using :attr:`sys.meta_path` - is done. ``None`` is returned if no loader is found. - - A dotted name does not have its parents implicitly imported as that requires - loading them and that may not be desired. To properly import a submodule you - will need to import all parent packages of the submodule and use the correct - argument to *path*. - - .. versionadded:: 3.3 - - .. versionchanged:: 3.4 - If ``__loader__`` is not set, raise :exc:`ValueError`, just like when the - attribute is set to ``None``. - - .. deprecated:: 3.4 - Use :func:`importlib.util.find_spec` instead. - .. function:: invalidate_caches() Invalidate the internal caches of finders stored at @@ -247,7 +225,6 @@ are also provided to help in implementing the core ABCs. ABC hierarchy:: object - +-- Finder (deprecated) +-- MetaPathFinder +-- PathEntryFinder +-- Loader @@ -258,28 +235,6 @@ ABC hierarchy:: +-- SourceLoader -.. class:: Finder - - An abstract base class representing a :term:`finder`. - - .. deprecated:: 3.3 - Use :class:`MetaPathFinder` or :class:`PathEntryFinder` instead. - - .. abstractmethod:: find_module(fullname, path=None) - - An abstract method for finding a :term:`loader` for the specified - module. Originally specified in :pep:`302`, this method was meant - for use in :data:`sys.meta_path` and in the path-based import subsystem. - - .. versionchanged:: 3.4 - Returns ``None`` when called instead of raising - :exc:`NotImplementedError`. - - .. deprecated:: 3.10 - Implement :meth:`MetaPathFinder.find_spec` or - :meth:`PathEntryFinder.find_spec` instead. - - .. class:: MetaPathFinder An abstract base class representing a :term:`meta path finder`. @@ -287,7 +242,7 @@ ABC hierarchy:: .. versionadded:: 3.3 .. versionchanged:: 3.10 - No longer a subclass of :class:`Finder`. + No longer a subclass of :class:`!Finder`. .. method:: find_spec(fullname, path, target=None) @@ -303,25 +258,6 @@ ABC hierarchy:: .. versionadded:: 3.4 - .. method:: find_module(fullname, path) - - A legacy method for finding a :term:`loader` for the specified - module. If this is a top-level import, *path* will be ``None``. - Otherwise, this is a search for a subpackage or module and *path* - will be the value of :attr:`__path__` from the parent - package. If a loader cannot be found, ``None`` is returned. - - If :meth:`find_spec` is defined, backwards-compatible functionality is - provided. - - .. versionchanged:: 3.4 - Returns ``None`` when called instead of raising - :exc:`NotImplementedError`. Can use :meth:`find_spec` to provide - functionality. - - .. deprecated:: 3.4 - Use :meth:`find_spec` instead. - .. method:: invalidate_caches() An optional method which, when called, should invalidate any internal @@ -342,7 +278,7 @@ ABC hierarchy:: .. versionadded:: 3.3 .. versionchanged:: 3.10 - No longer a subclass of :class:`Finder`. + No longer a subclass of :class:`!Finder`. .. method:: find_spec(fullname, target=None) @@ -356,36 +292,6 @@ ABC hierarchy:: .. versionadded:: 3.4 - .. method:: find_loader(fullname) - - A legacy method for finding a :term:`loader` for the specified - module. Returns a 2-tuple of ``(loader, portion)`` where ``portion`` - is a sequence of file system locations contributing to part of a namespace - package. The loader may be ``None`` while specifying ``portion`` to - signify the contribution of the file system locations to a namespace - package. An empty list can be used for ``portion`` to signify the loader - is not part of a namespace package. If ``loader`` is ``None`` and - ``portion`` is the empty list then no loader or location for a namespace - package were found (i.e. failure to find anything for the module). - - If :meth:`find_spec` is defined then backwards-compatible functionality is - provided. - - .. versionchanged:: 3.4 - Returns ``(None, [])`` instead of raising :exc:`NotImplementedError`. - Uses :meth:`find_spec` when available to provide functionality. - - .. deprecated:: 3.4 - Use :meth:`find_spec` instead. - - .. method:: find_module(fullname) - - A concrete implementation of :meth:`Finder.find_module` which is - equivalent to ``self.find_loader(fullname)[0]``. - - .. deprecated:: 3.4 - Use :meth:`find_spec` instead. - .. method:: invalidate_caches() An optional method which, when called, should invalidate any internal @@ -881,13 +787,6 @@ find and load modules. is no longer valid then ``None`` is returned but no value is cached in :data:`sys.path_importer_cache`. - .. classmethod:: find_module(fullname, path=None) - - A legacy wrapper around :meth:`find_spec`. - - .. deprecated:: 3.4 - Use :meth:`find_spec` instead. - .. classmethod:: invalidate_caches() Calls :meth:`importlib.abc.PathEntryFinder.invalidate_caches` on all @@ -938,13 +837,6 @@ find and load modules. .. versionadded:: 3.4 - .. method:: find_loader(fullname) - - Attempt to find the loader to handle *fullname* within :attr:`path`. - - .. deprecated:: 3.10 - Use :meth:`find_spec` instead. - .. method:: invalidate_caches() Clear out the internal cache. diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index 64e617b82b48..98e6e294af0c 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -48,33 +48,6 @@ support. this function to raise an exception (in line with :func:`os.path.isdir` behavior). - -.. class:: ImpImporter(dirname=None) - - :pep:`302` Finder that wraps Python's "classic" import algorithm. - - If *dirname* is a string, a :pep:`302` finder is created that searches that - directory. If *dirname* is ``None``, a :pep:`302` finder is created that - searches the current :data:`sys.path`, plus any modules that are frozen or - built-in. - - Note that :class:`ImpImporter` does not currently support being used by - placement on :data:`sys.meta_path`. - - .. deprecated:: 3.3 - This emulation is no longer needed, as the standard import mechanism - is now fully :pep:`302` compliant and available in :mod:`importlib`. - - -.. class:: ImpLoader(fullname, file, filename, etc) - - :term:`Loader <loader>` that wraps Python's "classic" import algorithm. - - .. deprecated:: 3.3 - This emulation is no longer needed, as the standard import mechanism - is now fully :pep:`302` compliant and available in :mod:`importlib`. - - .. function:: find_loader(fullname) Retrieve a module :term:`loader` for the given *fullname*. diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 95ad243bdde3..57a0d0a1258c 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1177,7 +1177,7 @@ always available. :term:`Module specs <module spec>` were introduced in Python 3.4, by :pep:`451`. Earlier versions of Python looked for a method called - :meth:`~importlib.abc.MetaPathFinder.find_module`. + :meth:`!find_module`. This is still called as a fallback if a :data:`meta_path` entry doesn't have a :meth:`~importlib.abc.MetaPathFinder.find_spec` method. diff --git a/Doc/library/zipimport.rst b/Doc/library/zipimport.rst index fe1adcae163c..11d19e8c863e 100644 --- a/Doc/library/zipimport.rst +++ b/Doc/library/zipimport.rst @@ -74,6 +74,11 @@ zipimporter Objects :exc:`ZipImportError` is raised if *archivepath* doesn't point to a valid ZIP archive. + .. versionchanged:: 3.12 + + Methods ``find_loader()`` and ``find_module()``, deprecated in 3.10 are + now removed. Use :meth:`find_spec` instead. + .. method:: create_module(spec) Implementation of :meth:`importlib.abc.Loader.create_module` that returns @@ -89,28 +94,6 @@ zipimporter Objects .. versionadded:: 3.10 - .. method:: find_loader(fullname, path=None) - - An implementation of :meth:`importlib.abc.PathEntryFinder.find_loader`. - - .. deprecated:: 3.10 - - Use :meth:`find_spec` instead. - - - .. method:: find_module(fullname, path=None) - - Search for a module specified by *fullname*. *fullname* must be the fully - qualified (dotted) module name. It returns the zipimporter instance itself - if the module was found, or :const:`None` if it wasn't. The optional - *path* argument is ignored---it's there for compatibility with the - importer protocol. - - .. deprecated:: 3.10 - - Use :meth:`find_spec` instead. - - .. method:: find_spec(fullname, target=None) An implementation of :meth:`importlib.abc.PathEntryFinder.find_spec`. diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 57eb5403243e..8f30181ae0a1 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -324,15 +324,18 @@ modules, and one that knows how to import modules from an :term:`import path` .. versionchanged:: 3.4 The :meth:`~importlib.abc.MetaPathFinder.find_spec` method of meta path - finders replaced :meth:`~importlib.abc.MetaPathFinder.find_module`, which + finders replaced :meth:`!find_module`, which is now deprecated. While it will continue to work without change, the import machinery will try it only if the finder does not implement ``find_spec()``. .. versionchanged:: 3.10 - Use of :meth:`~importlib.abc.MetaPathFinder.find_module` by the import system + Use of :meth:`!find_module` by the import system now raises :exc:`ImportWarning`. +.. versionchanged:: 3.12 + ``find_module()`` has been removed. Use :meth:`find_spec` instead. + Loading ======= @@ -837,7 +840,7 @@ stores finder objects rather than being limited to :term:`importer` objects). In this way, the expensive search for a particular :term:`path entry` location's :term:`path entry finder` need only be done once. User code is free to remove cache entries from :data:`sys.path_importer_cache` forcing -the path based finder to perform the path entry search again [#fnpic]_. +the path based finder to perform the path entry search again. If the path entry is not present in the cache, the path based finder iterates over every callable in :data:`sys.path_hooks`. Each of the :term:`path entry @@ -887,13 +890,13 @@ module. ``find_spec()`` returns a fully populated spec for the module. This spec will always have "loader" set (with one exception). To indicate to the import machinery that the spec represents a namespace -:term:`portion`, the path entry finder sets "submodule_search_locations" to +:term:`portion`, the path entry finder sets ``submodule_search_locations`` to a list containing the portion. .. versionchanged:: 3.4 :meth:`~importlib.abc.PathEntryFinder.find_spec` replaced - :meth:`~importlib.abc.PathEntryFinder.find_loader` and - :meth:`~importlib.abc.PathEntryFinder.find_module`, both of which + :meth:`!find_loader` and + :meth:`!find_module`, both of which are now deprecated, but will be used if ``find_spec()`` is not defined. Older path entry finders may implement one of these two deprecated methods @@ -901,7 +904,7 @@ a list containing the portion. sake of backward compatibility. However, if ``find_spec()`` is implemented on the path entry finder, the legacy methods are ignored. - :meth:`~importlib.abc.PathEntryFinder.find_loader` takes one argument, the + :meth:`!find_loader` takes one argument, the fully qualified name of the module being imported. ``find_loader()`` returns a 2-tuple where the first item is the loader and the second item is a namespace :term:`portion`. @@ -920,10 +923,13 @@ a list containing the portion. ``find_loader()`` in preference to ``find_module()``. .. versionchanged:: 3.10 - Calls to :meth:`~importlib.abc.PathEntryFinder.find_module` and - :meth:`~importlib.abc.PathEntryFinder.find_loader` by the import + Calls to :meth:`!find_module` and + :meth:`!find_loader` by the import system will raise :exc:`ImportWarning`. +.. versionchanged:: 3.12 + ``find_module()`` and ``find_loader()`` have been removed. + Replacing the standard import system ==================================== @@ -1045,8 +1051,8 @@ The original specification for :data:`sys.meta_path` was :pep:`302`, with subsequent extension in :pep:`420`. :pep:`420` introduced :term:`namespace packages <namespace package>` for -Python 3.3. :pep:`420` also introduced the :meth:`find_loader` protocol as an -alternative to :meth:`find_module`. +Python 3.3. :pep:`420` also introduced the :meth:`!find_loader` protocol as an +alternative to :meth:`!find_module`. :pep:`366` describes the addition of the ``__package__`` attribute for explicit relative imports in main modules. @@ -1073,9 +1079,3 @@ methods to finders and loaders. module may replace itself in :data:`sys.modules`. This is implementation-specific behavior that is not guaranteed to work in other Python implementations. - -.. [#fnpic] In legacy code, it is possible to find instances of - :class:`imp.NullImporter` in the :data:`sys.path_importer_cache`. It - is recommended that code be changed to use ``None`` instead. See - :ref:`portingpythoncode` for more details. Note that the ``imp`` module - was removed in Python 3.12. diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index af489d7cb45c..4eb864f5092d 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -728,7 +728,7 @@ module: Importer objects must have a single method, ``find_module(fullname, path=None)``. *fullname* will be a module or package name, e.g. ``string`` or -``distutils.core``. :meth:`find_module` must return a loader object that has a +``distutils.core``. :meth:`!find_module` must return a loader object that has a single method, ``load_module(fullname)``, that creates and returns the corresponding module object. diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index f6a48ed2680c..44c8fa1e9eb2 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1608,7 +1608,7 @@ Deprecated * Starting in this release, there will be a concerted effort to begin cleaning up old import semantics that were kept for Python 2.7 compatibility. Specifically, - :meth:`~importlib.abc.PathEntryFinder.find_loader`/:meth:`~importlib.abc.Finder.find_module` + :meth:`!find_loader`/:meth:`!find_module` (superseded by :meth:`~importlib.abc.Finder.find_spec`), :meth:`~importlib.abc.Loader.load_module` (superseded by :meth:`~importlib.abc.Loader.exec_module`), @@ -1645,8 +1645,8 @@ Deprecated :meth:`~importlib.abc.Loader.exec_module` is preferred. (Contributed by Brett Cannon in :issue:`26131`.) -* The use of :meth:`importlib.abc.MetaPathFinder.find_module` and - :meth:`importlib.abc.PathEntryFinder.find_module` by the import system now +* The use of :meth:`!importlib.abc.MetaPathFinder.find_module` and + :meth:`!importlib.abc.PathEntryFinder.find_module` by the import system now trigger an :exc:`ImportWarning` as :meth:`importlib.abc.MetaPathFinder.find_spec` and :meth:`importlib.abc.PathEntryFinder.find_spec` @@ -1654,40 +1654,40 @@ Deprecated :func:`importlib.util.spec_from_loader` to help in porting. (Contributed by Brett Cannon in :issue:`42134`.) -* The use of :meth:`importlib.abc.PathEntryFinder.find_loader` by the import +* The use of :meth:`!importlib.abc.PathEntryFinder.find_loader` by the import system now triggers an :exc:`ImportWarning` as :meth:`importlib.abc.PathEntryFinder.find_spec` is preferred. You can use :func:`importlib.util.spec_from_loader` to help in porting. (Contributed by Brett Cannon in :issue:`43672`.) * The various implementations of - :meth:`importlib.abc.MetaPathFinder.find_module` ( - :meth:`importlib.machinery.BuiltinImporter.find_module`, - :meth:`importlib.machinery.FrozenImporter.find_module`, - :meth:`importlib.machinery.WindowsRegistryFinder.find_module`, - :meth:`importlib.machinery.PathFinder.find_module`, - :meth:`importlib.abc.MetaPathFinder.find_module` ), - :meth:`importlib.abc.PathEntryFinder.find_module` ( - :meth:`importlib.machinery.FileFinder.find_module` ), and - :meth:`importlib.abc.PathEntryFinder.find_loader` ( - :meth:`importlib.machinery.FileFinder.find_loader` ) + :meth:`!importlib.abc.MetaPathFinder.find_module` ( + :meth:`!importlib.machinery.BuiltinImporter.find_module`, + :meth:`!importlib.machinery.FrozenImporter.find_module`, + :meth:`!importlib.machinery.WindowsRegistryFinder.find_module`, + :meth:`!importlib.machinery.PathFinder.find_module`, + :meth:`!importlib.abc.MetaPathFinder.find_module` ), + :meth:`!importlib.abc.PathEntryFinder.find_module` ( + :meth:`!importlib.machinery.FileFinder.find_module` ), and + :meth:`!importlib.abc.PathEntryFinder.find_loader` ( + :meth:`!importlib.machinery.FileFinder.find_loader` ) now raise :exc:`DeprecationWarning` and are slated for removal in Python 3.12 (previously they were documented as deprecated in Python 3.4). (Contributed by Brett Cannon in :issue:`42135`.) -* :class:`importlib.abc.Finder` is deprecated (including its sole method, - :meth:`~importlib.abc.Finder.find_module`). Both +* :class:`!importlib.abc.Finder` is deprecated (including its sole method, + :meth:`!find_module`). Both :class:`importlib.abc.MetaPathFinder` and :class:`importlib.abc.PathEntryFinder` no longer inherit from the class. Users should inherit from one of these two classes as appropriate instead. (Contributed by Brett Cannon in :issue:`42135`.) -* The deprecations of :mod:`imp`, :func:`importlib.find_loader`, +* The deprecations of :mod:`imp`, :func:`!importlib.find_loader`, :func:`importlib.util.set_package_wrapper`, :func:`importlib.util.set_loader_wrapper`, :func:`importlib.util.module_for_loader`, - :class:`pkgutil.ImpImporter`, and - :class:`pkgutil.ImpLoader` have all been updated to list Python 3.12 as the + :class:`!pkgutil.ImpImporter`, and + :class:`!pkgutil.ImpLoader` have all been updated to list Python 3.12 as the slated version of removal (they began raising :exc:`DeprecationWarning` in previous versions of Python). (Contributed by Brett Cannon in :issue:`43720`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 6b591d5e184e..918a6824618c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1876,24 +1876,24 @@ C APIs pending removal are * The :class:`typing.io <typing.IO>` namespace * The :class:`typing.re <typing.Pattern>` namespace * :func:`!cgi.log` -* :func:`importlib.find_loader` +* :func:`!importlib.find_loader` * :meth:`importlib.abc.Loader.module_repr` -* :meth:`importlib.abc.MetaPathFinder.find_module` -* :meth:`importlib.abc.PathEntryFinder.find_loader` -* :meth:`importlib.abc.PathEntryFinder.find_module` +* :meth:`!importlib.abc.MetaPathFinder.find_module` +* :meth:`!importlib.abc.PathEntryFinder.find_loader` +* :meth:`!importlib.abc.PathEntryFinder.find_module` * :meth:`!importlib.machinery.BuiltinImporter.find_module` * :meth:`!importlib.machinery.BuiltinLoader.module_repr` * :meth:`!importlib.machinery.FileFinder.find_loader` * :meth:`!importlib.machinery.FileFinder.find_module` * :meth:`!importlib.machinery.FrozenImporter.find_module` * :meth:`!importlib.machinery.FrozenLoader.module_repr` -* :meth:`importlib.machinery.PathFinder.find_module` +* :meth:`!importlib.machinery.PathFinder.find_module` * :meth:`!importlib.machinery.WindowsRegistryFinder.find_module` * :func:`importlib.util.module_for_loader` * :func:`!importlib.util.set_loader_wrapper` * :func:`!importlib.util.set_package_wrapper` -* :class:`pkgutil.ImpImporter` -* :class:`pkgutil.ImpLoader` +* :class:`!pkgutil.ImpImporter` +* :class:`!pkgutil.ImpLoader` * :meth:`pathlib.Path.link_to` * :func:`!sqlite3.enable_shared_cache` * :func:`!sqlite3.OptimizedUnicode` diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 5f8a1f08026d..1139bb89f5cf 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -983,14 +983,20 @@ Removed * Many previously deprecated cleanups in :mod:`importlib` have now been completed: - * References to, and support for ``module_repr()`` has been eradicated. + * References to, and support for ``module_repr()`` has been removed. (Contributed by Barry Warsaw in :gh:`97850`.) -* ``importlib.util.set_package`` has been removed. - (Contributed by Brett Cannon in :gh:`65961`.) + * ``importlib.util.set_package`` has been removed. (Contributed by Brett + Cannon in :gh:`65961`.) + + * Support for ``find_loader()`` and ``find_module()`` APIs have been + removed. (Contributed by Barry Warsaw in :gh:`98040`.) + + * ``importlib.abc.Finder``, ``pkg.ImpImporter``, and ``pkg.ImpLoader`` have + been removed. (Contributed by Barry Warsaw in :gh:`98040`.) -* The ``imp`` module has been removed. (Contributed by Barry Warsaw in - :gh:`98040`.) + * The ``imp`` module has been removed. (Contributed by Barry Warsaw in + :gh:`98040`.) * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 5b6c3dcd45c6..df1f2ab775b0 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -714,7 +714,7 @@ to properly delineate between :term:`meta path finders <meta path finder>` and :term:`path entry finders <path entry finder>` by introducing :class:`importlib.abc.MetaPathFinder` and :class:`importlib.abc.PathEntryFinder`, respectively. The old ABC of -:class:`importlib.abc.Finder` is now only provided for backwards-compatibility +:class:`!importlib.abc.Finder` is now only provided for backwards-compatibility and does not enforce any method requirements. In terms of finders, :class:`importlib.machinery.FileFinder` exposes the @@ -2390,7 +2390,7 @@ Porting Python code :attr:`sys.path_importer_cache` where it represents the use of implicit finders, but semantically it should not change anything. -* :class:`importlib.abc.Finder` no longer specifies a ``find_module()`` abstract +* :class:`!importlib.abc.Finder` no longer specifies a ``find_module()`` abstract method that must be implemented. If you were relying on subclasses to implement that method, make sure to check for the method's existence first. You will probably want to check for ``find_loader()`` first, though, in the diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index b7bb505a8184..53f78e3621cf 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2077,19 +2077,19 @@ Deprecations in the Python API ------------------------------ * As mentioned in :ref:`whatsnew-pep-451`, a number of :mod:`importlib` - methods and functions are deprecated: :meth:`importlib.find_loader` is + methods and functions are deprecated: :meth:`!importlib.find_loader` is replaced by :func:`importlib.util.find_spec`; - :meth:`importlib.machinery.PathFinder.find_module` is replaced by + :meth:`!importlib.machinery.PathFinder.find_module` is replaced by :meth:`importlib.machinery.PathFinder.find_spec`; - :meth:`importlib.abc.MetaPathFinder.find_module` is replaced by + :meth:`!importlib.abc.MetaPathFinder.find_module` is replaced by :meth:`importlib.abc.MetaPathFinder.find_spec`; - :meth:`importlib.abc.PathEntryFinder.find_loader` and - :meth:`~importlib.abc.PathEntryFinder.find_module` are replaced by + :meth:`!importlib.abc.PathEntryFinder.find_loader` and + :meth:`!find_module` are replaced by :meth:`importlib.abc.PathEntryFinder.find_spec`; all of the ``xxxLoader`` ABC - ``load_module`` methods (:meth:`importlib.abc.Loader.load_module`, - :meth:`importlib.abc.InspectLoader.load_module`, - :meth:`importlib.abc.FileLoader.load_module`, - :meth:`importlib.abc.SourceLoader.load_module`) should no longer be + ``load_module`` methods (:meth:`!importlib.abc.Loader.load_module`, + :meth:`!importlib.abc.InspectLoader.load_module`, + :meth:`!importlib.abc.FileLoader.load_module`, + :meth:`!importlib.abc.SourceLoader.load_module`) should no longer be implemented, instead loaders should implement an ``exec_module`` method (:meth:`importlib.abc.Loader.exec_module`, diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index df3b636cb9ec..28f22836d8d0 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -2004,11 +2004,11 @@ importlib --------- Methods -:meth:`MetaPathFinder.find_module() <importlib.abc.MetaPathFinder.find_module>` +:meth:`MetaPathFinder.find_module() <!importlib.abc.MetaPathFinder.find_module>` (replaced by :meth:`MetaPathFinder.find_spec() <importlib.abc.MetaPathFinder.find_spec>`) and -:meth:`PathEntryFinder.find_loader() <importlib.abc.PathEntryFinder.find_loader>` +:meth:`PathEntryFinder.find_loader() <!importlib.abc.PathEntryFinder.find_loader>` (replaced by :meth:`PathEntryFinder.find_spec() <importlib.abc.PathEntryFinder.find_spec>`) both deprecated in Python 3.4 now emit :exc:`DeprecationWarning`. diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index 21d9dee652b3..707c081cb2c5 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -70,40 +70,6 @@ def invalidate_caches(): finder.invalidate_caches() -def find_loader(name, path=None): - """Return the loader for the specified module. - - This is a backward-compatible wrapper around find_spec(). - - This function is deprecated in favor of importlib.util.find_spec(). - - """ - warnings.warn('Deprecated since Python 3.4 and slated for removal in ' - 'Python 3.12; use importlib.util.find_spec() instead', - DeprecationWarning, stacklevel=2) - try: - loader = sys.modules[name].__loader__ - if loader is None: - raise ValueError(f'{name}.__loader__ is None') - else: - return loader - except KeyError: - pass - except AttributeError: - raise ValueError(f'{name}.__loader__ is not set') from None - - spec = _bootstrap._find_spec(name, path) - # We won't worry about malformed specs (missing attributes). - if spec is None: - return None - if spec.loader is None: - if spec.submodule_search_locations is None: - raise ImportError(f'spec for {name} missing loader', name=name) - raise ImportError('namespace packages do not have loaders', - name=name) - return spec.loader - - def import_module(name, package=None): """Import a module. diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index e4fcaa61e6de..c48fd506a0e4 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -892,21 +892,6 @@ def find_spec(cls, fullname, path=None, target=None): else: return None - @classmethod - def find_module(cls, fullname, path=None): - """Find the built-in module. - - If 'path' is ever specified then the search is considered a failure. - - This method is deprecated. Use find_spec() instead. - - """ - _warnings.warn("BuiltinImporter.find_module() is deprecated and " - "slated for removal in Python 3.12; use find_spec() instead", - DeprecationWarning) - spec = cls.find_spec(fullname, path) - return spec.loader if spec is not None else None - @staticmethod def create_module(spec): """Create a built-in module""" @@ -1076,18 +1061,6 @@ def find_spec(cls, fullname, path=None, target=None): spec.submodule_search_locations.insert(0, pkgdir) return spec - @classmethod - def find_module(cls, fullname, path=None): - """Find a frozen module. - - This method is deprecated. Use find_spec() instead. - - """ - _warnings.warn("FrozenImporter.find_module() is deprecated and " - "slated for removal in Python 3.12; use find_spec() instead", - DeprecationWarning) - return cls if _imp.is_frozen(fullname) else None - @staticmethod def create_module(spec): """Set __file__, if able.""" @@ -1170,16 +1143,6 @@ def _resolve_name(name, package, level): return f'{base}.{name}' if name else base -def _find_spec_legacy(finder, name, path): - msg = (f"{_object_name(finder)}.find_spec() not found; " - "falling back to find_module()") - _warnings.warn(msg, ImportWarning) - loader = finder.find_module(name, path) - if loader is None: - return None - return spec_from_loader(name, loader) - - def _find_spec(name, path, target=None): """Find a module's spec.""" meta_path = sys.meta_path @@ -1200,9 +1163,7 @@ def _find_spec(name, path, target=None): try: find_spec = finder.find_spec except AttributeError: - spec = _find_spec_legacy(finder, name, path) - if spec is None: - continue + continue else: spec = find_spec(name, path, target) if spec is not None: diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index cb227373ca2f..7a3fdbaebdf2 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -659,26 +659,6 @@ def _wrap(new, old): return _check_name_wrapper -def _find_module_shim(self, fullname): - """Try to find a loader for the specified module by delegating to - self.find_loader(). - - This method is deprecated in favor of finder.find_spec(). - - """ - _warnings.warn("find_module() is deprecated and " - "slated for removal in Python 3.12; use find_spec() instead", - DeprecationWarning) - # Call find_loader(). If it returns a string (indicating this - # is a namespace package portion), generate a warning and - # return None. - loader, portions = self.find_loader(fullname) - if loader is None and len(portions): - msg = f'Not importing directory {portions[0]}: missing __init__' - _warnings.warn(msg, ImportWarning) - return loader - - def _classify_pyc(data, name, exc_details): """Perform basic validity checking of a pyc header and return the flags field, which determines how the pyc should be further validated against the source. @@ -985,22 +965,6 @@ def find_spec(cls, fullname, path=None, target=None): origin=filepath) return spec - @classmethod - def find_module(cls, fullname, path=None): - """Find module named in the registry. - - This method is deprecated. Use find_spec() instead. - - """ - _warnings.warn("WindowsRegistryFinder.find_module() is deprecated and " - "slated for removal in Python 3.12; use find_spec() instead", - DeprecationWarning) - spec = cls.find_spec(fullname, path) - if spec is not None: - return spec.loader - else: - return None - class _LoaderBasics: @@ -1517,27 +1481,6 @@ def _path_importer_cache(cls, path): sys.path_importer_cache[path] = finder return finder - @classmethod - def _legacy_get_spec(cls, fullname, finder): - # This would be a good place for a DeprecationWarning if - # we ended up going that route. - if hasattr(finder, 'find_loader'): - msg = (f"{_bootstrap._object_name(finder)}.find_spec() not found; " - "falling back to find_loader()") - _warnings.warn(msg, ImportWarning) - loader, portions = finder.find_loader(fullname) - else: - msg = (f"{_bootstrap._object_name(finder)}.find_spec() not found; " - "falling back to find_module()") - _warnings.warn(msg, ImportWarning) - loader = finder.find_module(fullname) - portions = [] - if loader is not None: - return _bootstrap.spec_from_loader(fullname, loader) - spec = _bootstrap.ModuleSpec(fullname, None) - spec.submodule_search_locations = portions - return spec - @classmethod def _get_spec(cls, fullname, path, target=None): """Find the loader or namespace_path for this module/package name.""" @@ -1549,10 +1492,7 @@ def _get_spec(cls, fullname, path, target=None): continue finder = cls._path_importer_cache(entry) if finder is not None: - if hasattr(finder, 'find_spec'): - spec = finder.find_spec(fullname, target) - else: - spec = cls._legacy_get_spec(fullname, finder) + spec = finder.find_spec(fullname, target) if spec is None: continue if spec.loader is not None: @@ -1594,22 +1534,6 @@ def find_spec(cls, fullname, path=None, target=None): else: return spec - @classmethod - def find_module(cls, fullname, path=None): - """find the module on sys.path or 'path' based on sys.path_hooks and - sys.path_importer_cache. - - This method is deprecated. Use find_spec() instead. - - """ - _warnings.warn("PathFinder.find_module() is deprecated and " - "slated for removal in Python 3.12; use find_spec() instead", - DeprecationWarning) - spec = cls.find_spec(fullname, path) - if spec is None: - return None - return spec.loader - @staticmethod def find_distributions(*args, **kwargs): """ @@ -1654,23 +1578,6 @@ def invalidate_caches(self): """Invalidate the directory mtime.""" self._path_mtime = -1 - find_module = _find_module_shim - - def find_loader(self, fullname): - """Try to find a loader for the specified module, or the namespace - package portions. Returns (loader, list-of-portions). - - This method is deprecated. Use find_spec() instead. - - """ - _warnings.warn("FileFinder.find_loader() is deprecated and " - "slated for removal in Python 3.12; use find_spec() instead", - DeprecationWarning) - spec = self.find_spec(fullname) - if spec is None: - return None, [] - return spec.loader, spec.submodule_search_locations or [] - def _get_spec(self, loader_class, fullname, path, smsl, target): loader = loader_class(fullname, path) return spec_from_file_location(fullname, path, loader=loader, diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py index 8fa9a0f3bc1e..b56fa94eb9c1 100644 --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -19,7 +19,7 @@ __all__ = [ - 'Loader', 'Finder', 'MetaPathFinder', 'PathEntryFinder', + 'Loader', 'MetaPathFinder', 'PathEntryFinder', 'ResourceLoader', 'InspectLoader', 'ExecutionLoader', 'FileLoader', 'SourceLoader', ] @@ -49,38 +49,6 @@ def _register(abstract_cls, *classes): abstract_cls.register(frozen_cls) -class Finder(metaclass=abc.ABCMeta): - - """Legacy abstract base class for import finders. - - It may be subclassed for compatibility with legacy third party - reimplementations of the import system. Otherwise, finder - implementations should derive from the more specific MetaPathFinder - or PathEntryFinder ABCs. - - Deprecated since Python 3.3 - """ - - def __init__(self): - warnings.warn("the Finder ABC is deprecated and " - "slated for removal in Python 3.12; use MetaPathFinder " - "or PathEntryFinder instead", - DeprecationWarning) - - @abc.abstractmethod - def find_module(self, fullname, path=None): - """An abstract method that should find a module. - The fullname is a str and the optional path is a str or None. - Returns a Loader object or None. - """ - warnings.warn("importlib.abc.Finder along with its find_module() " - "method are deprecated and " - "slated for removal in Python 3.12; use " - "MetaPathFinder.find_spec() or " - "PathEntryFinder.find_spec() instead", - DeprecationWarning) - - class MetaPathFinder(metaclass=abc.ABCMeta): """Abstract base class for import finders on sys.meta_path.""" @@ -88,27 +56,6 @@ class MetaPathFinder(metaclass=abc.ABCMeta): # We don't define find_spec() here since that would break # hasattr checks we do to support backward compatibility. - def find_module(self, fullname, path): - """Return a loader for the module. - - If no module is found, return None. The fullname is a str and - the path is a list of strings or None. - - This method is deprecated since Python 3.4 in favor of - finder.find_spec(). If find_spec() exists then backwards-compatible - functionality is provided for this method. - - """ - warnings.warn("MetaPathFinder.find_module() is deprecated since Python " - "3.4 in favor of MetaPathFinder.find_spec() and is " - "slated for removal in Python 3.12", - DeprecationWarning, - stacklevel=2) - if not hasattr(self, 'find_spec'): - return None - found = self.find_spec(fullname, path) - return found.loader if found is not None else None - def invalidate_caches(self): """An optional method for clearing the finder's cache, if any. This method is used by importlib.invalidate_caches(). @@ -122,43 +69,6 @@ class PathEntryFinder(metaclass=abc.ABCMeta): """Abstract base class for path entry finders used by PathFinder.""" - # We don't define find_spec() here since that would break - # hasattr checks we do to support backward compatibility. - - def find_loader(self, fullname): - """Return (loader, namespace portion) for the path entry. - - The fullname is a str. The namespace portion is a sequence of - path entries contributing to part of a namespace package. The - sequence may be empty. If loader is not None, the portion will - be ignored. - - The portion will be discarded if another path entry finder - locates the module as a normal module or package. - - This method is deprecated since Python 3.4 in favor of - finder.find_spec(). If find_spec() is provided than backwards-compatible - functionality is provided. - """ - warnings.warn("PathEntryFinder.find_loader() is deprecated since Python " - "3.4 in favor of PathEntryFinder.find_spec() " - "(available since 3.4)", - DeprecationWarning, - stacklevel=2) - if not hasattr(self, 'find_spec'): - return None, [] - found = self.find_spec(fullname) - if found is not None: - if not found.submodule_search_locations: - portions = [] - else: - portions = found.submodule_search_locations - return found.loader, portions - else: - return None, [] - - find_module = _bootstrap_external._find_module_shim - def invalidate_caches(self): """An optional method for clearing the finder's cache, if any. This method is used by PathFinder.invalidate_caches(). diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index fb977eaaa057..f62eccb974d6 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -23,20 +23,6 @@ ModuleInfo.__doc__ = 'A namedtuple with minimal info about a module.' -def _get_spec(finder, name): - """Return the finder-specific module spec.""" - # Works with legacy finders. - try: - find_spec = finder.find_spec - except AttributeError: - loader = finder.find_module(name) - if loader is None: - return None - return importlib.util.spec_from_loader(name, loader) - else: - return find_spec(name) - - def read_code(stream): # This helper is needed in order for the PEP 302 emulation to # correctly handle compiled files diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 1c3443fa8469..b10a5da99402 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -2242,7 +2242,7 @@ def run(self, callback, key=None, completer=None, onerror=None): callback(None, modname, '') else: try: - spec = pkgutil._get_spec(importer, modname) + spec = importer.find_spec(modname) except SyntaxError: # raised by tests for bad coding cookies or BOM continue diff --git a/Lib/test/test_importlib/builtin/test_finder.py b/Lib/test/test_importlib/builtin/test_finder.py index 81dc5a3699d9..111c4af1ea7c 100644 --- a/Lib/test/test_importlib/builtin/test_finder.py +++ b/Lib/test/test_importlib/builtin/test_finder.py @@ -43,38 +43,5 @@ def test_failure(self): ) = util.test_both(FindSpecTests, machinery=machinery) - at unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module') -class FinderTests(abc.FinderTests): - - """Test find_module() for built-in modules.""" - - def test_module(self): - # Common case. - with util.uncache(util.BUILTINS.good_name): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - found = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name) - self.assertTrue(found) - self.assertTrue(hasattr(found, 'load_module')) - - # Built-in modules cannot be a package. - test_package = test_package_in_package = test_package_over_module = None - - # Built-in modules cannot be in a package. - test_module_in_package = None - - def test_failure(self): - assert 'importlib' not in sys.builtin_module_names - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.machinery.BuiltinImporter.find_module('importlib') - self.assertIsNone(loader) - - -(Frozen_FinderTests, - Source_FinderTests - ) = util.test_both(FinderTests, machinery=machinery) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py index a0adc70ad1ec..ec9644dc5205 100644 --- a/Lib/test/test_importlib/extension/test_path_hook.py +++ b/Lib/test/test_importlib/extension/test_path_hook.py @@ -19,7 +19,7 @@ def hook(self, entry): def test_success(self): # Path hook should handle a directory where a known extension module # exists. - self.assertTrue(hasattr(self.hook(util.EXTENSIONS.path), 'find_module')) + self.assertTrue(hasattr(self.hook(util.EXTENSIONS.path), 'find_spec')) (Frozen_PathHooksTests, diff --git a/Lib/test/test_importlib/fixtures.py b/Lib/test/test_importlib/fixtures.py index a364a977bce7..73e5da2ba922 100644 --- a/Lib/test/test_importlib/fixtures.py +++ b/Lib/test/test_importlib/fixtures.py @@ -350,11 +350,6 @@ def DALS(str): return textwrap.dedent(str).lstrip() -class NullFinder: - def find_module(self, name): - pass - - @requires_zlib() class ZipFixtures: root = 'test.test_importlib.data' diff --git a/Lib/test/test_importlib/frozen/test_finder.py b/Lib/test/test_importlib/frozen/test_finder.py index 069755606b40..469dcdbd09ea 100644 --- a/Lib/test/test_importlib/frozen/test_finder.py +++ b/Lib/test/test_importlib/frozen/test_finder.py @@ -182,45 +182,5 @@ def test_not_using_frozen(self): ) = util.test_both(FindSpecTests, machinery=machinery) -class FinderTests(abc.FinderTests): - - """Test finding frozen modules.""" - - def find(self, name, path=None): - finder = self.machinery.FrozenImporter - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - with import_helper.frozen_modules(): - return finder.find_module(name, path) - - def test_module(self): - name = '__hello__' - loader = self.find(name) - self.assertTrue(hasattr(loader, 'load_module')) - - def test_package(self): - loader = self.find('__phello__') - self.assertTrue(hasattr(loader, 'load_module')) - - def test_module_in_package(self): - loader = self.find('__phello__.spam', ['__phello__']) - self.assertTrue(hasattr(loader, 'load_module')) - - # No frozen package within another package to test with. - test_package_in_package = None - - # No easy way to test. - test_package_over_module = None - - def test_failure(self): - loader = self.find('<not real>') - self.assertIsNone(loader) - - -(Frozen_FinderTests, - Source_FinderTests - ) = util.test_both(FinderTests, machinery=machinery) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py index da1569e3d068..4f1af454b52c 100644 --- a/Lib/test/test_importlib/frozen/test_loader.py +++ b/Lib/test/test_importlib/frozen/test_loader.py @@ -125,88 +125,6 @@ def test_unloadable(self): ) = util.test_both(ExecModuleTests, machinery=machinery) -class LoaderTests(abc.LoaderTests): - - def load_module(self, name): - with fresh(name, oldapi=True): - module = self.machinery.FrozenImporter.load_module(name) - with captured_stdout() as stdout: - module.main() - return module, stdout - - def test_module(self): - module, stdout = self.load_module('__hello__') - filename = resolve_stdlib_file('__hello__') - check = {'__name__': '__hello__', - '__package__': '', - '__loader__': self.machinery.FrozenImporter, - '__file__': filename, - } - for attr, value in check.items(): - self.assertEqual(getattr(module, attr, None), value) - self.assertEqual(stdout.getvalue(), 'Hello world!\n') - - def test_package(self): - module, stdout = self.load_module('__phello__') - filename = resolve_stdlib_file('__phello__', ispkg=True) - pkgdir = os.path.dirname(filename) - check = {'__name__': '__phello__', - '__package__': '__phello__', - '__path__': [pkgdir], - '__loader__': self.machinery.FrozenImporter, - '__file__': filename, - } - for attr, value in check.items(): - attr_value = getattr(module, attr, None) - self.assertEqual(attr_value, value, - "for __phello__.%s, %r != %r" % - (attr, attr_value, value)) - self.assertEqual(stdout.getvalue(), 'Hello world!\n') - - def test_lacking_parent(self): - with util.uncache('__phello__'): - module, stdout = self.load_module('__phello__.spam') - filename = resolve_stdlib_file('__phello__.spam') - check = {'__name__': '__phello__.spam', - '__package__': '__phello__', - '__loader__': self.machinery.FrozenImporter, - '__file__': filename, - } - for attr, value in check.items(): - attr_value = getattr(module, attr) - self.assertEqual(attr_value, value, - "for __phello__.spam.%s, %r != %r" % - (attr, attr_value, value)) - self.assertEqual(stdout.getvalue(), 'Hello world!\n') - - def test_module_reuse(self): - with fresh('__hello__', oldapi=True): - module1 = self.machinery.FrozenImporter.load_module('__hello__') - module2 = self.machinery.FrozenImporter.load_module('__hello__') - with captured_stdout() as stdout: - module1.main() - module2.main() - self.assertIs(module1, module2) - self.assertEqual(stdout.getvalue(), - 'Hello world!\nHello world!\n') - - # No way to trigger an error in a frozen module. - test_state_after_failure = None - - def test_unloadable(self): - with import_helper.frozen_modules(): - with deprecated(): - assert self.machinery.FrozenImporter.find_module('_not_real') is None - with self.assertRaises(ImportError) as cm: - self.load_module('_not_real') - self.assertEqual(cm.exception.name, '_not_real') - - -(Frozen_LoaderTests, - Source_LoaderTests - ) = util.test_both(LoaderTests, machinery=machinery) - - class InspectLoaderTests: """Tests for the InspectLoader methods for FrozenImporter.""" diff --git a/Lib/test/test_importlib/import_/test___loader__.py b/Lib/test/test_importlib/import_/test___loader__.py index eaf665a6f5b5..a14163919af6 100644 --- a/Lib/test/test_importlib/import_/test___loader__.py +++ b/Lib/test/test_importlib/import_/test___loader__.py @@ -33,48 +33,5 @@ def test___loader__(self): ) = util.test_both(SpecLoaderAttributeTests, __import__=util.__import__) -class LoaderMock: - - def find_module(self, fullname, path=None): - return self - - def load_module(self, fullname): - sys.modules[fullname] = self.module - return self.module - - -class LoaderAttributeTests: - - def test___loader___missing(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - module = types.ModuleType('blah') - try: - del module.__loader__ - except AttributeError: - pass - loader = LoaderMock() - loader.module = module - with util.uncache('blah'), util.import_state(meta_path=[loader]): - module = self.__import__('blah') - self.assertEqual(loader, module.__loader__) - - def test___loader___is_None(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - module = types.ModuleType('blah') - module.__loader__ = None - loader = LoaderMock() - loader.module = module - with util.uncache('blah'), util.import_state(meta_path=[loader]): - returned_module = self.__import__('blah') - self.assertEqual(loader, module.__loader__) - - -(Frozen_Tests, - Source_Tests - ) = util.test_both(LoaderAttributeTests, __import__=util.__import__) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py index ab1b35ee3c1a..7130c99a6fc1 100644 --- a/Lib/test/test_importlib/import_/test___package__.py +++ b/Lib/test/test_importlib/import_/test___package__.py @@ -95,25 +95,6 @@ def __init__(self, parent): self.parent = parent -class Using__package__PEP302(Using__package__): - mock_modules = util.mock_modules - - def test_using___package__(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_using___package__() - - def test_spec_fallback(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_spec_fallback() - - -(Frozen_UsingPackagePEP302, - Source_UsingPackagePEP302 - ) = util.test_both(Using__package__PEP302, __import__=util.__import__) - - class Using__package__PEP451(Using__package__): mock_modules = util.mock_spec @@ -162,23 +143,6 @@ def test_submodule(self): module = getattr(pkg, 'mod') self.assertEqual(module.__package__, 'pkg') -class Setting__package__PEP302(Setting__package__, unittest.TestCase): - mock_modules = util.mock_modules - - def test_top_level(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_top_level() - - def test_package(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_package() - - def test_submodule(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - super().test_submodule() class Setting__package__PEP451(Setting__package__, unittest.TestCase): mock_modules = util.mock_spec diff --git a/Lib/test/test_importlib/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py index 0ee032b0206d..d6ad590b3d46 100644 --- a/Lib/test/test_importlib/import_/test_api.py +++ b/Lib/test/test_importlib/import_/test_api.py @@ -28,11 +28,6 @@ def exec_module(module): class BadLoaderFinder: - @classmethod - def find_module(cls, fullname, path): - if fullname == SUBMOD_NAME: - return cls - @classmethod def load_module(cls, fullname): if fullname == SUBMOD_NAME: diff --git a/Lib/test/test_importlib/import_/test_caching.py b/Lib/test/test_importlib/import_/test_caching.py index 3ca765fb4ada..aedf0fd4f9db 100644 --- a/Lib/test/test_importlib/import_/test_caching.py +++ b/Lib/test/test_importlib/import_/test_caching.py @@ -52,12 +52,11 @@ class ImportlibUseCache(UseCache, unittest.TestCase): __import__ = util.__import__['Source'] def create_mock(self, *names, return_=None): - mock = util.mock_modules(*names) - original_load = mock.load_module - def load_module(self, fullname): - original_load(fullname) - return return_ - mock.load_module = MethodType(load_module, mock) + mock = util.mock_spec(*names) + original_spec = mock.find_spec + def find_spec(self, fullname, path, target=None): + return original_spec(fullname) + mock.find_spec = MethodType(find_spec, mock) return mock # __import__ inconsistent between loaders and built-in import when it comes @@ -86,14 +85,12 @@ def test_using_cache_for_assigning_to_attribute(self): # See test_using_cache_after_loader() for reasoning. def test_using_cache_for_fromlist(self): # [from cache for fromlist] - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - with self.create_mock('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = self.__import__('pkg', fromlist=['module']) - self.assertTrue(hasattr(module, 'module')) - self.assertEqual(id(module.module), - id(sys.modules['pkg.module'])) + with self.create_mock('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = self.__import__('pkg', fromlist=['module']) + self.assertTrue(hasattr(module, 'module')) + self.assertEqual(id(module.module), + id(sys.modules['pkg.module'])) if __name__ == '__main__': diff --git a/Lib/test/test_importlib/import_/test_meta_path.py b/Lib/test/test_importlib/import_/test_meta_path.py index c8b898ec2378..8689017ba431 100644 --- a/Lib/test/test_importlib/import_/test_meta_path.py +++ b/Lib/test/test_importlib/import_/test_meta_path.py @@ -113,16 +113,6 @@ def test_with_path(self): super().test_no_path() -class CallSignaturePEP302(CallSignoreSuppressImportWarning): - mock_modules = util.mock_modules - finder_name = 'find_module' - - -(Frozen_CallSignaturePEP302, - Source_CallSignaturePEP302 - ) = util.test_both(CallSignaturePEP302, __import__=util.__import__) - - class CallSignaturePEP451(CallSignature): mock_modules = util.mock_spec finder_name = 'find_spec' diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py index de620842bbc5..89b52fbd1e1a 100644 --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -116,46 +116,6 @@ def test_None_on_sys_path(self): if email is not missing: sys.modules['email'] = email - def test_finder_with_find_module(self): - class TestFinder: - def find_module(self, fullname): - return self.to_return - failing_finder = TestFinder() - failing_finder.to_return = None - path = 'testing path' - with util.import_state(path_importer_cache={path: failing_finder}): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.assertIsNone( - self.machinery.PathFinder.find_spec('whatever', [path])) - success_finder = TestFinder() - success_finder.to_return = __loader__ - with util.import_state(path_importer_cache={path: success_finder}): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - spec = self.machinery.PathFinder.find_spec('whatever', [path]) - self.assertEqual(spec.loader, __loader__) - - def test_finder_with_find_loader(self): - class TestFinder: - loader = None - portions = [] - def find_loader(self, fullname): - return self.loader, self.portions - path = 'testing path' - with util.import_state(path_importer_cache={path: TestFinder()}): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.assertIsNone( - self.machinery.PathFinder.find_spec('whatever', [path])) - success_finder = TestFinder() - success_finder.loader = __loader__ - with util.import_state(path_importer_cache={path: success_finder}): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - spec = self.machinery.PathFinder.find_spec('whatever', [path]) - self.assertEqual(spec.loader, __loader__) - def test_finder_with_find_spec(self): class TestFinder: spec = None @@ -228,9 +188,9 @@ def invalidate_caches(self): class FindModuleTests(FinderTests): def find(self, *args, **kwargs): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return self.machinery.PathFinder.find_module(*args, **kwargs) + spec = self.machinery.PathFinder.find_spec(*args, **kwargs) + return None if spec is None else spec.loader + def check_found(self, found, importer): self.assertIs(found, importer) @@ -255,16 +215,14 @@ def check_found(self, found, importer): class PathEntryFinderTests: def test_finder_with_failing_find_spec(self): - # PathEntryFinder with find_module() defined should work. - # Issue #20763. class Finder: - path_location = 'test_finder_with_find_module' + path_location = 'test_finder_with_find_spec' def __init__(self, path): if path != self.path_location: raise ImportError @staticmethod - def find_module(fullname): + def find_spec(fullname, target=None): return None @@ -274,27 +232,6 @@ def find_module(fullname): warnings.simplefilter("ignore", ImportWarning) self.machinery.PathFinder.find_spec('importlib') - def test_finder_with_failing_find_module(self): - # PathEntryFinder with find_module() defined should work. - # Issue #20763. - class Finder: - path_location = 'test_finder_with_find_module' - def __init__(self, path): - if path != self.path_location: - raise ImportError - - @staticmethod - def find_module(fullname): - return None - - - with util.import_state(path=[Finder.path_location]+sys.path[:], - path_hooks=[Finder]): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - warnings.simplefilter("ignore", DeprecationWarning) - self.machinery.PathFinder.find_module('importlib') - (Frozen_PEFTests, Source_PEFTests diff --git a/Lib/test/test_importlib/source/test_case_sensitivity.py b/Lib/test/test_importlib/source/test_case_sensitivity.py index 9d472707abe8..6a06313319db 100644 --- a/Lib/test/test_importlib/source/test_case_sensitivity.py +++ b/Lib/test/test_importlib/source/test_case_sensitivity.py @@ -63,19 +63,6 @@ def test_insensitive(self): self.assertIn(self.name, insensitive.get_filename(self.name)) -class CaseSensitivityTestPEP302(CaseSensitivityTest): - def find(self, finder): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return finder.find_module(self.name) - - -(Frozen_CaseSensitivityTestPEP302, - Source_CaseSensitivityTestPEP302 - ) = util.test_both(CaseSensitivityTestPEP302, importlib=importlib, - machinery=machinery) - - class CaseSensitivityTestPEP451(CaseSensitivityTest): def find(self, finder): found = finder.find_spec(self.name) diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py index bed9d56dca84..12db7c7d352a 100644 --- a/Lib/test/test_importlib/source/test_finder.py +++ b/Lib/test/test_importlib/source/test_finder.py @@ -120,7 +120,7 @@ def test_package_over_module(self): def test_failure(self): with util.create_modules('blah') as mapping: nothing = self.import_(mapping['.root'], 'sdfsadsadf') - self.assertIsNone(nothing) + self.assertEqual(nothing, self.NOT_FOUND) def test_empty_string_for_dir(self): # The empty string from sys.path means to search in the cwd. @@ -150,7 +150,7 @@ def test_dir_removal_handling(self): found = self._find(finder, 'mod', loader_only=True) self.assertIsNotNone(found) found = self._find(finder, 'mod', loader_only=True) - self.assertIsNone(found) + self.assertEqual(found, self.NOT_FOUND) @unittest.skipUnless(sys.platform != 'win32', 'os.chmod() does not support the needed arguments under Windows') @@ -196,10 +196,12 @@ class FinderTestsPEP420(FinderTests): NOT_FOUND = (None, []) def _find(self, finder, name, loader_only=False): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader_portions = finder.find_loader(name) - return loader_portions[0] if loader_only else loader_portions + spec = finder.find_spec(name) + if spec is None: + return self.NOT_FOUND + if loader_only: + return spec.loader + return spec.loader, spec.submodule_search_locations (Frozen_FinderTestsPEP420, @@ -207,20 +209,5 @@ def _find(self, finder, name, loader_only=False): ) = util.test_both(FinderTestsPEP420, machinery=machinery) -class FinderTestsPEP302(FinderTests): - - NOT_FOUND = None - - def _find(self, finder, name, loader_only=False): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - return finder.find_module(name) - - -(Frozen_FinderTestsPEP302, - Source_FinderTestsPEP302 - ) = util.test_both(FinderTestsPEP302, machinery=machinery) - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py index ead62f5e945e..f274330e0b33 100644 --- a/Lib/test/test_importlib/source/test_path_hook.py +++ b/Lib/test/test_importlib/source/test_path_hook.py @@ -18,19 +18,10 @@ def test_success(self): self.assertTrue(hasattr(self.path_hook()(mapping['.root']), 'find_spec')) - def test_success_legacy(self): - with util.create_modules('dummy') as mapping: - self.assertTrue(hasattr(self.path_hook()(mapping['.root']), - 'find_module')) - def test_empty_string(self): # The empty string represents the cwd. self.assertTrue(hasattr(self.path_hook()(''), 'find_spec')) - def test_empty_string_legacy(self): - # The empty string represents the cwd. - self.assertTrue(hasattr(self.path_hook()(''), 'find_module')) - (Frozen_PathHookTest, Source_PathHooktest diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index 3c9149c4e45a..603125f6d926 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -147,20 +147,13 @@ def ins(self): class MetaPathFinder: - def find_module(self, fullname, path): - return super().find_module(fullname, path) + pass class MetaPathFinderDefaultsTests(ABCTestHarness): SPLIT = make_abc_subclasses(MetaPathFinder) - def test_find_module(self): - # Default should return None. - with self.assertWarns(DeprecationWarning): - found = self.ins.find_module('something', None) - self.assertIsNone(found) - def test_invalidate_caches(self): # Calling the method is a no-op. self.ins.invalidate_caches() @@ -173,22 +166,13 @@ def test_invalidate_caches(self): class PathEntryFinder: - def find_loader(self, fullname): - return super().find_loader(fullname) + pass class PathEntryFinderDefaultsTests(ABCTestHarness): SPLIT = make_abc_subclasses(PathEntryFinder) - def test_find_loader(self): - with self.assertWarns(DeprecationWarning): - found = self.ins.find_loader('something') - self.assertEqual(found, (None, [])) - - def find_module(self): - self.assertEqual(None, self.ins.find_module('something')) - def test_invalidate_caches(self): # Should be a no-op. self.ins.invalidate_caches() @@ -201,8 +185,7 @@ def test_invalidate_caches(self): class Loader: - def load_module(self, fullname): - return super().load_module(fullname) + pass class LoaderDefaultsTests(ABCTestHarness): @@ -333,14 +316,6 @@ def find_spec(self, fullname, path, target=None): return MetaPathSpecFinder() - def test_find_module(self): - finder = self.finder(None) - path = ['a', 'b', 'c'] - name = 'blah' - with self.assertWarns(DeprecationWarning): - found = finder.find_module(name, path) - self.assertIsNone(found) - def test_find_spec_with_explicit_target(self): loader = object() spec = self.util.spec_from_loader('blah', loader) @@ -370,53 +345,6 @@ def test_spec(self): ) = test_util.test_both(MetaPathFinderFindModuleTests, abc=abc, util=util) -##### PathEntryFinder concrete methods ######################################### -class PathEntryFinderFindLoaderTests: - - @classmethod - def finder(cls, spec): - class PathEntrySpecFinder(cls.abc.PathEntryFinder): - - def find_spec(self, fullname, target=None): - self.called_for = fullname - return spec - - return PathEntrySpecFinder() - - def test_no_spec(self): - finder = self.finder(None) - name = 'blah' - with self.assertWarns(DeprecationWarning): - found = finder.find_loader(name) - self.assertIsNone(found[0]) - self.assertEqual([], found[1]) - self.assertEqual(name, finder.called_for) - - def test_spec_with_loader(self): - loader = object() - spec = self.util.spec_from_loader('blah', loader) - finder = self.finder(spec) - with self.assertWarns(DeprecationWarning): - found = finder.find_loader('blah') - self.assertIs(found[0], spec.loader) - - def test_spec_with_portions(self): - spec = self.machinery.ModuleSpec('blah', None) - paths = ['a', 'b', 'c'] - spec.submodule_search_locations = paths - finder = self.finder(spec) - with self.assertWarns(DeprecationWarning): - found = finder.find_loader('blah') - self.assertIsNone(found[0]) - self.assertEqual(paths, found[1]) - - -(Frozen_PEFFindLoaderTests, - Source_PEFFindLoaderTests - ) = test_util.test_both(PathEntryFinderFindLoaderTests, abc=abc, util=util, - machinery=machinery) - - ##### Loader concrete methods ################################################## class LoaderLoadModuleTests: diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index b3a99dc2dd57..ecf2c47c462e 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -95,7 +95,8 @@ def load_b(): (Frozen_ImportModuleTests, Source_ImportModuleTests - ) = test_util.test_both(ImportModuleTests, init=init) + ) = test_util.test_both( + ImportModuleTests, init=init, util=util, machinery=machinery) class FindLoaderTests: @@ -103,29 +104,26 @@ class FindLoaderTests: FakeMetaFinder = None def test_sys_modules(self): - # If a module with __loader__ is in sys.modules, then return it. + # If a module with __spec__.loader is in sys.modules, then return it. name = 'some_mod' with test_util.uncache(name): module = types.ModuleType(name) loader = 'a loader!' - module.__loader__ = loader + module.__spec__ = self.machinery.ModuleSpec(name, loader) sys.modules[name] = module - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - found = self.init.find_loader(name) - self.assertEqual(loader, found) + spec = self.util.find_spec(name) + self.assertIsNotNone(spec) + self.assertEqual(spec.loader, loader) def test_sys_modules_loader_is_None(self): - # If sys.modules[name].__loader__ is None, raise ValueError. + # If sys.modules[name].__spec__.loader is None, raise ValueError. name = 'some_mod' with test_util.uncache(name): module = types.ModuleType(name) module.__loader__ = None sys.modules[name] = module with self.assertRaises(ValueError): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - self.init.find_loader(name) + self.util.find_spec(name) def test_sys_modules_loader_is_not_set(self): # Should raise ValueError @@ -134,24 +132,20 @@ def test_sys_modules_loader_is_not_set(self): with test_util.uncache(name): module = types.ModuleType(name) try: - del module.__loader__ + del module.__spec__.loader except AttributeError: pass sys.modules[name] = module with self.assertRaises(ValueError): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - self.init.find_loader(name) + self.util.find_spec(name) def test_success(self): # Return the loader found on sys.meta_path. name = 'some_mod' with test_util.uncache(name): with test_util.import_state(meta_path=[self.FakeMetaFinder]): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - warnings.simplefilter('ignore', ImportWarning) - self.assertEqual((name, None), self.init.find_loader(name)) + spec = self.util.find_spec(name) + self.assertEqual((name, (name, None)), (spec.name, spec.loader)) def test_success_path(self): # Searching on a path should work. @@ -159,17 +153,12 @@ def test_success_path(self): path = 'path to some place' with test_util.uncache(name): with test_util.import_state(meta_path=[self.FakeMetaFinder]): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - warnings.simplefilter('ignore', ImportWarning) - self.assertEqual((name, path), - self.init.find_loader(name, path)) + spec = self.util.find_spec(name, path) + self.assertEqual(name, spec.name) def test_nothing(self): # None is returned upon failure to find a loader. - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) + self.assertIsNone(self.util.find_spec('nevergoingtofindthismodule')) class FindLoaderPEP451Tests(FindLoaderTests): @@ -182,20 +171,8 @@ def find_spec(name, path=None, target=None): (Frozen_FindLoaderPEP451Tests, Source_FindLoaderPEP451Tests - ) = test_util.test_both(FindLoaderPEP451Tests, init=init) - - -class FindLoaderPEP302Tests(FindLoaderTests): - - class FakeMetaFinder: - @staticmethod - def find_module(name, path=None): - return name, path - - -(Frozen_FindLoaderPEP302Tests, - Source_FindLoaderPEP302Tests - ) = test_util.test_both(FindLoaderPEP302Tests, init=init) + ) = test_util.test_both( + FindLoaderPEP451Tests, init=init, util=util, machinery=machinery) class ReloadTests: @@ -380,7 +357,8 @@ def test_module_missing_spec(self): (Frozen_ReloadTests, Source_ReloadTests - ) = test_util.test_both(ReloadTests, init=init, util=util) + ) = test_util.test_both( + ReloadTests, init=init, util=util, machinery=machinery) class InvalidateCacheTests: @@ -390,8 +368,6 @@ def test_method_called(self): class InvalidatingNullFinder: def __init__(self, *ignored): self.called = False - def find_module(self, *args): - return None def invalidate_caches(self): self.called = True @@ -416,7 +392,8 @@ def test_method_lacking(self): (Frozen_InvalidateCacheTests, Source_InvalidateCacheTests - ) = test_util.test_both(InvalidateCacheTests, init=init) + ) = test_util.test_both( + InvalidateCacheTests, init=init, util=util, machinery=machinery) class FrozenImportlibTests(unittest.TestCase): diff --git a/Lib/test/test_importlib/test_windows.py b/Lib/test/test_importlib/test_windows.py index b7dfe865a03a..40b8aa1787fe 100644 --- a/Lib/test/test_importlib/test_windows.py +++ b/Lib/test/test_importlib/test_windows.py @@ -92,30 +92,16 @@ class WindowsRegistryFinderTests: def test_find_spec_missing(self): spec = self.machinery.WindowsRegistryFinder.find_spec('spam') - self.assertIs(spec, None) - - def test_find_module_missing(self): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.machinery.WindowsRegistryFinder.find_module('spam') - self.assertIs(loader, None) + self.assertIsNone(spec) def test_module_found(self): with setup_module(self.machinery, self.test_module): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.machinery.WindowsRegistryFinder.find_module(self.test_module) spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module) - self.assertIsNot(loader, None) - self.assertIsNot(spec, None) + self.assertIsNotNone(spec) def test_module_not_found(self): with setup_module(self.machinery, self.test_module, path="."): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - loader = self.machinery.WindowsRegistryFinder.find_module(self.test_module) spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module) - self.assertIsNone(loader) self.assertIsNone(spec) (Frozen_WindowsRegistryFinderTests, diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index e348733f6ce3..c25be096e528 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -194,8 +194,7 @@ def import_state(**kwargs): new_value = default setattr(sys, attr, new_value) if len(kwargs): - raise ValueError( - 'unrecognized arguments: {0}'.format(kwargs.keys())) + raise ValueError('unrecognized arguments: {}'.format(kwargs)) yield finally: for attr, value in originals.items(): @@ -243,30 +242,6 @@ def __exit__(self, *exc_info): self._uncache.__exit__(None, None, None) -class mock_modules(_ImporterMock): - - """Importer mock using PEP 302 APIs.""" - - def find_module(self, fullname, path=None): - if fullname not in self.modules: - return None - else: - return self - - def load_module(self, fullname): - if fullname not in self.modules: - raise ImportError - else: - sys.modules[fullname] = self.modules[fullname] - if fullname in self.module_code: - try: - self.module_code[fullname]() - except Exception: - del sys.modules[fullname] - raise - return self.modules[fullname] - - class mock_spec(_ImporterMock): """Importer mock using PEP 451 APIs.""" diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index 4d9f5db3c6b3..902627088fc2 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -429,7 +429,7 @@ def test_iter_importers(self): importers = list(iter_importers(fullname)) expected_importer = get_importer(pathitem) for finder in importers: - spec = pkgutil._get_spec(finder, fullname) + spec = finder.find_spec(fullname) loader = spec.loader try: loader = loader.loader @@ -441,7 +441,7 @@ def test_iter_importers(self): self.assertEqual(finder, expected_importer) self.assertIsInstance(loader, importlib.machinery.SourceFileLoader) - self.assertIsNone(pkgutil._get_spec(finder, pkgname)) + self.assertIsNone(finder.find_spec(pkgname)) with self.assertRaises(ImportError): list(iter_importers('invalid.module')) @@ -535,12 +535,6 @@ class ImportlibMigrationTests(unittest.TestCase): # PEP 302 emulation in this module is in the process of being # deprecated in favour of importlib proper - def check_deprecated(self): - return check_warnings( - ("This emulation is deprecated and slated for removal in " - "Python 3.12; use 'importlib' instead", - DeprecationWarning)) - def test_get_loader_avoids_emulation(self): with check_warnings() as w: self.assertIsNotNone(pkgutil.get_loader("sys")) diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index 52d43bdead67..14c19719e260 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -836,7 +836,6 @@ def _testBogusZipFile(self): self.assertRaises(TypeError, z.get_source, None) error = zipimport.ZipImportError - self.assertIsNone(z.find_module('abc')) self.assertIsNone(z.find_spec('abc')) with warnings.catch_warnings(): diff --git a/Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst b/Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst new file mode 100644 index 000000000000..ac1854068441 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst @@ -0,0 +1,2 @@ +Remove more deprecated importlib APIs: ``find_loader()``, ``find_module()``, +``importlib.abc.Finder``, ``pkgutil.ImpImporter``, ``pkgutil.ImpLoader``. From webhook-mailer at python.org Wed May 3 08:29:50 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 03 May 2023 12:29:50 -0000 Subject: [Python-checkins] GH-98040: Suppress cross-references to the removed ``imp`` module (#104131) Message-ID: <mailman.127.1683116991.13550.python-checkins@python.org> https://github.com/python/cpython/commit/328435ed42d9d2d0aab7024540c745e730b9b9b1 commit: 328435ed42d9d2d0aab7024540c745e730b9b9b1 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-03T13:29:42+01:00 summary: GH-98040: Suppress cross-references to the removed ``imp`` module (#104131) Suppress cross-references to imp files: M Doc/c-api/import.rst M Doc/library/functions.rst M Doc/whatsnew/3.0.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.2.rst M Doc/whatsnew/3.3.rst M Doc/whatsnew/3.4.rst M Doc/whatsnew/3.6.rst M Misc/NEWS.d/3.8.0a1.rst diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 474a64800044..8e5af32b65e0 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -186,10 +186,10 @@ Importing Modules .. versionadded:: 3.2 .. versionchanged:: 3.3 - Uses :func:`imp.source_from_cache()` in calculating the source path if + Uses :func:`!imp.source_from_cache()` in calculating the source path if only the bytecode path is provided. .. versionchanged:: 3.12 - No longer uses the removed ``imp`` module. + No longer uses the removed :mod:`!imp` module. .. c:function:: long PyImport_GetMagicNumber() diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 085a11c3caa7..47e388012959 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1987,6 +1987,7 @@ are always available. They are listed here in alphabetical order. .. index:: statement: import + module: builtins .. note:: diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index 63b24748d8aa..f9ac13036cbc 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -840,7 +840,7 @@ Builtins need it; however, 99 percent of the time an explicit :keyword:`for` loop is more readable. -* Removed :func:`reload`. Use :func:`imp.reload`. +* Removed :func:`reload`. Use :func:`!imp.reload`. * Removed. :meth:`dict.has_key` -- use the :keyword:`in` operator instead. diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 44c8fa1e9eb2..3d7bcf896944 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1682,7 +1682,7 @@ Deprecated classes as appropriate instead. (Contributed by Brett Cannon in :issue:`42135`.) -* The deprecations of :mod:`imp`, :func:`!importlib.find_loader`, +* The deprecations of :mod:`!imp`, :func:`!importlib.find_loader`, :func:`importlib.util.set_package_wrapper`, :func:`importlib.util.set_loader_wrapper`, :func:`importlib.util.module_for_loader`, diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 918a6824618c..6df30ad6c19c 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1872,7 +1872,7 @@ C APIs pending removal are * The :mod:`asynchat` module * The :mod:`asyncore` module * The :ref:`entire distutils package <distutils-deprecated>` -* The :mod:`imp` module +* The :mod:`!imp` module * The :class:`typing.io <typing.IO>` namespace * The :class:`typing.re <typing.Pattern>` namespace * :func:`!cgi.log` diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1139bb89f5cf..4ed08f3ca3b3 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -995,7 +995,7 @@ Removed * ``importlib.abc.Finder``, ``pkg.ImpImporter``, and ``pkg.ImpLoader`` have been removed. (Contributed by Barry Warsaw in :gh:`98040`.) - * The ``imp`` module has been removed. (Contributed by Barry Warsaw in + * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) * Removed the ``suspicious`` rule from the documentation Makefile, and diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 8dbe2a1d828b..7af0c0288376 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -319,7 +319,7 @@ aspects that are visible to the programmer: >>> collections.__cached__ # doctest: +SKIP 'c:/py32/lib/__pycache__/collections.cpython-32.pyc' -* The tag that is unique to each interpreter is accessible from the :mod:`imp` +* The tag that is unique to each interpreter is accessible from the :mod:`!imp` module: >>> import imp # doctest: +SKIP @@ -328,7 +328,7 @@ aspects that are visible to the programmer: * Scripts that try to deduce source filename from the imported file now need to be smarter. It is no longer sufficient to simply strip the "c" from a ".pyc" - filename. Instead, use the new functions in the :mod:`imp` module: + filename. Instead, use the new functions in the :mod:`!imp` module: >>> imp.source_from_cache('c:/py32/lib/__pycache__/collections.cpython-32.pyc') # doctest: +SKIP 'c:/py32/lib/collections.py' diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index df1f2ab775b0..f121652ba51c 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -685,7 +685,7 @@ through normal attribute access. Using importlib as the Implementation of Import =============================================== :issue:`2377` - Replace __import__ w/ importlib.__import__ -:issue:`13959` - Re-implement parts of :mod:`imp` in pure Python +:issue:`13959` - Re-implement parts of :mod:`!imp` in pure Python :issue:`14605` - Make import machinery explicit :issue:`14646` - Require loaders set __loader__ and __package__ @@ -762,7 +762,7 @@ Loaders are also now expected to set the ``__package__`` attribute from from :mod:`importlib` and import itself is setting the attribute post-load. ``None`` is now inserted into :attr:`sys.path_importer_cache` when no finder -can be found on :attr:`sys.path_hooks`. Since :class:`imp.NullImporter` is not +can be found on :attr:`sys.path_hooks`. Since :class:`!imp.NullImporter` is not directly exposed on :attr:`sys.path_hooks` it could no longer be relied upon to always be available to use as a value representing no finder found. @@ -2385,7 +2385,7 @@ Porting Python code * Because ``None`` is now inserted into :attr:`sys.path_importer_cache`, if you are clearing out entries in the dictionary of paths that do not have a finder, you will need to remove keys paired with values of ``None`` **and** - :class:`imp.NullImporter` to be backwards-compatible. This will lead to extra + :class:`!imp.NullImporter` to be backwards-compatible. This will lead to extra overhead on older versions of Python that re-insert ``None`` into :attr:`sys.path_importer_cache` where it represents the use of implicit finders, but semantically it should not change anything. diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 53f78e3621cf..dabfdaa230ff 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -991,18 +991,18 @@ for the :meth:`~importlib.abc.InspectLoader.get_code` method. However, it will normally be desirable to override the default implementation for performance reasons. (Contributed by Brett Cannon in :issue:`18072`.) -The :func:`~importlib.reload` function has been moved from :mod:`imp` to -:mod:`importlib` as part of the :mod:`imp` module deprecation. (Contributed by +The :func:`~importlib.reload` function has been moved from :mod:`!imp` to +:mod:`importlib` as part of the :mod:`!imp` module deprecation. (Contributed by Berker Peksag in :issue:`18193`.) :mod:`importlib.util` now has a :data:`~importlib.util.MAGIC_NUMBER` attribute providing access to the bytecode version number. This replaces the -:func:`~imp.get_magic` function in the deprecated :mod:`imp` module. +:func:`!get_magic` function in the deprecated :mod:`!imp` module. (Contributed by Brett Cannon in :issue:`18192`.) New :mod:`importlib.util` functions :func:`~importlib.util.cache_from_source` and :func:`~importlib.util.source_from_cache` replace the same-named functions -in the deprecated :mod:`imp` module. (Contributed by Brett Cannon in +in the deprecated :mod:`!imp` module. (Contributed by Brett Cannon in :issue:`18194`.) The :mod:`importlib` bootstrap :class:`.NamespaceLoader` now conforms to @@ -2101,7 +2101,7 @@ Deprecations in the Python API and :meth:`importlib.util.set_package` are no longer needed because their functions are now handled automatically by the import system. -* The :mod:`imp` module is pending deprecation. To keep compatibility with +* The :mod:`!imp` module is pending deprecation. To keep compatibility with Python 2/3 code bases, the module's removal is currently not scheduled. * The :mod:`formatter` module is pending deprecation and is slated for removal @@ -2300,7 +2300,7 @@ Changes in the Python API then you can see if the module's ``__spec__.location`` is set to ``'frozen'``, check if the loader is a subclass of :class:`importlib.machinery.FrozenImporter`, - or if Python 2 compatibility is necessary you can use :func:`imp.is_frozen`. + or if Python 2 compatibility is necessary you can use :func:`!imp.is_frozen`. * :func:`py_compile.compile` now raises :exc:`FileExistsError` if the file path it would write to is a symlink or a non-regular file. This is to act as a diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index c7faaebfed62..3a681754e25d 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2180,7 +2180,7 @@ Changes in the Python API now raises :exc:`ValueError` for out-of-range values, rather than returning :const:`None`. See :issue:`20059`. -* The :mod:`imp` module now raises a :exc:`DeprecationWarning` instead of +* The :mod:`!imp` module now raises a :exc:`DeprecationWarning` instead of :exc:`PendingDeprecationWarning`. * The following modules have had missing APIs added to their :attr:`__all__` diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index db2eba32e6ea..854458f2d1a9 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -3818,7 +3818,7 @@ user. .. section: Library The :2to3fixer:`reload` fixer now uses :func:`importlib.reload` instead of -deprecated :func:`imp.reload`. +deprecated :func:`!imp.reload`. .. From webhook-mailer at python.org Wed May 3 08:57:30 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 03 May 2023 12:57:30 -0000 Subject: [Python-checkins] GH-97850: Suppress cross-references to the removed ``module_repr`` method (#104133) Message-ID: <mailman.128.1683118652.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8b03e5ff94d494109a84a106c1471175d42dd8fe commit: 8b03e5ff94d494109a84a106c1471175d42dd8fe branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-03T13:57:23+01:00 summary: GH-97850: Suppress cross-references to the removed ``module_repr`` method (#104133) Suppress cross-references to ``module_repr`` files: M Doc/reference/import.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.4.rst diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index 8f30181ae0a1..0f416a5c583f 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -706,7 +706,7 @@ Here are the exact rules used: * Otherwise, just use the module's ``__name__`` in the repr. .. versionchanged:: 3.12 - Use of :meth:`module_repr`, having been deprecated since Python 3.4, was + Use of :meth:`!module_repr`, having been deprecated since Python 3.4, was removed in Python 3.12 and is no longer called during the resolution of a module's repr. diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 3d7bcf896944..f689930ff0ca 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1612,7 +1612,7 @@ Deprecated (superseded by :meth:`~importlib.abc.Finder.find_spec`), :meth:`~importlib.abc.Loader.load_module` (superseded by :meth:`~importlib.abc.Loader.exec_module`), - :meth:`~importlib.abc.Loader.module_repr` (which the import system + :meth:`!module_repr` (which the import system takes care of for you), the ``__package__`` attribute (superseded by ``__spec__.parent``), the ``__loader__`` attribute (superseded by ``__spec__.loader``), and the ``__cached__`` attribute @@ -1693,14 +1693,14 @@ Deprecated (Contributed by Brett Cannon in :issue:`43720`.) * The import system now uses the ``__spec__`` attribute on modules before - falling back on :meth:`~importlib.abc.Loader.module_repr` for a module's + falling back on :meth:`!module_repr` for a module's ``__repr__()`` method. Removal of the use of ``module_repr()`` is scheduled for Python 3.12. (Contributed by Brett Cannon in :issue:`42137`.) -* :meth:`importlib.abc.Loader.module_repr`, - :meth:`importlib.machinery.FrozenLoader.module_repr`, and - :meth:`importlib.machinery.BuiltinLoader.module_repr` are deprecated and +* :meth:`!importlib.abc.Loader.module_repr`, + :meth:`!importlib.machinery.FrozenLoader.module_repr`, and + :meth:`!importlib.machinery.BuiltinLoader.module_repr` are deprecated and slated for removal in Python 3.12. (Contributed by Brett Cannon in :issue:`42136`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 6df30ad6c19c..7d3639f67952 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1877,7 +1877,7 @@ C APIs pending removal are * The :class:`typing.re <typing.Pattern>` namespace * :func:`!cgi.log` * :func:`!importlib.find_loader` -* :meth:`importlib.abc.Loader.module_repr` +* :meth:`!importlib.abc.Loader.module_repr` * :meth:`!importlib.abc.MetaPathFinder.find_module` * :meth:`!importlib.abc.PathEntryFinder.find_loader` * :meth:`!importlib.abc.PathEntryFinder.find_module` diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4ed08f3ca3b3..3381ce7b6b0d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -983,7 +983,7 @@ Removed * Many previously deprecated cleanups in :mod:`importlib` have now been completed: - * References to, and support for ``module_repr()`` has been removed. + * References to, and support for :meth:`!module_repr()` has been removed. (Contributed by Barry Warsaw in :gh:`97850`.) * ``importlib.util.set_package`` has been removed. (Contributed by Brett diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index dabfdaa230ff..38f9449b9afe 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2096,7 +2096,7 @@ Deprecations in the Python API :meth:`importlib.abc.InspectLoader.exec_module` :meth:`importlib.abc.SourceLoader.exec_module`) and let the import system take care of the rest; and - :meth:`importlib.abc.Loader.module_repr`, + :meth:`!importlib.abc.Loader.module_repr`, :meth:`importlib.util.module_for_loader`, :meth:`importlib.util.set_loader`, and :meth:`importlib.util.set_package` are no longer needed because their functions are now handled automatically by the import system. From webhook-mailer at python.org Wed May 3 09:13:19 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 03 May 2023 13:13:19 -0000 Subject: [Python-checkins] GH-97850: Suppress cross-references to removed ``importlib.util`` functions (#104134) Message-ID: <mailman.129.1683119600.13550.python-checkins@python.org> https://github.com/python/cpython/commit/423d7faeb37b6c13b3ebbf9255165fefc651983e commit: 423d7faeb37b6c13b3ebbf9255165fefc651983e branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-03T14:13:03+01:00 summary: GH-97850: Suppress cross-references to removed ``importlib.util`` functions (#104134) `importlib.utils` -> `importlib.util` in a few places --------- Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.4.rst M Misc/NEWS.d/3.10.0a5.rst M Misc/NEWS.d/3.12.0a1.rst diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index f689930ff0ca..661eeaedbfc0 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1683,9 +1683,9 @@ Deprecated (Contributed by Brett Cannon in :issue:`42135`.) * The deprecations of :mod:`!imp`, :func:`!importlib.find_loader`, - :func:`importlib.util.set_package_wrapper`, - :func:`importlib.util.set_loader_wrapper`, - :func:`importlib.util.module_for_loader`, + :func:`!importlib.util.set_package_wrapper`, + :func:`!importlib.util.set_loader_wrapper`, + :func:`!importlib.util.module_for_loader`, :class:`!pkgutil.ImpImporter`, and :class:`!pkgutil.ImpLoader` have all been updated to list Python 3.12 as the slated version of removal (they began raising :exc:`DeprecationWarning` in diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 7d3639f67952..7a479c6e56a9 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1889,7 +1889,7 @@ C APIs pending removal are * :meth:`!importlib.machinery.FrozenLoader.module_repr` * :meth:`!importlib.machinery.PathFinder.find_module` * :meth:`!importlib.machinery.WindowsRegistryFinder.find_module` -* :func:`importlib.util.module_for_loader` +* :func:`!importlib.util.module_for_loader` * :func:`!importlib.util.set_loader_wrapper` * :func:`!importlib.util.set_package_wrapper` * :class:`!pkgutil.ImpImporter` diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 38f9449b9afe..45bb91833a35 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2097,8 +2097,8 @@ Deprecations in the Python API :meth:`importlib.abc.SourceLoader.exec_module`) and let the import system take care of the rest; and :meth:`!importlib.abc.Loader.module_repr`, - :meth:`importlib.util.module_for_loader`, :meth:`importlib.util.set_loader`, - and :meth:`importlib.util.set_package` are no longer needed because their + :meth:`!importlib.util.module_for_loader`, :meth:`!importlib.util.set_loader`, + and :meth:`!importlib.util.set_package` are no longer needed because their functions are now handled automatically by the import system. * The :mod:`!imp` module is pending deprecation. To keep compatibility with @@ -2277,7 +2277,7 @@ Changes in the Python API in a backwards-compatible fashion, use e.g. ``getattr(module, '__loader__', None) is not None``. (:issue:`17115`.) -* :meth:`importlib.util.module_for_loader` now sets ``__loader__`` and +* :meth:`!importlib.util.module_for_loader` now sets ``__loader__`` and ``__package__`` unconditionally to properly support reloading. If this is not desired then you will need to set these attributes manually. You can use :func:`importlib.util.module_to_load` for module management. diff --git a/Misc/NEWS.d/3.10.0a5.rst b/Misc/NEWS.d/3.10.0a5.rst index 1c7c7447cae0..497e38491718 100644 --- a/Misc/NEWS.d/3.10.0a5.rst +++ b/Misc/NEWS.d/3.10.0a5.rst @@ -499,7 +499,7 @@ Araujo. .. nonce: HY2beA .. section: Documentation -Updated importlib.utils.resolve_name() doc to use __spec__.parent instead of +Updated importlib.util.resolve_name() doc to use __spec__.parent instead of __package__. (Thanks Yair Frid.) .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 075e8da825a3..ff5064f89d8d 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -2028,8 +2028,8 @@ resources. .. nonce: NzdREm .. section: Library -Remove deprecated :func:`importlib.utils.set_loader` and -:func:`importlib.utils.module_for_loader` from :mod:`importlib.utils`. +Remove deprecated :func:`!importlib.util.set_loader` and +:func:`!importlib.util.module_for_loader` from :mod:`importlib.util`. .. From webhook-mailer at python.org Wed May 3 09:17:21 2023 From: webhook-mailer at python.org (encukou) Date: Wed, 03 May 2023 13:17:21 -0000 Subject: [Python-checkins] gh-103968: Deprecate creating heap types whose metaclass has custom tp_new. (GH-103972) Message-ID: <mailman.130.1683119842.13550.python-checkins@python.org> https://github.com/python/cpython/commit/524a7f77fd8244835e382f076dd4a76404580bb3 commit: 524a7f77fd8244835e382f076dd4a76404580bb3 branch: main author: Petr Viktorin <encukou at gmail.com> committer: encukou <encukou at gmail.com> date: 2023-05-03T15:17:14+02:00 summary: gh-103968: Deprecate creating heap types whose metaclass has custom tp_new. (GH-103972) (That's a mouthful of an edge case!) Co-authored-by: Barney Gale <barney.gale at gmail.com> files: A Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst M Doc/c-api/type.rst M Doc/whatsnew/3.12.rst M Lib/test/test_capi/test_misc.py M Modules/_testcapi/heaptype.c M Objects/typeobject.c diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 69b152969933..9fd40e1008c4 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -256,8 +256,13 @@ The following functions and structs are used to create The metaclass *metaclass* is used to construct the resulting type object. When *metaclass* is ``NULL``, the metaclass is derived from *bases* (or *Py_tp_base[s]* slots if *bases* is ``NULL``, see below). - Note that metaclasses that override - :c:member:`~PyTypeObject.tp_new` are not supported. + + Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not + supported. + (For backwards compatibility, other ``PyType_From*`` functions allow + such metaclasses. They ignore ``tp_new``, which may result in incomplete + initialization. This is deprecated and in Python 3.14+ such metaclasses will + not be supported.) The *bases* argument can be used to specify base classes; it can either be only one class or a tuple of classes. @@ -305,6 +310,11 @@ The following functions and structs are used to create The function now finds and uses a metaclass corresponding to the provided base classes. Previously, only :class:`type` instances were returned. + The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*. + which may result in incomplete initialization. + Creating classes whose metaclass overrides + :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it + will be no longer allowed. .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) @@ -317,6 +327,12 @@ The following functions and structs are used to create The function now finds and uses a metaclass corresponding to the provided base classes. Previously, only :class:`type` instances were returned. + The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*. + which may result in incomplete initialization. + Creating classes whose metaclass overrides + :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it + will be no longer allowed. + .. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec) Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, NULL)``. @@ -327,6 +343,12 @@ The following functions and structs are used to create base classes provided in *Py_tp_base[s]* slots. Previously, only :class:`type` instances were returned. + The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*. + which may result in incomplete initialization. + Creating classes whose metaclass overrides + :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it + will be no longer allowed. + .. c:type:: PyType_Spec Structure defining a type's behavior. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3381ce7b6b0d..63db5d3f89be 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1320,6 +1320,21 @@ Porting to Python 3.12 available on debug builds. If you happen to be using it then you'll need to start using ``_Py_GetGlobalRefTotal()``. +* The following functions now select an appropriate metaclass for the newly + created type: + + * :c:func:`PyType_FromSpec` + * :c:func:`PyType_FromSpecWithBases` + * :c:func:`PyType_FromModuleAndSpec` + + Creating classes whose metaclass overrides :c:member:`~PyTypeObject.tp_new` + is deprecated, and in Python 3.14+ it will be disallowed. + Note that these functions ignore ``tp_new`` of the metaclass, possibly + allowing incomplete initialization. + + Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12) + already disallows creating classes whose metaclass overrides ``tp_new``. + Deprecated ---------- @@ -1396,6 +1411,11 @@ Deprecated * ``_PyErr_ChainExceptions`` is deprecated. Use ``_PyErr_ChainExceptions1`` instead. (Contributed by Irit Katriel in :gh:`102192`.) +* Using :c:func:`PyType_FromSpec`, :c:func:`PyType_FromSpecWithBases` + or :c:func:`PyType_FromModuleAndSpec` to create a class whose metaclass + overrides :c:member:`~PyTypeObject.tp_new` is deprecated. + Call the metaclass instead. + Removed ------- diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9d5d1ca6e7dc..1d426d0f8f82 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -681,6 +681,20 @@ def test_heaptype_with_custom_metaclass(self): with self.assertRaisesRegex(TypeError, msg): t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew) + def test_heaptype_with_custom_metaclass_deprecation(self): + # gh-103968: a metaclass with custom tp_new is deprecated, but still + # allowed for functions that existed in 3.11 + # (PyType_FromSpecWithBases is used here). + class Base(metaclass=_testcapi.HeapCTypeMetaclassCustomNew): + pass + + with warnings_helper.check_warnings( + ('.*custom tp_new.*in Python 3.14.*', DeprecationWarning), + ): + sub = _testcapi.make_type_with_base(Base) + self.assertTrue(issubclass(sub, Base)) + self.assertIsInstance(sub, _testcapi.HeapCTypeMetaclassCustomNew) + def test_multiple_inheritance_ctypes_with_weakref_or_dict(self): with self.assertRaises(TypeError): diff --git a/Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst b/Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst new file mode 100644 index 000000000000..5e4270f82afd --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst @@ -0,0 +1,4 @@ +:c:func:`PyType_FromSpec` and its variants now allow creating classes whose +metaclass overrides :c:member:`~PyTypeObject.tp_new`. The ``tp_new`` is +ignored. This behavior is deprecated and will be disallowed in 3.14+. The +new :c:func:`PyType_FromMetaclass` already disallows it. diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index 209cc182c069..6384fbc485fb 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -22,7 +22,7 @@ static PyObject *pytype_fromspec_meta(PyObject* self, PyObject *meta) "_testcapi.HeapCTypeViaMetaclass", sizeof(PyObject), 0, - Py_TPFLAGS_DEFAULT, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, HeapCTypeViaMetaclass_slots }; @@ -385,6 +385,19 @@ make_immutable_type_with_base(PyObject *self, PyObject *base) return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base); } +static PyObject * +make_type_with_base(PyObject *self, PyObject *base) +{ + assert(PyType_Check(base)); + PyType_Spec ImmutableSubclass_spec = { + .name = "_testcapi.Subclass", + .basicsize = (int)((PyTypeObject*)base)->tp_basicsize, + .slots = empty_type_slots, + .flags = Py_TPFLAGS_DEFAULT, + }; + return PyType_FromSpecWithBases(&ImmutableSubclass_spec, base); +} + static PyMethodDef TestMethods[] = { {"pytype_fromspec_meta", pytype_fromspec_meta, METH_O}, @@ -397,6 +410,7 @@ static PyMethodDef TestMethods[] = { test_from_spec_invalid_metatype_inheritance, METH_NOARGS}, {"make_immutable_type_with_base", make_immutable_type_with_base, METH_O}, + {"make_type_with_base", make_type_with_base, METH_O}, {NULL}, }; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index cf0efe199b28..4ced04b0bde9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3950,9 +3950,10 @@ check_basicsize_includes_size_and_offsets(PyTypeObject* type) return 1; } -PyObject * -PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, - PyType_Spec *spec, PyObject *bases_in) +static PyObject * +_PyType_FromMetaclass_impl( + PyTypeObject *metaclass, PyObject *module, + PyType_Spec *spec, PyObject *bases_in, int _allow_tp_new) { /* Invariant: A non-NULL value in one of these means this function holds * a strong reference or owns allocated memory. @@ -4127,9 +4128,21 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, goto finally; } if (metaclass->tp_new != PyType_Type.tp_new) { - PyErr_SetString(PyExc_TypeError, - "Metaclasses with custom tp_new are not supported."); - goto finally; + if (_allow_tp_new) { + if (PyErr_WarnFormat( + PyExc_DeprecationWarning, 1, + "Using PyType_Spec with metaclasses that have custom " + "tp_new is deprecated and will no longer be allowed in " + "Python 3.14.") < 0) { + goto finally; + } + } + else { + PyErr_SetString( + PyExc_TypeError, + "Metaclasses with custom tp_new are not supported."); + goto finally; + } } /* Calculate best base, and check that all bases are type objects */ @@ -4316,22 +4329,29 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, return (PyObject*)res; } +PyObject * +PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, + PyType_Spec *spec, PyObject *bases_in) +{ + return _PyType_FromMetaclass_impl(metaclass, module, spec, bases_in, 0); +} + PyObject * PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { - return PyType_FromMetaclass(NULL, module, spec, bases); + return _PyType_FromMetaclass_impl(NULL, module, spec, bases, 1); } PyObject * PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) { - return PyType_FromMetaclass(NULL, NULL, spec, bases); + return _PyType_FromMetaclass_impl(NULL, NULL, spec, bases, 1); } PyObject * PyType_FromSpec(PyType_Spec *spec) { - return PyType_FromMetaclass(NULL, NULL, spec, NULL); + return _PyType_FromMetaclass_impl(NULL, NULL, spec, NULL, 1); } PyObject * From webhook-mailer at python.org Wed May 3 10:05:27 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 03 May 2023 14:05:27 -0000 Subject: [Python-checkins] gh-103693: Add convenience variable feature to `pdb` (#103694) Message-ID: <mailman.131.1683122728.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0fc58c66bafbd20f02c206c801cf9ab939853164 commit: 0fc58c66bafbd20f02c206c801cf9ab939853164 branch: main author: Tian Gao <gaogaotiantian at hotmail.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-03T15:04:50+01:00 summary: gh-103693: Add convenience variable feature to `pdb` (#103694) files: A Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst M Doc/library/pdb.rst M Doc/whatsnew/3.12.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 5bc48a6d5f77..8a386aa77368 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -263,6 +263,21 @@ the commands; the input is split at the first ``;;`` pair, even if it is in the middle of a quoted string. A workaround for strings with double semicolons is to use implicit string concatenation ``';'';'`` or ``";"";"``. +To set a temporary global variable, use a *convenience variable*. A *convenience +variable* is a variable whose name starts with ``$``. For example, ``$foo = 1`` +sets a global variable ``$foo`` which you can use in the debugger session. The +*convenience variables* are cleared when the program resumes execution so it's +less likely to interfere with your program compared to using normal variables +like ``foo = 1``. + +There are three preset *convenience variables*: + +* ``$_frame``: the current frame you are debugging +* ``$_retval``: the return value if the frame is returning +* ``$_exception``: the exception if the frame is raising an exception + +.. versionadded:: 3.12 + .. index:: pair: .pdbrc; file triple: debugger; configuration; file diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 63db5d3f89be..94b44ed9ce09 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -408,6 +408,14 @@ os.path * Add :func:`os.path.splitroot` to split a path into a triad ``(drive, root, tail)``. (Contributed by Barney Gale in :gh:`101000`.) +pdb +--- + +* Add convenience variables to hold values temporarily for debug session + and provide quick access to values like the current frame or the return + value. + (Contributed by Tian Gao in :gh:`103693`.) + shutil ------ diff --git a/Lib/pdb.py b/Lib/pdb.py index 645cbf518e58..b3dc5a455e56 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -270,6 +270,8 @@ def forget(self): self.lineno = None self.stack = [] self.curindex = 0 + if hasattr(self, 'curframe') and self.curframe: + self.curframe.f_globals.pop('__pdb_convenience_variables', None) self.curframe = None self.tb_lineno.clear() @@ -288,6 +290,7 @@ def setup(self, f, tb): # locals whenever the .f_locals accessor is called, so we # cache it here to ensure that modifications are not overwritten. self.curframe_locals = self.curframe.f_locals + self.set_convenience_variable(self.curframe, '_frame', self.curframe) return self.execRcLines() # Can be executed earlier than 'setup' if desired @@ -359,6 +362,7 @@ def user_return(self, frame, return_value): if self._wait_for_mainpyfile: return frame.f_locals['__return__'] = return_value + self.set_convenience_variable(frame, '_retval', return_value) self.message('--Return--') self.interaction(frame, None) @@ -369,6 +373,7 @@ def user_exception(self, frame, exc_info): return exc_type, exc_value, exc_traceback = exc_info frame.f_locals['__exception__'] = exc_type, exc_value + self.set_convenience_variable(frame, '_exception', exc_value) # An 'Internal StopIteration' exception is an exception debug event # issued by the interpreter when handling a subgenerator run with @@ -394,6 +399,7 @@ def _cmdloop(self): self.message('--KeyboardInterrupt--') # Called before loop, handles display expressions + # Set up convenience variable containers def preloop(self): displaying = self.displaying.get(self.curframe) if displaying: @@ -477,6 +483,9 @@ def precmd(self, line): next = line[marker+2:].lstrip() self.cmdqueue.append(next) line = line[:marker].rstrip() + + # Replace all the convenience variables + line = re.sub(r'\$([a-zA-Z_][a-zA-Z0-9_]*)', r'__pdb_convenience_variables["\1"]', line) return line def onecmd(self, line): @@ -527,6 +536,13 @@ def message(self, msg): def error(self, msg): print('***', msg, file=self.stdout) + # convenience variables + + def set_convenience_variable(self, frame, name, value): + if '__pdb_convenience_variables' not in frame.f_globals: + frame.f_globals['__pdb_convenience_variables'] = {} + frame.f_globals['__pdb_convenience_variables'][name] = value + # Generic completion functions. Individual complete_foo methods can be # assigned below to one of these functions. @@ -1018,6 +1034,7 @@ def _select_frame(self, number): self.curindex = number self.curframe = self.stack[self.curindex][0] self.curframe_locals = self.curframe.f_locals + self.set_convenience_variable(self.curframe, '_frame', self.curframe) self.print_stack_entry(self.stack[self.curindex]) self.lineno = None diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 2f712a102579..482c92dbf1f6 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -746,6 +746,84 @@ def test_pdb_where_command(): (Pdb) continue """ +def test_convenience_variables(): + """Test convenience variables + + >>> def util_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... try: + ... raise Exception('test') + ... except: + ... pass + ... return 1 + + >>> def test_function(): + ... util_function() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ... '$_frame.f_lineno', # Check frame convenience variable + ... '$a = 10', # Set a convenience variable + ... '$a', # Print its value + ... 'p $a + 2', # Do some calculation + ... 'u', # Switch frame + ... '$_frame.f_lineno', # Make sure the frame changed + ... '$a', # Make sure the value persists + ... 'd', # Go back to the original frame + ... 'next', + ... '$a', # The value should be gone + ... 'next', + ... '$_exception', # Check exception convenience variable + ... 'next', + ... '$_exception', # Exception should be gone + ... 'return', + ... '$_retval', # Check return convenience variable + ... 'continue', + ... ]): + ... test_function() + > <doctest test.test_pdb.test_convenience_variables[0]>(3)util_function() + -> try: + (Pdb) $_frame.f_lineno + 3 + (Pdb) $a = 10 + (Pdb) $a + 10 + (Pdb) p $a + 2 + 12 + (Pdb) u + > <doctest test.test_pdb.test_convenience_variables[1]>(2)test_function() + -> util_function() + (Pdb) $_frame.f_lineno + 2 + (Pdb) $a + 10 + (Pdb) d + > <doctest test.test_pdb.test_convenience_variables[0]>(3)util_function() + -> try: + (Pdb) next + > <doctest test.test_pdb.test_convenience_variables[0]>(4)util_function() + -> raise Exception('test') + (Pdb) $a + *** KeyError: 'a' + (Pdb) next + Exception: test + > <doctest test.test_pdb.test_convenience_variables[0]>(4)util_function() + -> raise Exception('test') + (Pdb) $_exception + Exception('test') + (Pdb) next + > <doctest test.test_pdb.test_convenience_variables[0]>(5)util_function() + -> except: + (Pdb) $_exception + *** KeyError: '_exception' + (Pdb) return + --Return-- + > <doctest test.test_pdb.test_convenience_variables[0]>(7)util_function()->1 + -> return 1 + (Pdb) $_retval + 1 + (Pdb) continue + """ + def test_post_mortem(): """Test post mortem traceback debugging. diff --git a/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst b/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst new file mode 100644 index 000000000000..52c68bfc9cee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst @@ -0,0 +1 @@ +Add convenience variable feature to :mod:`pdb` From webhook-mailer at python.org Wed May 3 11:17:40 2023 From: webhook-mailer at python.org (pganssle) Date: Wed, 03 May 2023 15:17:40 -0000 Subject: [Python-checkins] GH-103944: Remove last use of `utcfromtimestamp` (#103995) Message-ID: <mailman.132.1683127061.13550.python-checkins@python.org> https://github.com/python/cpython/commit/38dc3f28dde92b4fa6284a57f4e554991a3d9276 commit: 38dc3f28dde92b4fa6284a57f4e554991a3d9276 branch: main author: Paul Ganssle <1377457+pganssle at users.noreply.github.com> committer: pganssle <1377457+pganssle at users.noreply.github.com> date: 2023-05-03T11:17:27-04:00 summary: GH-103944: Remove last use of `utcfromtimestamp` (#103995) * Remove last use of `utcfromtimestamp` This was a weirdly valid use of `utcfromtimestamp` in the sense that the "timestamps" in TZif files are not epoch times, but actually something more properly thought of as "number of seconds since 1970 in the local time zone", so even though we didn't want UTC time, `utcfromtimestamp` was still a good way to get the thing we wanted. Since we're deprecating `utcfromtimestamp`, it's just as valid to use `timedelta` arithmetic here. We may be able to avoid the question entirely by switching these tests over to using `ZoneInfo` in the future. * Fix a few missing DeprecationWarnings in tests In one test, we simply turn off DeprecationWarning rather than asserting about it, because whether the error condition happens before or after the warning seems to differ between the Python and C versions. files: M Lib/test/datetimetester.py diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py index fb07d2a5ad9b..55e061950ff2 100644 --- a/Lib/test/datetimetester.py +++ b/Lib/test/datetimetester.py @@ -2,18 +2,19 @@ See https://www.zope.dev/Members/fdrake/DateTimeWiki/TestCases """ -import io -import itertools import bisect import copy import decimal -import sys +import io +import itertools import os import pickle import random import re import struct +import sys import unittest +import warnings from array import array @@ -51,11 +52,12 @@ for proto in range(pickle.HIGHEST_PROTOCOL + 1)] assert len(pickle_choices) == pickle.HIGHEST_PROTOCOL + 1 +EPOCH_NAIVE = datetime(1970, 1, 1, 0, 0) # For calculating transitions + # An arbitrary collection of objects of non-datetime types, for testing # mixed-type comparisons. OTHERSTUFF = (10, 34.5, "abc", {}, [], ()) - # XXX Copied from test_float. INF = float("inf") NAN = float("nan") @@ -2626,9 +2628,10 @@ def test_utcfromtimestamp_limits(self): for test_name, ts in test_cases: with self.subTest(test_name, ts=ts): with self.assertRaises((ValueError, OverflowError)): - # converting a Python int to C time_t can raise a - # OverflowError, especially on 32-bit platforms. - self.theclass.utcfromtimestamp(ts) + with self.assertWarns(DeprecationWarning): + # converting a Python int to C time_t can raise a + # OverflowError, especially on 32-bit platforms. + self.theclass.utcfromtimestamp(ts) def test_insane_fromtimestamp(self): # It's possible that some platform maps time_t to double, @@ -2645,8 +2648,9 @@ def test_insane_utcfromtimestamp(self): # exempt such platforms (provided they return reasonable # results!). for insane in -1e200, 1e200: - self.assertRaises(OverflowError, self.theclass.utcfromtimestamp, - insane) + with self.assertWarns(DeprecationWarning): + self.assertRaises(OverflowError, self.theclass.utcfromtimestamp, + insane) @unittest.skipIf(sys.platform == "win32", "Windows doesn't accept negative timestamps") def test_negative_float_fromtimestamp(self): @@ -3005,7 +3009,7 @@ def __new__(cls, *args, **kwargs): for name, meth_name, kwargs in test_cases: with self.subTest(name): constr = getattr(DateTimeSubclass, meth_name) - if constr == "utcnow": + if meth_name == "utcnow": with self.assertWarns(DeprecationWarning): dt = constr(**kwargs) else: @@ -4733,8 +4737,10 @@ def test_tzinfo_utcfromtimestamp(self): # Try with and without naming the keyword; for whatever reason, # utcfromtimestamp() doesn't accept a tzinfo argument. off42 = FixedOffset(42, "42") - self.assertRaises(TypeError, meth, ts, off42) - self.assertRaises(TypeError, meth, ts, tzinfo=off42) + with warnings.catch_warnings(category=DeprecationWarning): + warnings.simplefilter("ignore", category=DeprecationWarning) + self.assertRaises(TypeError, meth, ts, off42) + self.assertRaises(TypeError, meth, ts, tzinfo=off42) def test_tzinfo_timetuple(self): # TestDateTime tested most of this. datetime adds a twist to the @@ -6102,15 +6108,14 @@ def stats(cls, start_year=1): def transitions(self): for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)): shift = ti[0] - prev_ti[0] - # TODO: Remove this use of utcfromtimestamp - yield datetime.utcfromtimestamp(t), shift + yield (EPOCH_NAIVE + timedelta(seconds=t)), shift def nondst_folds(self): """Find all folds with the same value of isdst on both sides of the transition.""" for (_, prev_ti), (t, ti) in pairs(zip(self.ut, self.ti)): shift = ti[0] - prev_ti[0] if shift < ZERO and ti[1] == prev_ti[1]: - yield datetime.utcfromtimestamp(t), -shift, prev_ti[2], ti[2] + yield _utcfromtimestamp(datetime, t,), -shift, prev_ti[2], ti[2] @classmethod def print_all_nondst_folds(cls, same_abbr=False, start_year=1): From webhook-mailer at python.org Wed May 3 12:28:57 2023 From: webhook-mailer at python.org (barneygale) Date: Wed, 03 May 2023 16:28:57 -0000 Subject: [Python-checkins] GH-104114: Fix `pathlib.WindowsPath.glob()` use of literal pattern segment case (GH-104116) Message-ID: <mailman.133.1683131338.13550.python-checkins@python.org> https://github.com/python/cpython/commit/da1980afcb8820ffaa0574df735bc39b1a276a76 commit: da1980afcb8820ffaa0574df735bc39b1a276a76 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-03T17:28:44+01:00 summary: GH-104114: Fix `pathlib.WindowsPath.glob()` use of literal pattern segment case (GH-104116) We now use `_WildcardSelector` to evaluate literal pattern segments, which allows us to retrieve the real filesystem case. This change is necessary in order to implement a *case_sensitive* argument (see GH-81079) and a *follow_symlinks* argument (see GH-77609). files: A Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index dee19d1f89ad..8a1651c23d7f 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -54,11 +54,6 @@ def _ignore_error(exception): getattr(exception, 'winerror', None) in _IGNORED_WINERRORS) -def _is_wildcard_pattern(pat): - # Whether this pattern needs actual matching using fnmatch, or can - # be looked up directly as a file. - return "*" in pat or "?" in pat or "[" in pat - def _is_case_sensitive(flavour): return flavour.normcase('Aa') == 'Aa' @@ -78,10 +73,8 @@ def _make_selector(pattern_parts, flavour): cls = _ParentSelector elif '**' in pat: raise ValueError("Invalid pattern: '**' can only be an entire path component") - elif _is_wildcard_pattern(pat): - cls = _WildcardSelector else: - cls = _PreciseSelector + cls = _WildcardSelector return cls(pat, child_parts, flavour) @@ -102,17 +95,15 @@ def select_from(self, parent_path): """Iterate over all child paths of `parent_path` matched by this selector. This can contain parent_path itself.""" path_cls = type(parent_path) - is_dir = path_cls.is_dir - exists = path_cls.exists scandir = path_cls._scandir - if not is_dir(parent_path): + if not parent_path.is_dir(): return iter([]) - return self._select_from(parent_path, is_dir, exists, scandir) + return self._select_from(parent_path, scandir) class _TerminatingSelector: - def _select_from(self, parent_path, is_dir, exists, scandir): + def _select_from(self, parent_path, scandir): yield parent_path @@ -120,29 +111,12 @@ class _ParentSelector(_Selector): def __init__(self, name, child_parts, flavour): _Selector.__init__(self, child_parts, flavour) - def _select_from(self, parent_path, is_dir, exists, scandir): + def _select_from(self, parent_path, scandir): path = parent_path._make_child_relpath('..') - for p in self.successor._select_from(path, is_dir, exists, scandir): + for p in self.successor._select_from(path, scandir): yield p -class _PreciseSelector(_Selector): - - def __init__(self, name, child_parts, flavour): - self.name = name - _Selector.__init__(self, child_parts, flavour) - - def _select_from(self, parent_path, is_dir, exists, scandir): - try: - path = parent_path._make_child_relpath(self.name) - follow = is_dir(path) if self.dironly else exists(path, follow_symlinks=False) - if follow: - for p in self.successor._select_from(path, is_dir, exists, scandir): - yield p - except PermissionError: - return - - class _WildcardSelector(_Selector): def __init__(self, pat, child_parts, flavour): @@ -150,7 +124,7 @@ def __init__(self, pat, child_parts, flavour): self.match = re.compile(fnmatch.translate(pat), flags=flags).fullmatch _Selector.__init__(self, child_parts, flavour) - def _select_from(self, parent_path, is_dir, exists, scandir): + def _select_from(self, parent_path, scandir): try: # We must close the scandir() object before proceeding to # avoid exhausting file descriptors when globbing deep trees. @@ -171,7 +145,7 @@ def _select_from(self, parent_path, is_dir, exists, scandir): name = entry.name if self.match(name): path = parent_path._make_child_relpath(name) - for p in self.successor._select_from(path, is_dir, exists, scandir): + for p in self.successor._select_from(path, scandir): yield p except PermissionError: return @@ -182,7 +156,7 @@ class _RecursiveWildcardSelector(_Selector): def __init__(self, pat, child_parts, flavour): _Selector.__init__(self, child_parts, flavour) - def _iterate_directories(self, parent_path, is_dir, scandir): + def _iterate_directories(self, parent_path, scandir): yield parent_path try: # We must close the scandir() object before proceeding to @@ -198,18 +172,18 @@ def _iterate_directories(self, parent_path, is_dir, scandir): raise if entry_is_dir and not entry.is_symlink(): path = parent_path._make_child_relpath(entry.name) - for p in self._iterate_directories(path, is_dir, scandir): + for p in self._iterate_directories(path, scandir): yield p except PermissionError: return - def _select_from(self, parent_path, is_dir, exists, scandir): + def _select_from(self, parent_path, scandir): try: yielded = set() try: successor_select = self.successor._select_from - for starting_point in self._iterate_directories(parent_path, is_dir, scandir): - for p in successor_select(starting_point, is_dir, exists, scandir): + for starting_point in self._iterate_directories(parent_path, scandir): + for p in successor_select(starting_point, scandir): if p not in yielded: yield p yielded.add(p) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 620d480e37e2..424bb92a87d1 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -3122,7 +3122,7 @@ def test_glob(self): self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") }) self.assertEqual(set(p.glob("*a\\")), { P(BASE, "dirA") }) self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") }) - self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\FILEa"}) + self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\fileA"}) self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"}) def test_rglob(self): @@ -3130,7 +3130,7 @@ def test_rglob(self): p = P(BASE, "dirC") self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") }) self.assertEqual(set(p.rglob("*\\")), { P(BASE, "dirC/dirD") }) - self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\FILEd"}) + self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\fileD"}) def test_expanduser(self): P = self.cls diff --git a/Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst b/Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst new file mode 100644 index 000000000000..e705fea8326e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst @@ -0,0 +1,3 @@ +Fix issue where :meth:`pathlib.Path.glob` returns paths using the case of +non-wildcard segments for corresponding path segments, rather than the real +filesystem case. From webhook-mailer at python.org Wed May 3 16:55:26 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 03 May 2023 20:55:26 -0000 Subject: [Python-checkins] gh-103590: mention that the change is included in 3.11.4 and clarify except* documentation (#104095) Message-ID: <mailman.134.1683147328.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9f9e001ab2ab67acdb2e0383a25ab4c164608a47 commit: 9f9e001ab2ab67acdb2e0383a25ab4c164608a47 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-03T21:55:19+01:00 summary: gh-103590: mention that the change is included in 3.11.4 and clarify except* documentation (#104095) files: M Doc/reference/compound_stmts.rst M Doc/whatsnew/3.12.rst diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index f0a8936c35bf..0731589e4cad 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -362,8 +362,10 @@ one :keyword:`!except*` clause, the first that matches it. :: Any remaining exceptions that were not handled by any :keyword:`!except*` -clause are re-raised at the end, combined into an exception group along with -all exceptions that were raised from within :keyword:`!except*` clauses. +clause are re-raised at the end, along with all exceptions that were +raised from within the :keyword:`!except*` clauses. If this list contains +more than one exception to reraise, they are combined into an exception +group. If the raised exception is not an exception group and its type matches one of the :keyword:`!except*` clauses, it is caught and wrapped by an diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 94b44ed9ce09..49f9bd28248d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -239,7 +239,8 @@ Other Language Changes * When a ``try-except*`` construct handles the entire :exc:`ExceptionGroup` and raises one other exception, that exception is no longer wrapped in an - :exc:`ExceptionGroup`. (Contributed by Irit Katriel in :gh:`103590`.) + :exc:`ExceptionGroup`. Also changed in version 3.11.4. (Contributed by Irit + Katriel in :gh:`103590`.) New Modules From webhook-mailer at python.org Wed May 3 19:12:10 2023 From: webhook-mailer at python.org (brettcannon) Date: Wed, 03 May 2023 23:12:10 -0000 Subject: [Python-checkins] gh-97850: Deprecate `find_loader` and `get_loader` in `pkgutil` (GH-98520) Message-ID: <mailman.135.1683155531.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d6e83fbf30fb25996b547d8a2444814437e228e5 commit: d6e83fbf30fb25996b547d8a2444814437e228e5 branch: main author: Nikita Sobolev <mail at sobolevn.me> committer: brettcannon <brett at python.org> date: 2023-05-03T16:11:54-07:00 summary: gh-97850: Deprecate `find_loader` and `get_loader` in `pkgutil` (GH-98520) Co-authored-by: C.A.M. Gerlach <CAM.Gerlach at Gerlach.CAM> Co-authored-by: Brett Cannon <brett at python.org> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: A Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst M Doc/library/pkgutil.rst M Doc/whatsnew/3.12.rst M Lib/pkgutil.py M Lib/test/test_pkgutil.py diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst index 98e6e294af0c..891a867d1ceb 100644 --- a/Doc/library/pkgutil.rst +++ b/Doc/library/pkgutil.rst @@ -64,6 +64,10 @@ support. .. versionchanged:: 3.4 Updated to be based on :pep:`451` + .. deprecated-removed:: 3.12 3.14 + Use :func:`importlib.util.find_spec` instead. + + .. function:: get_importer(path_item) Retrieve a :term:`finder` for the given *path_item*. @@ -96,6 +100,9 @@ support. .. versionchanged:: 3.4 Updated to be based on :pep:`451` + .. deprecated-removed:: 3.12 3.14 + Use :func:`importlib.util.find_spec` instead. + .. function:: iter_importers(fullname='') diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 49f9bd28248d..3dfd787e3df8 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -813,6 +813,11 @@ Pending Removal in Python 3.14 * The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, and will be removed in 3.14. +* :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` + now raise :exc:`DeprecationWarning`; + use :func:`importlib.util.find_spec` instead. + (Contributed by Nikita Sobolev in :gh:`97850`.) + Pending Removal in Future Versions ---------------------------------- diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index f62eccb974d6..dccbec52aa73 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -270,6 +270,10 @@ def get_loader(module_or_name): If the named module is not already imported, its containing package (if any) is imported, in order to establish the package __path__. """ + warnings._deprecated("pkgutil.get_loader", + f"{warnings._DEPRECATED_MSG}; " + "use importlib.util.find_spec() instead", + remove=(3, 14)) if module_or_name in sys.modules: module_or_name = sys.modules[module_or_name] if module_or_name is None: @@ -294,6 +298,10 @@ def find_loader(fullname): importlib.util.find_spec that converts most failures to ImportError and only returns the loader rather than the full spec """ + warnings._deprecated("pkgutil.find_loader", + f"{warnings._DEPRECATED_MSG}; " + "use importlib.util.find_spec() instead", + remove=(3, 14)) if fullname.startswith('.'): msg = "Relative module name {!r} not supported".format(fullname) raise ImportError(msg) diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index 902627088fc2..6fcd726345ee 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -1,6 +1,6 @@ from pathlib import Path from test.support.import_helper import unload, CleanImport -from test.support.warnings_helper import check_warnings +from test.support.warnings_helper import check_warnings, ignore_warnings import unittest import sys import importlib @@ -535,25 +535,18 @@ class ImportlibMigrationTests(unittest.TestCase): # PEP 302 emulation in this module is in the process of being # deprecated in favour of importlib proper - def test_get_loader_avoids_emulation(self): - with check_warnings() as w: - self.assertIsNotNone(pkgutil.get_loader("sys")) - self.assertIsNotNone(pkgutil.get_loader("os")) - self.assertIsNotNone(pkgutil.get_loader("test.support")) - self.assertEqual(len(w.warnings), 0) - @unittest.skipIf(__name__ == '__main__', 'not compatible with __main__') + @ignore_warnings(category=DeprecationWarning) def test_get_loader_handles_missing_loader_attribute(self): global __loader__ this_loader = __loader__ del __loader__ try: - with check_warnings() as w: - self.assertIsNotNone(pkgutil.get_loader(__name__)) - self.assertEqual(len(w.warnings), 0) + self.assertIsNotNone(pkgutil.get_loader(__name__)) finally: __loader__ = this_loader + @ignore_warnings(category=DeprecationWarning) def test_get_loader_handles_missing_spec_attribute(self): name = 'spam' mod = type(sys)(name) @@ -563,6 +556,7 @@ def test_get_loader_handles_missing_spec_attribute(self): loader = pkgutil.get_loader(name) self.assertIsNone(loader) + @ignore_warnings(category=DeprecationWarning) def test_get_loader_handles_spec_attribute_none(self): name = 'spam' mod = type(sys)(name) @@ -572,6 +566,7 @@ def test_get_loader_handles_spec_attribute_none(self): loader = pkgutil.get_loader(name) self.assertIsNone(loader) + @ignore_warnings(category=DeprecationWarning) def test_get_loader_None_in_sys_modules(self): name = 'totally bogus' sys.modules[name] = None @@ -581,18 +576,26 @@ def test_get_loader_None_in_sys_modules(self): del sys.modules[name] self.assertIsNone(loader) + def test_get_loader_is_deprecated(self): + with check_warnings( + (r".*\bpkgutil.get_loader\b.*", DeprecationWarning), + ): + res = pkgutil.get_loader("sys") + self.assertIsNotNone(res) + + def test_find_loader_is_deprecated(self): + with check_warnings( + (r".*\bpkgutil.find_loader\b.*", DeprecationWarning), + ): + res = pkgutil.find_loader("sys") + self.assertIsNotNone(res) + + @ignore_warnings(category=DeprecationWarning) def test_find_loader_missing_module(self): name = 'totally bogus' loader = pkgutil.find_loader(name) self.assertIsNone(loader) - def test_find_loader_avoids_emulation(self): - with check_warnings() as w: - self.assertIsNotNone(pkgutil.find_loader("sys")) - self.assertIsNotNone(pkgutil.find_loader("os")) - self.assertIsNotNone(pkgutil.find_loader("test.support")) - self.assertEqual(len(w.warnings), 0) - def test_get_importer_avoids_emulation(self): # We use an illegal path so *none* of the path hooks should fire with check_warnings() as w: diff --git a/Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst b/Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst new file mode 100644 index 000000000000..e3297d164fff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst @@ -0,0 +1,2 @@ +Deprecate :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` +in favor of :func:`importlib.util.find_spec`. From webhook-mailer at python.org Wed May 3 19:26:46 2023 From: webhook-mailer at python.org (brettcannon) Date: Wed, 03 May 2023 23:26:46 -0000 Subject: [Python-checkins] pydoc.safeimport: Use importlib.import_module instead of __import__ (GH-103118) Message-ID: <mailman.136.1683156407.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e95dd40aff35775efce4c03bec7d82f03711310b commit: e95dd40aff35775efce4c03bec7d82f03711310b branch: main author: Yuxin Wu <ppwwyyxxc at gmail.com> committer: brettcannon <brett at python.org> date: 2023-05-03T16:26:39-07:00 summary: pydoc.safeimport: Use importlib.import_module instead of __import__ (GH-103118) files: M Lib/pydoc.py diff --git a/Lib/pydoc.py b/Lib/pydoc.py index b10a5da99402..84e673a7f87f 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -448,7 +448,7 @@ def safeimport(path, forceload=0, cache={}): # Prevent garbage collection. cache[key] = sys.modules[key] del sys.modules[key] - module = __import__(path) + module = importlib.import_module(path) except BaseException as err: # Did the error occur before or after the module was found? if path in sys.modules: @@ -463,9 +463,6 @@ def safeimport(path, forceload=0, cache={}): else: # Some other error occurred during the importing process. raise ErrorDuringImport(path, err) - for part in path.split('.')[1:]: - try: module = getattr(module, part) - except AttributeError: return None return module # ---------------------------------------------------- formatter base class From webhook-mailer at python.org Wed May 3 20:11:36 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 04 May 2023 00:11:36 -0000 Subject: [Python-checkins] gh-104146: Remove unused 'second_pass_replacements' from clinic.py (#104147) Message-ID: <mailman.137.1683159097.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9885677b0494e9be3eb8d7d69bebca0e79d8abcc commit: 9885677b0494e9be3eb8d7d69bebca0e79d8abcc branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-04T00:11:29Z summary: gh-104146: Remove unused 'second_pass_replacements' from clinic.py (#104147) The code that manipulated 'second_pass_replacements' was removed in 2015 with commit 0759f84 (gh-67688, bpo-23500). files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index b8b2b75c7491..d3e120c0e7a8 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2112,8 +2112,6 @@ def parse(self, input): traceback.format_exc().rstrip()) printer.print_block(block) - second_pass_replacements = {} - # these are destinations not buffers for name, destination in self.destinations.items(): if destination.type == 'suppress': @@ -2155,23 +2153,8 @@ def parse(self, input): printer_2.print_block(block, core_includes=True) write_file(destination.filename, printer_2.f.getvalue()) continue - text = printer.f.getvalue() - - if second_pass_replacements: - printer_2 = BlockPrinter(self.language) - parser_2 = BlockParser(text, self.language) - changed = False - for block in parser_2: - if block.dsl_name: - for id, replacement in second_pass_replacements.items(): - if id in block.output: - changed = True - block.output = block.output.replace(id, replacement) - printer_2.print_block(block) - if changed: - text = printer_2.f.getvalue() - - return text + + return printer.f.getvalue() def _module_and_class(self, fields): From webhook-mailer at python.org Thu May 4 03:11:29 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 07:11:29 -0000 Subject: [Python-checkins] GH-97950: Allow translation of index directive content (#104000) Message-ID: <mailman.138.1683184290.13550.python-checkins@python.org> https://github.com/python/cpython/commit/35d273825abc319d0ecbd69110e847f6040d0cd7 commit: 35d273825abc319d0ecbd69110e847f6040d0cd7 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T10:11:09+03:00 summary: GH-97950: Allow translation of index directive content (#104000) files: M Doc/conf.py M Doc/tools/extensions/pyspecific.py diff --git a/Doc/conf.py b/Doc/conf.py index 6a3c01cd91a7..485c0bdf84df 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -91,6 +91,11 @@ # Avoid a warning with Sphinx >= 2.0 master_doc = 'contents' +# Allow translation of index directives +gettext_additional_targets = [ + 'index', +] + # Options for HTML output # ----------------------- diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index d659a4a54b9d..39c7c42e66f9 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -674,6 +674,34 @@ def process_audit_events(app, doctree, fromdocname): node.replace_self(table) +def patch_pairindextypes(app) -> None: + if app.builder.name != 'gettext': + return + + # allow translating deprecated index entries + try: + from sphinx.domains.python import pairindextypes + except ImportError: + pass + else: + # Sphinx checks if a 'pair' type entry on an index directive is one of + # the Sphinx-translated pairindextypes values. As we intend to move + # away from this, we need Sphinx to believe that these values don't + # exist, by deleting them when using the gettext builder. + + # pairindextypes.pop('module', None) + # pairindextypes.pop('keyword', None) + # pairindextypes.pop('operator', None) + # pairindextypes.pop('object', None) + # pairindextypes.pop('exception', None) + # pairindextypes.pop('statement', None) + # pairindextypes.pop('builtin', None) + + # there needs to be at least one statement in this block, will be + # removed when the first of the below is uncommented. + pass + + def setup(app): app.add_role('issue', issue_role) app.add_role('gh', gh_issue_role) @@ -695,6 +723,7 @@ def setup(app): app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod) app.add_directive('miscnews', MiscNews) + app.connect('builder-inited', patch_pairindextypes) app.connect('doctree-resolved', process_audit_events) app.connect('env-merge-info', audit_events_merge) app.connect('env-purge-doc', audit_events_purge) From webhook-mailer at python.org Thu May 4 03:26:15 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 07:26:15 -0000 Subject: [Python-checkins] [3.11] GH-97950: Allow translation of index directive content (GH-104000) (#104151) Message-ID: <mailman.139.1683185176.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8f94c9465bda92f4dd913635799a375881e5c93e commit: 8f94c9465bda92f4dd913635799a375881e5c93e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T10:26:08+03:00 summary: [3.11] GH-97950: Allow translation of index directive content (GH-104000) (#104151) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/conf.py M Doc/tools/extensions/pyspecific.py diff --git a/Doc/conf.py b/Doc/conf.py index 3bb915b0b02e..3bd828f8ce9e 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -86,6 +86,11 @@ # Avoid a warning with Sphinx >= 2.0 master_doc = 'contents' +# Allow translation of index directives +gettext_additional_targets = [ + 'index', +] + # Options for HTML output # ----------------------- diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index b4fea983818d..3ff2a91b1fef 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -679,6 +679,34 @@ def process_audit_events(app, doctree, fromdocname): node.replace_self(table) +def patch_pairindextypes(app) -> None: + if app.builder.name != 'gettext': + return + + # allow translating deprecated index entries + try: + from sphinx.domains.python import pairindextypes + except ImportError: + pass + else: + # Sphinx checks if a 'pair' type entry on an index directive is one of + # the Sphinx-translated pairindextypes values. As we intend to move + # away from this, we need Sphinx to believe that these values don't + # exist, by deleting them when using the gettext builder. + + # pairindextypes.pop('module', None) + # pairindextypes.pop('keyword', None) + # pairindextypes.pop('operator', None) + # pairindextypes.pop('object', None) + # pairindextypes.pop('exception', None) + # pairindextypes.pop('statement', None) + # pairindextypes.pop('builtin', None) + + # there needs to be at least one statement in this block, will be + # removed when the first of the below is uncommented. + pass + + def setup(app): app.add_role('issue', issue_role) app.add_role('gh', gh_issue_role) @@ -701,6 +729,7 @@ def setup(app): app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod) app.add_directive('miscnews', MiscNews) + app.connect('builder-inited', patch_pairindextypes) app.connect('doctree-resolved', process_audit_events) app.connect('env-merge-info', audit_events_merge) app.connect('env-purge-doc', audit_events_purge) From webhook-mailer at python.org Thu May 4 03:57:29 2023 From: webhook-mailer at python.org (encukou) Date: Thu, 04 May 2023 07:57:29 -0000 Subject: [Python-checkins] gh-103509: PEP 697 -- Limited C API for Extending Opaque Types (GH-103511) Message-ID: <mailman.140.1683187050.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cd9a56c2b0e14f56f2e83dd4db43c5c69a74b232 commit: cd9a56c2b0e14f56f2e83dd4db43c5c69a74b232 branch: main author: Petr Viktorin <encukou at gmail.com> committer: encukou <encukou at gmail.com> date: 2023-05-04T09:56:53+02:00 summary: gh-103509: PEP 697 -- Limited C API for Extending Opaque Types (GH-103511) Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst A Modules/_testcapi/heaptype_relative.c M Doc/c-api/object.rst M Doc/c-api/structures.rst M Doc/c-api/type.rst M Doc/c-api/typeobj.rst M Doc/data/stable_abi.dat M Doc/whatsnew/3.12.rst M Include/cpython/object.h M Include/descrobject.h M Include/internal/pycore_object.h M Include/object.h M Include/pyport.h M Lib/test/test_capi/test_misc.py M Lib/test/test_stable_abi_ctypes.py M Misc/stable_abi.toml M Modules/Setup.stdlib.in M Modules/_testcapi/heaptype.c M Modules/_testcapi/parts.h M Modules/_testcapimodule.c M Objects/descrobject.c M Objects/typeobject.c M PC/pyconfig.h M PC/python3dll.c M PCbuild/_testcapi.vcxproj M PCbuild/_testcapi.vcxproj.filters M Python/structmember.c M configure M configure.ac M pyconfig.h.in diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 0a12bb9e8c54..a0c3194ab0fb 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -395,3 +395,42 @@ Object Protocol returns ``NULL`` if the object cannot be iterated. .. versionadded:: 3.10 + +.. c:function:: void *PyObject_GetTypeData(PyObject *o, PyTypeObject *cls) + + Get a pointer to subclass-specific data reserved for *cls*. + + The object *o* must be an instance of *cls*, and *cls* must have been + created using negative :c:member:`PyType_Spec.basicsize`. + Python does not check this. + + On error, set an exception and return ``NULL``. + + .. versionadded:: 3.12 + +.. c:function:: Py_ssize_t PyType_GetTypeDataSize(PyTypeObject *cls) + + Return the size of the instance memory space reserved for *cls*, i.e. the size of the + memory :c:func:`PyObject_GetTypeData` returns. + + This may be larger than requested using :c:member:`-PyType_Spec.basicsize <PyType_Spec.basicsize>`; + it is safe to use this larger size (e.g. with :c:func:`!memset`). + + The type *cls* **must** have been created using + negative :c:member:`PyType_Spec.basicsize`. + Python does not check this. + + On error, set an exception and return a negative value. + + .. versionadded:: 3.12 + +.. c:function:: void *PyObject_GetItemData(PyObject *o) + + Get a pointer to per-item data for a class with + :const:`Py_TPFLAGS_ITEMS_AT_END`. + + On error, set an exception and return ``NULL``. + :py:exc:`TypeError` is raised if *o* does not have + :const:`Py_TPFLAGS_ITEMS_AT_END` set. + + .. versionadded:: 3.12 diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 9618a0cf6769..338db6378d24 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -486,6 +486,22 @@ The following flags can be used with :c:member:`PyMemberDef.flags`: Emit an ``object.__getattr__`` :ref:`audit event <audit-events>` before reading. +.. c:macro:: Py_RELATIVE_OFFSET + + Indicates that the :c:member:`~PyMemberDef.offset` of this ``PyMemberDef`` + entry indicates an offset from the subclass-specific data, rather than + from ``PyObject``. + + Can only be used as part of :c:member:`Py_tp_members <PyTypeObject.tp_members>` + :c:type:`slot <PyTypeSlot>` when creating a class using negative + :c:member:`~PyTypeDef.basicsize`. + It is mandatory in that case. + + This flag is only used in :c:type:`PyTypeSlot`. + When setting :c:member:`~PyTypeObject.tp_members` during + class creation, Python clears it and sets + :c:member:`PyMemberDef.offset` to the offset from the ``PyObject`` struct. + .. index:: single: READ_RESTRICTED single: WRITE_RESTRICTED diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 9fd40e1008c4..c21fd9255d28 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -353,25 +353,57 @@ The following functions and structs are used to create Structure defining a type's behavior. - .. c:member:: const char* PyType_Spec.name + .. c:member:: const char* name Name of the type, used to set :c:member:`PyTypeObject.tp_name`. - .. c:member:: int PyType_Spec.basicsize - .. c:member:: int PyType_Spec.itemsize + .. c:member:: int basicsize - Size of the instance in bytes, used to set - :c:member:`PyTypeObject.tp_basicsize` and - :c:member:`PyTypeObject.tp_itemsize`. + If positive, specifies the size of the instance in bytes. + It is used to set :c:member:`PyTypeObject.tp_basicsize`. - .. c:member:: int PyType_Spec.flags + If zero, specifies that :c:member:`~PyTypeObject.tp_basicsize` + should be inherited. + + If negative, the absolute value specifies how much space instances of the + class need *in addition* to the superclass. + Use :c:func:`PyObject_GetTypeData` to get a pointer to subclass-specific + memory reserved this way. + + .. versionchanged:: 3.12 + + Previously, this field could not be negative. + + .. c:member:: int itemsize + + Size of one element of a variable-size type, in bytes. + Used to set :c:member:`PyTypeObject.tp_itemsize`. + See ``tp_itemsize`` documentation for caveats. + + If zero, :c:member:`~PyTypeObject.tp_itemsize` is inherited. + Extending arbitrary variable-sized classes is dangerous, + since some types use a fixed offset for variable-sized memory, + which can then overlap fixed-sized memory used by a subclass. + To help prevent mistakes, inheriting ``itemsize`` is only possible + in the following situations: + + - The base is not variable-sized (its + :c:member:`~PyTypeObject.tp_itemsize`). + - The requested :c:member:`PyType_Spec.basicsize` is positive, + suggesting that the memory layout of the base class is known. + - The requested :c:member:`PyType_Spec.basicsize` is zero, + suggesting that the subclass does not access the instance's memory + directly. + - With the :const:`Py_TPFLAGS_ITEMS_AT_END` flag. + + .. c:member:: unsigned int flags Type flags, used to set :c:member:`PyTypeObject.tp_flags`. If the ``Py_TPFLAGS_HEAPTYPE`` flag is not set, :c:func:`PyType_FromSpecWithBases` sets it automatically. - .. c:member:: PyType_Slot *PyType_Spec.slots + .. c:member:: PyType_Slot *slots Array of :c:type:`PyType_Slot` structures. Terminated by the special slot value ``{0, NULL}``. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index e963b90628aa..e13db3fb2211 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1171,6 +1171,26 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:member:`~PyTypeObject.tp_weaklistoffset` field is set in a superclass. + .. data:: Py_TPFLAGS_ITEMS_AT_END + + Only usable with variable-size types, i.e. ones with non-zero + :c:member:`~PyObject.tp_itemsize`. + + Indicates that the variable-sized portion of an instance of this type is + at the end of the instance's memory area, at an offset of + :c:expr:`Py_TYPE(obj)->tp_basicsize` (which may be different in each + subclass). + + When setting this flag, be sure that all superclasses either + use this memory layout, or are not variable-sized. + Python does not check this. + + .. versionadded:: 3.12 + + **Inheritance:** + + This flag is inherited. + .. XXX Document more flags here? diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 4cc06d22baaa..f112d268129f 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -521,6 +521,7 @@ function,PyObject_GetAttrString,3.2,, function,PyObject_GetBuffer,3.11,, function,PyObject_GetItem,3.2,, function,PyObject_GetIter,3.2,, +function,PyObject_GetTypeData,3.12,, function,PyObject_HasAttr,3.2,, function,PyObject_HasAttrString,3.2,, function,PyObject_Hash,3.2,, @@ -675,6 +676,7 @@ function,PyType_GetModuleState,3.10,, function,PyType_GetName,3.11,, function,PyType_GetQualName,3.11,, function,PyType_GetSlot,3.4,, +function,PyType_GetTypeDataSize,3.12,, function,PyType_IsSubtype,3.2,, function,PyType_Modified,3.2,, function,PyType_Ready,3.2,, diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3dfd787e3df8..edbf92146755 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1159,6 +1159,21 @@ New Features (Contributed by Petr Viktorin in :gh:`101101`.) +* :pep:`697`: Added API for extending types whose instance memory layout is + opaque: + + - :c:member:`PyType_Spec.basicsize` can be zero or negative to specify + inheriting or extending the base class size. + - :c:func:`PyObject_GetTypeData` and :c:func:`PyType_GetTypeDataSize` + added to allow access to subclass-specific instance data. + - :const:`Py_TPFLAGS_ITEMS_AT_END` and :c:func:`PyObject_GetItemData` + added to allow safely extending certain variable-sized types, including + :c:var:`PyType_Type`. + - :c:macro:`Py_RELATIVE_OFFSET` added to allow defining + :c:type:`members <PyMemberDef>` in terms of a subclass-specific struct. + + (Contributed by Petr Viktorin in :gh:`103509`.) + * Added the new limited C API function :c:func:`PyType_FromMetaclass`, which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass argument. diff --git a/Include/cpython/object.h b/Include/cpython/object.h index ce4d13cd9c28..d8eff691039d 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -553,6 +553,7 @@ Py_DEPRECATED(3.11) typedef int UsingDeprecatedTrashcanMacro; Py_TRASHCAN_END; \ } while(0); +PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj); PyAPI_FUNC(int) _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg); PyAPI_FUNC(void) _PyObject_ClearManagedDict(PyObject *obj); diff --git a/Include/descrobject.h b/Include/descrobject.h index 0a420b865dfd..fd66d17b497a 100644 --- a/Include/descrobject.h +++ b/Include/descrobject.h @@ -83,6 +83,7 @@ struct PyMemberDef { #define Py_READONLY 1 #define Py_AUDIT_READ 2 // Added in 3.10, harmless no-op before that #define _Py_WRITE_RESTRICTED 4 // Deprecated, no-op. Do not reuse the value. +#define Py_RELATIVE_OFFSET 8 PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, PyMemberDef *); PyAPI_FUNC(int) PyMember_SetOne(char *, PyMemberDef *, PyObject *); diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 91853ad0525b..b9e700ea280c 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -389,11 +389,6 @@ extern PyObject ** _PyObject_ComputedDictPointer(PyObject *); extern void _PyObject_FreeInstanceAttributes(PyObject *obj); extern int _PyObject_IsInstanceDictEmpty(PyObject *); -// Access macro to the members which are floating "behind" the object -static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) { - return (PyMemberDef*)((char*)etype + Py_TYPE(etype)->tp_basicsize); -} - PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, PyObject *); /* C function call trampolines to mitigate bad function pointer casts. diff --git a/Include/object.h b/Include/object.h index 66c3df0d7f78..81aeb2d8bd5a 100644 --- a/Include/object.h +++ b/Include/object.h @@ -355,6 +355,8 @@ PyAPI_FUNC(PyObject *) PyType_GetQualName(PyTypeObject *); #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 PyAPI_FUNC(PyObject *) PyType_FromMetaclass(PyTypeObject*, PyObject*, PyType_Spec*, PyObject*); +PyAPI_FUNC(void *) PyObject_GetTypeData(PyObject *obj, PyTypeObject *cls); +PyAPI_FUNC(Py_ssize_t) PyType_GetTypeDataSize(PyTypeObject *cls); #endif /* Generic type check */ @@ -521,6 +523,9 @@ given type object has a specified feature. // subject itself (rather than a mapped attribute on it): #define _Py_TPFLAGS_MATCH_SELF (1UL << 22) +/* Items (ob_size*tp_itemsize) are found at the end of an instance's memory */ +#define Py_TPFLAGS_ITEMS_AT_END (1UL << 23) + /* These flags are used to determine if a type is a subclass. */ #define Py_TPFLAGS_LONG_SUBCLASS (1UL << 24) #define Py_TPFLAGS_LIST_SUBCLASS (1UL << 25) diff --git a/Include/pyport.h b/Include/pyport.h index bd0ba6d0681b..d7c6ae64f2bf 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -765,4 +765,15 @@ extern char * _getpty(int *, int, mode_t, int); #undef __bool__ #endif +// Make sure we have maximum alignment, even if the current compiler +// does not support max_align_t. Note that: +// - Autoconf reports alignment of unknown types to 0. +// - 'long double' has maximum alignment on *most* platforms, +// looks like the best we can do for pre-C11 compilers. +// - The value is tested, see test_alignof_max_align_t +#if !defined(ALIGNOF_MAX_ALIGN_T) || ALIGNOF_MAX_ALIGN_T == 0 +# undef ALIGNOF_MAX_ALIGN_T +# define ALIGNOF_MAX_ALIGN_T _Alignof(long double) +#endif + #endif /* Py_PYPORT_H */ diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 1d426d0f8f82..22be3c081427 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -16,11 +16,13 @@ import unittest import warnings import weakref +import operator from test import support from test.support import MISSING_C_DOCSTRINGS from test.support import import_helper from test.support import threading_helper from test.support import warnings_helper +from test.support import requires_limited_api from test.support.script_helper import assert_python_failure, assert_python_ok, run_python_until_end try: import _posixsubprocess @@ -770,7 +772,6 @@ def meth(self): MutableBase.meth = lambda self: 'changed' self.assertEqual(instance.meth(), 'changed') - def test_pynumber_tobase(self): from _testcapi import pynumber_tobase small_number = 123 @@ -1072,6 +1073,161 @@ class Data(_testcapi.ObjExtraData): self.assertIsNone(d.extra) + at requires_limited_api +class TestHeapTypeRelative(unittest.TestCase): + """Test API for extending opaque types (PEP 697)""" + + @requires_limited_api + def test_heaptype_relative_sizes(self): + # Test subclassing using "relative" basicsize, see PEP 697 + def check(extra_base_size, extra_size): + Base, Sub, instance, data_ptr, data_offset, data_size = ( + _testcapi.make_sized_heaptypes( + extra_base_size, -extra_size)) + + # no alignment shenanigans when inheriting directly + if extra_size == 0: + self.assertEqual(Base.__basicsize__, Sub.__basicsize__) + self.assertEqual(data_size, 0) + + else: + # The following offsets should be in increasing order: + offsets = [ + (0, 'start of object'), + (Base.__basicsize__, 'end of base data'), + (data_offset, 'subclass data'), + (data_offset + extra_size, 'end of requested subcls data'), + (data_offset + data_size, 'end of reserved subcls data'), + (Sub.__basicsize__, 'end of object'), + ] + ordered_offsets = sorted(offsets, key=operator.itemgetter(0)) + self.assertEqual( + offsets, ordered_offsets, + msg=f'Offsets not in expected order, got: {ordered_offsets}') + + # end of reserved subcls data == end of object + self.assertEqual(Sub.__basicsize__, data_offset + data_size) + + # we don't reserve (requested + alignment) or more data + self.assertLess(data_size - extra_size, + _testcapi.ALIGNOF_MAX_ALIGN_T) + + # The offsets/sizes we calculated should be aligned. + self.assertEqual(data_offset % _testcapi.ALIGNOF_MAX_ALIGN_T, 0) + self.assertEqual(data_size % _testcapi.ALIGNOF_MAX_ALIGN_T, 0) + + sizes = sorted({0, 1, 2, 3, 4, 7, 8, 123, + object.__basicsize__, + object.__basicsize__-1, + object.__basicsize__+1}) + for extra_base_size in sizes: + for extra_size in sizes: + args = dict(extra_base_size=extra_base_size, + extra_size=extra_size) + with self.subTest(**args): + check(**args) + + def test_HeapCCollection(self): + """Make sure HeapCCollection works properly by itself""" + collection = _testcapi.HeapCCollection(1, 2, 3) + self.assertEqual(list(collection), [1, 2, 3]) + + def test_heaptype_inherit_itemsize(self): + """Test HeapCCollection subclasses work properly""" + sizes = sorted({0, 1, 2, 3, 4, 7, 8, 123, + object.__basicsize__, + object.__basicsize__-1, + object.__basicsize__+1}) + for extra_size in sizes: + with self.subTest(extra_size=extra_size): + Sub = _testcapi.subclass_var_heaptype( + _testcapi.HeapCCollection, -extra_size, 0, 0) + collection = Sub(1, 2, 3) + collection.set_data_to_3s() + + self.assertEqual(list(collection), [1, 2, 3]) + mem = collection.get_data() + self.assertGreaterEqual(len(mem), extra_size) + self.assertTrue(set(mem) <= {3}, f'got {mem!r}') + + def test_heaptype_invalid_inheritance(self): + with self.assertRaises(SystemError, + msg="Cannot extend variable-size class without " + + "Py_TPFLAGS_ITEMS_AT_END"): + _testcapi.subclass_heaptype(int, -8, 0) + + def test_heaptype_relative_members(self): + """Test HeapCCollection subclasses work properly""" + sizes = sorted({0, 1, 2, 3, 4, 7, 8, 123, + object.__basicsize__, + object.__basicsize__-1, + object.__basicsize__+1}) + for extra_base_size in sizes: + for extra_size in sizes: + for offset in sizes: + with self.subTest(extra_base_size=extra_base_size, extra_size=extra_size, offset=offset): + if offset < extra_size: + Sub = _testcapi.make_heaptype_with_member( + extra_base_size, -extra_size, offset, True) + Base = Sub.mro()[1] + instance = Sub() + self.assertEqual(instance.memb, instance.get_memb()) + instance.set_memb(13) + self.assertEqual(instance.memb, instance.get_memb()) + self.assertEqual(instance.get_memb(), 13) + instance.memb = 14 + self.assertEqual(instance.memb, instance.get_memb()) + self.assertEqual(instance.get_memb(), 14) + self.assertGreaterEqual(instance.get_memb_offset(), Base.__basicsize__) + self.assertLess(instance.get_memb_offset(), Sub.__basicsize__) + with self.assertRaises(SystemError): + instance.get_memb_relative() + with self.assertRaises(SystemError): + instance.set_memb_relative(0) + else: + with self.assertRaises(SystemError): + Sub = _testcapi.make_heaptype_with_member( + extra_base_size, -extra_size, offset, True) + with self.assertRaises(SystemError): + Sub = _testcapi.make_heaptype_with_member( + extra_base_size, extra_size, offset, True) + with self.subTest(extra_base_size=extra_base_size, extra_size=extra_size): + with self.assertRaises(SystemError): + Sub = _testcapi.make_heaptype_with_member( + extra_base_size, -extra_size, -1, True) + + def test_heaptype_relative_members_errors(self): + with self.assertRaisesRegex( + SystemError, + r"With Py_RELATIVE_OFFSET, basicsize must be negative"): + _testcapi.make_heaptype_with_member(0, 1234, 0, True) + with self.assertRaisesRegex( + SystemError, r"Member offset out of range \(0\.\.-basicsize\)"): + _testcapi.make_heaptype_with_member(0, -8, 1234, True) + with self.assertRaisesRegex( + SystemError, r"Member offset out of range \(0\.\.-basicsize\)"): + _testcapi.make_heaptype_with_member(0, -8, -1, True) + + Sub = _testcapi.make_heaptype_with_member(0, -8, 0, True) + instance = Sub() + with self.assertRaisesRegex( + SystemError, r"PyMember_GetOne used with Py_RELATIVE_OFFSET"): + instance.get_memb_relative() + with self.assertRaisesRegex( + SystemError, r"PyMember_SetOne used with Py_RELATIVE_OFFSET"): + instance.set_memb_relative(0) + + def test_pyobject_getitemdata_error(self): + """Test PyObject_GetItemData fails on unsupported types""" + with self.assertRaises(TypeError): + # None is not variable-length + _testcapi.pyobject_getitemdata(None) + with self.assertRaises(TypeError): + # int is variable-length, but doesn't have the + # Py_TPFLAGS_ITEMS_AT_END layout (and flag) + _testcapi.pyobject_getitemdata(0) + + class TestPendingCalls(unittest.TestCase): def pendingcalls_submit(self, l, n): diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 2feaaf8603b8..4ca39d85e546 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -529,6 +529,7 @@ def test_windows_feature_macros(self): "PyObject_GetBuffer", "PyObject_GetItem", "PyObject_GetIter", + "PyObject_GetTypeData", "PyObject_HasAttr", "PyObject_HasAttrString", "PyObject_Hash", @@ -679,6 +680,7 @@ def test_windows_feature_macros(self): "PyType_GetName", "PyType_GetQualName", "PyType_GetSlot", + "PyType_GetTypeDataSize", "PyType_IsSubtype", "PyType_Modified", "PyType_Ready", diff --git a/Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst b/Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst new file mode 100644 index 000000000000..af630c3aafa9 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst @@ -0,0 +1,5 @@ +Added C API for extending types whose instance memory layout is opaque: +:c:member:`PyType_Spec.basicsize` can now be zero or negative, +:c:func:`PyObject_GetTypeData` can be used to get subclass-specific data, +and :c:macro:`Py_TPFLAGS_ITEMS_AT_END` can be used to safely extend +variable-size objects. See :pep:`697` for details. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 23baeeeae791..48299e9b35ff 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2397,3 +2397,12 @@ added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix [const.Py_AUDIT_READ] added = '3.12' # Before 3.12, available in "structmember.h" + +[function.PyObject_GetTypeData] + added = '3.12' +[function.PyType_GetTypeDataSize] + added = '3.12' +[const.Py_RELATIVE_OFFSET] + added = '3.12' +[const.Py_TPFLAGS_ITEMS_AT_END] + added = '3.12' diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index a90c1e96ef02..6b4833419537 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE at _xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE at _testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE at _testinternalcapi _testinternalcapi.c - at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c _testcapi/immortal.c + at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c @MODULE__TESTCLINIC_TRUE at _testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index 6384fbc485fb..3488e35922c5 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -371,7 +371,6 @@ create_type_from_repeated_slots(PyObject *self, PyObject *variant_obj) } - static PyObject * make_immutable_type_with_base(PyObject *self, PyObject *base) { @@ -399,6 +398,17 @@ make_type_with_base(PyObject *self, PyObject *base) } +static PyObject * +pyobject_getitemdata(PyObject *self, PyObject *o) +{ + void *pointer = PyObject_GetItemData(o); + if (pointer == NULL) { + return NULL; + } + return PyLong_FromVoidPtr(pointer); +} + + static PyMethodDef TestMethods[] = { {"pytype_fromspec_meta", pytype_fromspec_meta, METH_O}, {"test_type_from_ephemeral_spec", test_type_from_ephemeral_spec, METH_NOARGS}, @@ -411,6 +421,7 @@ static PyMethodDef TestMethods[] = { METH_NOARGS}, {"make_immutable_type_with_base", make_immutable_type_with_base, METH_O}, {"make_type_with_base", make_type_with_base, METH_O}, + {"pyobject_getitemdata", pyobject_getitemdata, METH_O}, {NULL}, }; @@ -987,6 +998,113 @@ static PyType_Spec HeapCTypeSetattr_spec = { HeapCTypeSetattr_slots }; +PyDoc_STRVAR(HeapCCollection_doc, +"Tuple-like heap type that uses PyObject_GetItemData for items."); + +static PyObject* +HeapCCollection_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) +{ + PyObject *self = NULL; + PyObject *result = NULL; + + Py_ssize_t size = PyTuple_GET_SIZE(args); + self = subtype->tp_alloc(subtype, size); + if (!self) { + goto finally; + } + PyObject **data = PyObject_GetItemData(self); + if (!data) { + goto finally; + } + + for (Py_ssize_t i = 0; i < size; i++) { + data[i] = Py_NewRef(PyTuple_GET_ITEM(args, i)); + } + + result = self; + self = NULL; + finally: + Py_XDECREF(self); + return result; +} + +static Py_ssize_t +HeapCCollection_length(PyVarObject *self) +{ + return Py_SIZE(self); +} + +static PyObject* +HeapCCollection_item(PyObject *self, Py_ssize_t i) +{ + if (i < 0 || i >= Py_SIZE(self)) { + return PyErr_Format(PyExc_IndexError, "index %zd out of range", i); + } + PyObject **data = PyObject_GetItemData(self); + if (!data) { + return NULL; + } + return Py_NewRef(data[i]); +} + +static int +HeapCCollection_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyObject **data = PyObject_GetItemData(self); + if (!data) { + return -1; + } + for (Py_ssize_t i = 0; i < Py_SIZE(self); i++) { + Py_VISIT(data[i]); + } + return 0; +} + +static int +HeapCCollection_clear(PyObject *self) +{ + PyObject **data = PyObject_GetItemData(self); + if (!data) { + return -1; + } + Py_ssize_t size = Py_SIZE(self); + Py_SET_SIZE(self, 0); + for (Py_ssize_t i = 0; i < size; i++) { + Py_CLEAR(data[i]); + } + return 0; +} + +static void +HeapCCollection_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + HeapCCollection_clear(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot HeapCCollection_slots[] = { + {Py_tp_new, HeapCCollection_new}, + {Py_sq_length, HeapCCollection_length}, + {Py_sq_item, HeapCCollection_item}, + {Py_tp_traverse, HeapCCollection_traverse}, + {Py_tp_clear, HeapCCollection_clear}, + {Py_tp_dealloc, HeapCCollection_dealloc}, + {Py_tp_doc, (void *)HeapCCollection_doc}, + {0, 0}, +}; + +static PyType_Spec HeapCCollection_spec = { + .name = "_testcapi.HeapCCollection", + .basicsize = sizeof(PyVarObject), + .itemsize = sizeof(PyObject*), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_ITEMS_AT_END), + .slots = HeapCCollection_slots, +}; + int _PyTestCapi_Init_Heaptype(PyObject *m) { _testcapimodule = PyModule_GetDef(m); @@ -1110,5 +1228,16 @@ _PyTestCapi_Init_Heaptype(PyObject *m) { } PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew); + PyObject *HeapCCollection = PyType_FromMetaclass( + NULL, m, &HeapCCollection_spec, NULL); + if (HeapCCollection == NULL) { + return -1; + } + int rc = PyModule_AddType(m, (PyTypeObject *)HeapCCollection); + Py_DECREF(HeapCCollection); + if (rc < 0) { + return -1; + } + return 0; } diff --git a/Modules/_testcapi/heaptype_relative.c b/Modules/_testcapi/heaptype_relative.c new file mode 100644 index 000000000000..c247ca33b337 --- /dev/null +++ b/Modules/_testcapi/heaptype_relative.c @@ -0,0 +1,343 @@ +#define Py_LIMITED_API 0x030c0000 // 3.12 +#include "parts.h" +#include <stddef.h> // max_align_t +#include <string.h> // memset + +#ifdef LIMITED_API_AVAILABLE + +static PyType_Slot empty_slots[] = { + {0, NULL}, +}; + +static PyObject * +make_sized_heaptypes(PyObject *module, PyObject *args) +{ + PyObject *base = NULL; + PyObject *sub = NULL; + PyObject *instance = NULL; + PyObject *result = NULL; + + int extra_base_size, basicsize; + + int r = PyArg_ParseTuple(args, "ii", &extra_base_size, &basicsize); + if (!r) { + goto finally; + } + + PyType_Spec base_spec = { + .name = "_testcapi.Base", + .basicsize = sizeof(PyObject) + extra_base_size, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = empty_slots, + }; + PyType_Spec sub_spec = { + .name = "_testcapi.Sub", + .basicsize = basicsize, + .flags = Py_TPFLAGS_DEFAULT, + .slots = empty_slots, + }; + + base = PyType_FromMetaclass(NULL, module, &base_spec, NULL); + if (!base) { + goto finally; + } + sub = PyType_FromMetaclass(NULL, module, &sub_spec, base); + if (!sub) { + goto finally; + } + instance = PyObject_CallNoArgs(sub); + if (!instance) { + goto finally; + } + char *data_ptr = PyObject_GetTypeData(instance, (PyTypeObject *)sub); + if (!data_ptr) { + goto finally; + } + Py_ssize_t data_size = PyType_GetTypeDataSize((PyTypeObject *)sub); + if (data_size < 0) { + goto finally; + } + + result = Py_BuildValue("OOOKnn", base, sub, instance, + (unsigned long long)data_ptr, + (Py_ssize_t)(data_ptr - (char*)instance), + data_size); + finally: + Py_XDECREF(base); + Py_XDECREF(sub); + Py_XDECREF(instance); + return result; +} + +static PyObject * +var_heaptype_set_data_to_3s( + PyObject *self, PyTypeObject *defining_class, + PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + void *data_ptr = PyObject_GetTypeData(self, defining_class); + if (!data_ptr) { + return NULL; + } + Py_ssize_t data_size = PyType_GetTypeDataSize(defining_class); + if (data_size < 0) { + return NULL; + } + memset(data_ptr, 3, data_size); + Py_RETURN_NONE; +} + +static PyObject * +var_heaptype_get_data(PyObject *self, PyTypeObject *defining_class, + PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + void *data_ptr = PyObject_GetTypeData(self, defining_class); + if (!data_ptr) { + return NULL; + } + Py_ssize_t data_size = PyType_GetTypeDataSize(defining_class); + if (data_size < 0) { + return NULL; + } + return PyBytes_FromStringAndSize(data_ptr, data_size); +} + +static PyMethodDef var_heaptype_methods[] = { + {"set_data_to_3s", _PyCFunction_CAST(var_heaptype_set_data_to_3s), + METH_METHOD | METH_FASTCALL | METH_KEYWORDS}, + {"get_data", _PyCFunction_CAST(var_heaptype_get_data), + METH_METHOD | METH_FASTCALL | METH_KEYWORDS}, + {NULL}, +}; + +static PyObject * +subclass_var_heaptype(PyObject *module, PyObject *args) +{ + PyObject *result = NULL; + + PyObject *base; // borrowed from args + int basicsize, itemsize; + long pfunc; + + int r = PyArg_ParseTuple(args, "Oiil", &base, &basicsize, &itemsize, &pfunc); + if (!r) { + goto finally; + } + + PyType_Slot slots[] = { + {Py_tp_methods, var_heaptype_methods}, + {0, NULL}, + }; + + PyType_Spec sub_spec = { + .name = "_testcapi.Sub", + .basicsize = basicsize, + .itemsize = itemsize, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_ITEMS_AT_END, + .slots = slots, + }; + + result = PyType_FromMetaclass(NULL, module, &sub_spec, base); + finally: + return result; +} + +static PyObject * +subclass_heaptype(PyObject *module, PyObject *args) +{ + PyObject *result = NULL; + + PyObject *base; // borrowed from args + int basicsize, itemsize; + + int r = PyArg_ParseTuple(args, "Oii", &base, &basicsize, &itemsize); + if (!r) { + goto finally; + } + + PyType_Slot slots[] = { + {Py_tp_methods, var_heaptype_methods}, + {0, NULL}, + }; + + PyType_Spec sub_spec = { + .name = "_testcapi.Sub", + .basicsize = basicsize, + .itemsize = itemsize, + .flags = Py_TPFLAGS_DEFAULT, + .slots = slots, + }; + + result = PyType_FromMetaclass(NULL, module, &sub_spec, base); + finally: + return result; +} + +static PyMemberDef * +heaptype_with_member_extract_and_check_memb(PyObject *self) +{ + PyMemberDef *def = PyType_GetSlot(Py_TYPE(self), Py_tp_members); + if (!def) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "tp_members is NULL"); + } + return NULL; + } + if (!def[0].name) { + PyErr_SetString(PyExc_ValueError, "tp_members[0] is NULL"); + return NULL; + } + if (def[1].name) { + PyErr_SetString(PyExc_ValueError, "tp_members[1] is not NULL"); + return NULL; + } + if (strcmp(def[0].name, "memb")) { + PyErr_SetString(PyExc_ValueError, "tp_members[0] is not for `memb`"); + return NULL; + } + if (def[0].flags) { + PyErr_SetString(PyExc_ValueError, "tp_members[0] has flags set"); + return NULL; + } + return def; +} + +static PyObject * +heaptype_with_member_get_memb(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyMemberDef *def = heaptype_with_member_extract_and_check_memb(self); + return PyMember_GetOne((const char *)self, def); +} + +static PyObject * +heaptype_with_member_set_memb(PyObject *self, PyObject *value) +{ + PyMemberDef *def = heaptype_with_member_extract_and_check_memb(self); + int r = PyMember_SetOne((char *)self, def, value); + if (r < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +get_memb_offset(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyMemberDef *def = heaptype_with_member_extract_and_check_memb(self); + return PyLong_FromSsize_t(def->offset); +} + +static PyObject * +heaptype_with_member_get_memb_relative(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyMemberDef def = {"memb", Py_T_BYTE, sizeof(PyObject), Py_RELATIVE_OFFSET}; + return PyMember_GetOne((const char *)self, &def); +} + +static PyObject * +heaptype_with_member_set_memb_relative(PyObject *self, PyObject *value) +{ + PyMemberDef def = {"memb", Py_T_BYTE, sizeof(PyObject), Py_RELATIVE_OFFSET}; + int r = PyMember_SetOne((char *)self, &def, value); + if (r < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static PyMethodDef heaptype_with_member_methods[] = { + {"get_memb", heaptype_with_member_get_memb, METH_NOARGS}, + {"set_memb", heaptype_with_member_set_memb, METH_O}, + {"get_memb_offset", get_memb_offset, METH_NOARGS}, + {"get_memb_relative", heaptype_with_member_get_memb_relative, METH_NOARGS}, + {"set_memb_relative", heaptype_with_member_set_memb_relative, METH_O}, + {NULL}, +}; + +static PyObject * +make_heaptype_with_member(PyObject *module, PyObject *args) +{ + PyObject *base = NULL; + PyObject *result = NULL; + + int extra_base_size, basicsize, offset, add_flag; + + int r = PyArg_ParseTuple(args, "iiip", &extra_base_size, &basicsize, &offset, &add_flag); + if (!r) { + goto finally; + } + + PyType_Spec base_spec = { + .name = "_testcapi.Base", + .basicsize = sizeof(PyObject) + extra_base_size, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = empty_slots, + }; + base = PyType_FromMetaclass(NULL, module, &base_spec, NULL); + if (!base) { + goto finally; + } + + PyMemberDef members[] = { + {"memb", Py_T_BYTE, offset, add_flag ? Py_RELATIVE_OFFSET : 0}, + {0}, + }; + PyType_Slot slots[] = { + {Py_tp_members, members}, + {Py_tp_methods, heaptype_with_member_methods}, + {0, NULL}, + }; + + PyType_Spec sub_spec = { + .name = "_testcapi.Sub", + .basicsize = basicsize, + .flags = Py_TPFLAGS_DEFAULT, + .slots = slots, + }; + + result = PyType_FromMetaclass(NULL, module, &sub_spec, base); + finally: + Py_XDECREF(base); + return result; +} + + +static PyObject * +test_alignof_max_align_t(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + // We define ALIGNOF_MAX_ALIGN_T even if the compiler doesn't support + // max_align_t. Double-check that it's correct. + assert(ALIGNOF_MAX_ALIGN_T > 0); + assert(ALIGNOF_MAX_ALIGN_T >= _Alignof(long long)); + assert(ALIGNOF_MAX_ALIGN_T >= _Alignof(long double)); + assert(ALIGNOF_MAX_ALIGN_T >= _Alignof(void*)); + assert(ALIGNOF_MAX_ALIGN_T >= _Alignof(void (*)(void))); + + // Ensure it's a power of two + assert((ALIGNOF_MAX_ALIGN_T & (ALIGNOF_MAX_ALIGN_T - 1)) == 0); + + Py_RETURN_NONE; +} + +static PyMethodDef TestMethods[] = { + {"make_sized_heaptypes", make_sized_heaptypes, METH_VARARGS}, + {"subclass_var_heaptype", subclass_var_heaptype, METH_VARARGS}, + {"subclass_heaptype", subclass_heaptype, METH_VARARGS}, + {"make_heaptype_with_member", make_heaptype_with_member, METH_VARARGS}, + {"test_alignof_max_align_t", test_alignof_max_align_t, METH_NOARGS}, + {NULL}, +}; + +int +_PyTestCapi_Init_HeaptypeRelative(PyObject *m) { + if (PyModule_AddFunctions(m, TestMethods) < 0) { + return -1; + } + + if (PyModule_AddIntMacro(m, ALIGNOF_MAX_ALIGN_T) < 0) { + return -1; + } + + return 0; +} + +#endif // LIMITED_API_AVAILABLE diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index 4d2d6832a827..d75412d51160 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -43,6 +43,7 @@ int _PyTestCapi_Init_Immortal(PyObject *module); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); +int _PyTestCapi_Init_HeaptypeRelative(PyObject *module); #endif // LIMITED_API_AVAILABLE #endif diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 47e0ed9be8e7..1ecc44205808 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4324,6 +4324,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_VectorcallLimited(m) < 0) { return NULL; } + if (_PyTestCapi_Init_HeaptypeRelative(m) < 0) { + return NULL; + } #endif PyState_AddModule(m, &_testcapimodule); diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 334be75e8df9..17c0c85a06c4 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -978,6 +978,12 @@ PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) { PyMemberDescrObject *descr; + if (member->flags & Py_RELATIVE_OFFSET) { + PyErr_SetString( + PyExc_SystemError, + "PyDescr_NewMember used with Py_RELATIVE_OFFSET"); + return NULL; + } descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type, type, member->name); if (descr != NULL) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4ced04b0bde9..171c76a59a55 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -18,6 +18,7 @@ #include "structmember.h" // PyMemberDef #include <ctype.h> +#include <stddef.h> // ptrdiff_t /*[clinic input] class type "PyTypeObject *" "&PyType_Type" @@ -1686,6 +1687,12 @@ PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds) /* Helpers for subtyping */ +static inline PyMemberDef * +_PyHeapType_GET_MEMBERS(PyHeapTypeObject* type) +{ + return PyObject_GetItemData((PyObject *)type); +} + static int traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg) { @@ -3873,6 +3880,15 @@ static const PySlot_Offset pyslot_offsets[] = { #include "typeslots.inc" }; +/* Align up to the nearest multiple of alignof(max_align_t) + * (like _Py_ALIGN_UP, but for a size rather than pointer) + */ +static Py_ssize_t +_align_up(Py_ssize_t size) +{ + return (size + ALIGNOF_MAX_ALIGN_T - 1) & ~(ALIGNOF_MAX_ALIGN_T - 1); +} + /* Given a PyType_FromMetaclass `bases` argument (NULL, type, or tuple of * types), return a tuple of types. */ @@ -4013,6 +4029,20 @@ _PyType_FromMetaclass_impl( assert(memb->flags == READONLY); vectorcalloffset = memb->offset; } + if (memb->flags & Py_RELATIVE_OFFSET) { + if (spec->basicsize > 0) { + PyErr_SetString( + PyExc_SystemError, + "With Py_RELATIVE_OFFSET, basicsize must be negative."); + goto finally; + } + if (memb->offset < 0 || memb->offset >= -spec->basicsize) { + PyErr_SetString( + PyExc_SystemError, + "Member offset out of range (0..-basicsize)"); + goto finally; + } + } } break; case Py_tp_doc: @@ -4154,6 +4184,32 @@ _PyType_FromMetaclass_impl( // here we just check its work assert(_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)); + /* Calculate sizes */ + + Py_ssize_t basicsize = spec->basicsize; + Py_ssize_t type_data_offset = spec->basicsize; + if (basicsize == 0) { + /* Inherit */ + basicsize = base->tp_basicsize; + } + else if (basicsize < 0) { + /* Extend */ + type_data_offset = _align_up(base->tp_basicsize); + basicsize = type_data_offset + _align_up(-spec->basicsize); + + /* Inheriting variable-sized types is limited */ + if (base->tp_itemsize + && !((base->tp_flags | spec->flags) & Py_TPFLAGS_ITEMS_AT_END)) + { + PyErr_SetString( + PyExc_SystemError, + "Cannot extend variable-size class without Py_TPFLAGS_ITEMS_AT_END."); + goto finally; + } + } + + Py_ssize_t itemsize = spec->itemsize; + /* Allocate the new type * * Between here and PyType_Ready, we should limit: @@ -4201,8 +4257,8 @@ _PyType_FromMetaclass_impl( /* Copy the sizes */ - type->tp_basicsize = spec->basicsize; - type->tp_itemsize = spec->itemsize; + type->tp_basicsize = basicsize; + type->tp_itemsize = itemsize; /* Copy all the ordinary slots */ @@ -4219,6 +4275,16 @@ _PyType_FromMetaclass_impl( size_t len = Py_TYPE(type)->tp_itemsize * nmembers; memcpy(_PyHeapType_GET_MEMBERS(res), slot->pfunc, len); type->tp_members = _PyHeapType_GET_MEMBERS(res); + PyMemberDef *memb; + Py_ssize_t i; + for (memb = _PyHeapType_GET_MEMBERS(res), i = nmembers; + i > 0; ++memb, --i) + { + if (memb->flags & Py_RELATIVE_OFFSET) { + memb->flags &= ~Py_RELATIVE_OFFSET; + memb->offset += type_data_offset; + } + } } break; default: @@ -4227,6 +4293,7 @@ _PyType_FromMetaclass_impl( PySlot_Offset slotoffsets = pyslot_offsets[slot->slot]; short slot_offset = slotoffsets.slot_offset; if (slotoffsets.subslot_offset == -1) { + /* Set a slot in the main PyTypeObject */ *(void**)((char*)res_start + slot_offset) = slot->pfunc; } else { @@ -4461,6 +4528,34 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def) return NULL; } +void * +PyObject_GetTypeData(PyObject *obj, PyTypeObject *cls) +{ + assert(PyObject_TypeCheck(obj, cls)); + return (char *)obj + _align_up(cls->tp_base->tp_basicsize); +} + +Py_ssize_t +PyType_GetTypeDataSize(PyTypeObject *cls) +{ + ptrdiff_t result = cls->tp_basicsize - _align_up(cls->tp_base->tp_basicsize); + if (result < 0) { + return 0; + } + return result; +} + +void * +PyObject_GetItemData(PyObject *obj) +{ + if (!PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_ITEMS_AT_END)) { + PyErr_Format(PyExc_TypeError, + "type '%s' does not have Py_TPFLAGS_ITEMS_AT_END", + Py_TYPE(obj)->tp_name); + return NULL; + } + return (char *)obj + Py_TYPE(obj)->tp_basicsize; +} /* Internal API to look for a name through the MRO, bypassing the method cache. This returns a borrowed reference, and might set an exception. @@ -5158,7 +5253,8 @@ PyTypeObject PyType_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS | - Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */ + Py_TPFLAGS_HAVE_VECTORCALL | + Py_TPFLAGS_ITEMS_AT_END, /* tp_flags */ type_doc, /* tp_doc */ (traverseproc)type_traverse, /* tp_traverse */ (inquiry)type_clear, /* tp_clear */ @@ -6572,9 +6668,14 @@ inherit_special(PyTypeObject *type, PyTypeObject *base) else if (PyType_IsSubtype(base, &PyDict_Type)) { type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; } + + /* Setup some inheritable flags */ if (PyType_HasFeature(base, _Py_TPFLAGS_MATCH_SELF)) { type->tp_flags |= _Py_TPFLAGS_MATCH_SELF; } + if (PyType_HasFeature(base, Py_TPFLAGS_ITEMS_AT_END)) { + type->tp_flags |= Py_TPFLAGS_ITEMS_AT_END; + } } static int diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 8a3bf8968ce2..3415efe2dea1 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -330,6 +330,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # define SIZEOF_HKEY 8 # define SIZEOF_SIZE_T 8 # define ALIGNOF_SIZE_T 8 +# define ALIGNOF_MAX_ALIGN_T 8 /* configure.ac defines HAVE_LARGEFILE_SUPPORT iff sizeof(off_t) > sizeof(long), and sizeof(long long) >= sizeof(off_t). On Win64 the second condition is not true, but if fpos_t replaces off_t @@ -351,6 +352,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # else # define SIZEOF_TIME_T 4 # endif +# define ALIGNOF_MAX_ALIGN_T 8 #endif #ifdef _DEBUG diff --git a/PC/python3dll.c b/PC/python3dll.c index 706affa18351..7e848abccfd1 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -467,6 +467,7 @@ EXPORT_FUNC(PyObject_GetAttrString) EXPORT_FUNC(PyObject_GetBuffer) EXPORT_FUNC(PyObject_GetItem) EXPORT_FUNC(PyObject_GetIter) +EXPORT_FUNC(PyObject_GetTypeData) EXPORT_FUNC(PyObject_HasAttr) EXPORT_FUNC(PyObject_HasAttrString) EXPORT_FUNC(PyObject_Hash) @@ -618,6 +619,7 @@ EXPORT_FUNC(PyType_GetModuleState) EXPORT_FUNC(PyType_GetName) EXPORT_FUNC(PyType_GetQualName) EXPORT_FUNC(PyType_GetSlot) +EXPORT_FUNC(PyType_GetTypeDataSize) EXPORT_FUNC(PyType_IsSubtype) EXPORT_FUNC(PyType_Modified) EXPORT_FUNC(PyType_Ready) diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 21941247eb96..56448b6ee7d4 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -98,6 +98,7 @@ <ClCompile Include="..\Modules\_testcapi\vectorcall.c" /> <ClCompile Include="..\Modules\_testcapi\vectorcall_limited.c" /> <ClCompile Include="..\Modules\_testcapi\heaptype.c" /> + <ClCompile Include="..\Modules\_testcapi\heaptype_relative.c" /> <ClCompile Include="..\Modules\_testcapi\unicode.c" /> <ClCompile Include="..\Modules\_testcapi\pytime.c" /> <ClCompile Include="..\Modules\_testcapi\datetime.c" /> diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 0e42e4982c21..297c9ce799be 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -24,6 +24,9 @@ <ClCompile Include="..\Modules\_testcapi\heaptype.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Modules\_testcapi\heaptype_relative.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Modules\_testcapi\unicode.c"> <Filter>Source Files</Filter> </ClCompile> diff --git a/Python/structmember.c b/Python/structmember.c index 1b8be28dcf2e..19a75224a0f3 100644 --- a/Python/structmember.c +++ b/Python/structmember.c @@ -8,6 +8,12 @@ PyObject * PyMember_GetOne(const char *obj_addr, PyMemberDef *l) { PyObject *v; + if (l->flags & Py_RELATIVE_OFFSET) { + PyErr_SetString( + PyExc_SystemError, + "PyMember_GetOne used with Py_RELATIVE_OFFSET"); + return NULL; + } const char* addr = obj_addr + l->offset; switch (l->type) { @@ -103,6 +109,12 @@ int PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) { PyObject *oldv; + if (l->flags & Py_RELATIVE_OFFSET) { + PyErr_SetString( + PyExc_SystemError, + "PyMember_SetOne used with Py_RELATIVE_OFFSET"); + return -1; + } addr += l->offset; diff --git a/configure b/configure index 8133d47f6135..b8fa9d66e735 100755 --- a/configure +++ b/configure @@ -10729,6 +10729,41 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# The cast to long int works around a bug in the HP C Compiler, +# see AC_CHECK_SIZEOF for more information. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of max_align_t" >&5 +$as_echo_n "checking alignment of max_align_t... " >&6; } +if ${ac_cv_alignof_max_align_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_max_align_t" "$ac_includes_default +#ifndef offsetof +# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) +#endif +typedef struct { char x; max_align_t y; } ac__type_alignof_;"; then : + +else + if test "$ac_cv_type_max_align_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute alignment of max_align_t +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_max_align_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_max_align_t" >&5 +$as_echo "$ac_cv_alignof_max_align_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define ALIGNOF_MAX_ALIGN_T $ac_cv_alignof_max_align_t +_ACEOF + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double" >&5 diff --git a/configure.ac b/configure.ac index 3f20d8980d8a..0940b93c25f7 100644 --- a/configure.ac +++ b/configure.ac @@ -2921,6 +2921,7 @@ AC_CHECK_SIZEOF(size_t, 4) AC_CHECK_ALIGNOF(size_t) AC_CHECK_SIZEOF(pid_t, 4) AC_CHECK_SIZEOF(uintptr_t) +AC_CHECK_ALIGNOF(max_align_t) AC_TYPE_LONG_DOUBLE AC_CHECK_SIZEOF(long double, 16) diff --git a/pyconfig.h.in b/pyconfig.h.in index 236cee6588d4..2c22b27af65e 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -19,6 +19,9 @@ /* The normal alignment of `long', in bytes. */ #undef ALIGNOF_LONG +/* The normal alignment of `max_align_t', in bytes. */ +#undef ALIGNOF_MAX_ALIGN_T + /* The normal alignment of `size_t', in bytes. */ #undef ALIGNOF_SIZE_T From webhook-mailer at python.org Thu May 4 04:17:24 2023 From: webhook-mailer at python.org (ezio-melotti) Date: Thu, 04 May 2023 08:17:24 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('module') (#103996) Message-ID: <mailman.141.1683188245.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d0122372f2acb4cc56b89ab8c577ff9039d17d89 commit: d0122372f2acb4cc56b89ab8c577ff9039d17d89 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ezio-melotti <ezio.melotti at gmail.com> date: 2023-05-04T10:17:12+02:00 summary: GH-97950: Use new-style index directive ('module') (#103996) * Use new-style index directive ('module') - C API * Use new-style index directive ('module') - Library * Use new-style index directive ('module') - Reference * Use new-style index directive ('module') - Tutorial * Uncomment module removal in pairindextypes * Use new-style index directive ('module') - C API * Use new-style index directive ('module') - Library * Use new-style index directive ('module') - Reference files: M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/library/_thread.rst M Doc/library/binascii.rst M Doc/library/cmath.rst M Doc/library/copy.rst M Doc/library/copyreg.rst M Doc/library/exceptions.rst M Doc/library/fnmatch.rst M Doc/library/functions.rst M Doc/library/http.client.rst M Doc/library/internet.rst M Doc/library/locale.rst M Doc/library/marshal.rst M Doc/library/os.path.rst M Doc/library/os.rst M Doc/library/pdb.rst M Doc/library/posix.rst M Doc/library/pwd.rst M Doc/library/pyexpat.rst M Doc/library/runpy.rst M Doc/library/shelve.rst M Doc/library/site.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/executionmodel.rst M Doc/reference/toplevel_components.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/inputoutput.rst M Doc/tutorial/modules.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 49d2f18d4573..4ed96f01dbbc 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -602,7 +602,7 @@ Signal Handling .. c:function:: int PyErr_CheckSignals() .. index:: - module: signal + pair: module; signal single: SIGINT single: KeyboardInterrupt (built-in exception) @@ -633,7 +633,7 @@ Signal Handling .. c:function:: void PyErr_SetInterrupt() .. index:: - module: signal + pair: module; signal single: SIGINT single: KeyboardInterrupt (built-in exception) @@ -648,7 +648,7 @@ Signal Handling .. c:function:: int PyErr_SetInterruptEx(int signum) .. index:: - module: signal + pair: module; signal single: KeyboardInterrupt (built-in exception) Simulate the effect of a signal arriving. The next time diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 38e324fb6409..26762969ef8e 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -336,9 +336,9 @@ Initializing and finalizing the interpreter single: PyEval_InitThreads() single: modules (in module sys) single: path (in module sys) - module: builtins - module: __main__ - module: sys + pair: module; builtins + pair: module; __main__ + pair: module; sys triple: module; search; path single: PySys_SetArgv() single: PySys_SetArgvEx() @@ -1051,7 +1051,7 @@ code, or when embedding the Python interpreter: .. deprecated:: 3.9 - .. index:: module: _thread + .. index:: pair: module; _thread .. c:function:: int PyEval_ThreadsInitialized() @@ -1494,9 +1494,9 @@ function. You can create and destroy them using the following functions: .. c:function:: PyThreadState* Py_NewInterpreter() .. index:: - module: builtins - module: __main__ - module: sys + pair: module; builtins + pair: module; __main__ + pair: module; sys single: stdout (in module sys) single: stderr (in module sys) single: stdin (in module sys) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index acd4e033dfbc..1a200b919f0e 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -705,9 +705,9 @@ interpreter can only be used after the interpreter has been initialized. .. index:: single: Py_Initialize() - module: builtins - module: __main__ - module: sys + pair: module; builtins + pair: module; __main__ + pair: module; sys triple: module; search; path single: path (in module sys) diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index 122692a42859..ba9314e46ab6 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -208,7 +208,7 @@ In addition to these methods, lock objects can also be used via the **Caveats:** - .. index:: module: signal + .. index:: pair: module; signal * Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt` exception will be received by an arbitrary thread. (When the :mod:`signal` diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index 5a0815faa38e..21960cb7972e 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -6,8 +6,8 @@ representations. .. index:: - module: uu - module: base64 + pair: module; uu + pair: module; base64 -------------- diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 5ed7a09b3e9d..b17d58e1cc0c 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -301,7 +301,7 @@ Constants .. versionadded:: 3.6 -.. index:: module: math +.. index:: pair: module; math Note that the selection of functions is similar, but not identical, to that in module :mod:`math`. The reason for having two modules is that some users aren't diff --git a/Doc/library/copy.rst b/Doc/library/copy.rst index a8bc2fa55ea8..8f32477ed508 100644 --- a/Doc/library/copy.rst +++ b/Doc/library/copy.rst @@ -68,7 +68,7 @@ Shallow copies of dictionaries can be made using :meth:`dict.copy`, and of lists by assigning a slice of the entire list, for example, ``copied_list = original_list[:]``. -.. index:: module: pickle +.. index:: pair: module; pickle Classes can use the same interfaces to control copying that they use to control pickling. See the description of module :mod:`pickle` for information on these diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index afc3e66f0bf7..2a28c043f807 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -7,8 +7,8 @@ **Source code:** :source:`Lib/copyreg.py` .. index:: - module: pickle - module: copy + pair: module; pickle + pair: module; copy -------------- diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 18c3f47dddc0..aee1cb5cc6a4 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -318,7 +318,7 @@ The following exceptions are the exceptions that are usually raised. .. exception:: OSError([arg]) OSError(errno, strerror[, filename[, winerror[, filename2]]]) - .. index:: module: errno + .. index:: pair: module; errno This exception is raised when a system function returns a system-related error, including I/O failures such as "file not found" or "disk full" diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst index 46bf0fc28480..aed8991d4477 100644 --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -8,7 +8,7 @@ .. index:: single: filenames; wildcard expansion -.. index:: module: re +.. index:: pair: module; re -------------- @@ -38,7 +38,7 @@ special characters used in shell-style wildcards are: For a literal match, wrap the meta-characters in brackets. For example, ``'[?]'`` matches the character ``'?'``. -.. index:: module: glob +.. index:: pair: module; glob Note that the filename separator (``'/'`` on Unix) is *not* special to this module. See module :mod:`glob` for pathname expansion (:mod:`glob` uses diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 47e388012959..ddb918de115f 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1340,7 +1340,7 @@ are always available. They are listed here in alphabetical order. single: I/O control; buffering single: binary mode single: text mode - module: sys + pair: module; sys See also the file handling modules, such as :mod:`fileinput`, :mod:`io` (where :func:`open` is declared), :mod:`os`, :mod:`os.path`, :mod:`tempfile`, @@ -1987,7 +1987,7 @@ are always available. They are listed here in alphabetical order. .. index:: statement: import - module: builtins + pair: module; builtins .. note:: diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index abdc6b447a8b..eb8c1e198e2b 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -10,7 +10,7 @@ pair: HTTP; protocol single: HTTP; http.client (standard module) -.. index:: module: urllib.request +.. index:: pair: module; urllib.request -------------- diff --git a/Doc/library/internet.rst b/Doc/library/internet.rst index ff58dcf4d89c..681769a4820d 100644 --- a/Doc/library/internet.rst +++ b/Doc/library/internet.rst @@ -9,7 +9,7 @@ Internet Protocols and Support single: Internet single: World Wide Web -.. index:: module: socket +.. index:: pair: module; socket The modules described in this chapter implement internet protocols and support for related technology. They are all implemented in Python. Most of these diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index f726f8397c96..f2abb3638a14 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -16,7 +16,7 @@ functionality. The POSIX locale mechanism allows programmers to deal with certain cultural issues in an application, without requiring the programmer to know all the specifics of each country where the software is executed. -.. index:: module: _locale +.. index:: pair: module; _locale The :mod:`locale` module is implemented on top of the :mod:`_locale` module, which in turn uses an ANSI C locale implementation if available. @@ -464,7 +464,7 @@ The :mod:`locale` module defines the following exception and functions: .. data:: LC_CTYPE - .. index:: module: string + .. index:: pair: module; string Locale category for the character type functions. Depending on the settings of this category, the functions of module :mod:`string` dealing with case change diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst index 24f9dc1689da..0556f19699dc 100644 --- a/Doc/library/marshal.rst +++ b/Doc/library/marshal.rst @@ -15,8 +15,8 @@ undocumented on purpose; it may change between Python versions (although it rarely does). [#]_ .. index:: - module: pickle - module: shelve + pair: module; pickle + pair: module; shelve This is not a general "persistence" module. For general persistence and transfer of Python objects through RPC calls, see the modules :mod:`pickle` and diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 96bcb48ad7d1..7881c52db870 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -159,7 +159,7 @@ the :mod:`glob` module.) On Unix and Windows, return the argument with an initial component of ``~`` or ``~user`` replaced by that *user*'s home directory. - .. index:: module: pwd + .. index:: pair: module; pwd On Unix, an initial ``~`` is replaced by the environment variable :envvar:`HOME` if it is set; otherwise the current user's home directory is looked up in the diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 76623c630543..641e289e77c5 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1284,7 +1284,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo .. function:: openpty() - .. index:: module: pty + .. index:: pair: module; pty Open a new pseudo-terminal pair. Return a pair of file descriptors ``(master, slave)`` for the pty and the tty, respectively. The new file @@ -2890,7 +2890,7 @@ features: possible and call :func:`lstat` on the result. This does not apply to dangling symlinks or junction points, which will raise the usual exceptions. - .. index:: module: stat + .. index:: pair: module; stat Example:: diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 8a386aa77368..74bffef5562a 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -20,8 +20,8 @@ supports post-mortem debugging and can be called under program control. .. index:: single: Pdb (class in pdb) - module: bdb - module: cmd + pair: module; bdb + pair: module; cmd The debugger is extensible -- it is actually defined as the class :class:`Pdb`. This is currently undocumented but easily understood by reading the source. The diff --git a/Doc/library/posix.rst b/Doc/library/posix.rst index ec04b0dcfc16..0413f9d02a8d 100644 --- a/Doc/library/posix.rst +++ b/Doc/library/posix.rst @@ -11,7 +11,7 @@ This module provides access to operating system functionality that is standardized by the C Standard and the POSIX standard (a thinly disguised Unix interface). -.. index:: module: os +.. index:: pair: module; os **Do not import this module directly.** Instead, import the module :mod:`os`, which provides a *portable* version of this interface. On Unix, the :mod:`os` diff --git a/Doc/library/pwd.rst b/Doc/library/pwd.rst index 98f3c45e29cb..7cafc66fd7e9 100644 --- a/Doc/library/pwd.rst +++ b/Doc/library/pwd.rst @@ -39,7 +39,7 @@ raised if the entry asked for cannot be found. .. note:: - .. index:: module: crypt + .. index:: pair: module; crypt In traditional Unix the field ``pw_passwd`` usually contains a password encrypted with a DES derived algorithm (see module :mod:`crypt`). However most diff --git a/Doc/library/pyexpat.rst b/Doc/library/pyexpat.rst index d6581e21b01c..935e872480ef 100644 --- a/Doc/library/pyexpat.rst +++ b/Doc/library/pyexpat.rst @@ -33,7 +33,7 @@ can be set to handler functions. When an XML document is then fed to the parser, the handler functions are called for the character data and markup in the XML document. -.. index:: module: pyexpat +.. index:: pair: module; pyexpat This module uses the :mod:`pyexpat` module to provide access to the Expat parser. Direct use of the :mod:`pyexpat` module is deprecated. diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index 501f4ddf5a3e..42ed8c253b80 100644 --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -30,7 +30,7 @@ The :mod:`runpy` module provides two functions: .. function:: run_module(mod_name, init_globals=None, run_name=None, alter_sys=False) .. index:: - module: __main__ + pair: module; __main__ Execute the code of the specified module and return the resulting module globals dictionary. The module's code is first located using the standard @@ -101,7 +101,7 @@ The :mod:`runpy` module provides two functions: .. function:: run_path(path_name, init_globals=None, run_name=None) .. index:: - module: __main__ + pair: module; __main__ Execute the code at the named filesystem location and return the resulting module globals dictionary. As with a script name supplied to the CPython diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index a50fc6f0bf77..dc87af398ed7 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -6,7 +6,7 @@ **Source code:** :source:`Lib/shelve.py` -.. index:: module: pickle +.. index:: pair: module; pickle -------------- @@ -95,8 +95,8 @@ Restrictions ------------ .. index:: - module: dbm.ndbm - module: dbm.gnu + pair: module; dbm.ndbm + pair: module; dbm.gnu * The choice of which database package will be used (such as :mod:`dbm.ndbm` or :mod:`dbm.gnu`) depends on which interface is available. Therefore it is not diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 4a88013f1d6e..a4efefd587a6 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -109,7 +109,7 @@ directory precedes the :file:`foo` directory because :file:`bar.pth` comes alphabetically before :file:`foo.pth`; and :file:`spam` is omitted because it is not mentioned in either path configuration file. -.. index:: module: sitecustomize +.. index:: pair: module; sitecustomize After these path manipulations, an attempt is made to import a module named :mod:`sitecustomize`, which can perform arbitrary site-specific customizations. @@ -121,7 +121,7 @@ with :file:`pythonw.exe` on Windows (which is used by default to start IDLE), attempted output from :mod:`sitecustomize` is ignored. Any other exception causes a silent and perhaps mysterious failure of the process. -.. index:: module: usercustomize +.. index:: pair: module; usercustomize After this, an attempt is made to import a module named :mod:`usercustomize`, which can perform arbitrary user-specific customizations, if diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index c8ca555700a3..150c1f93afd9 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1916,7 +1916,7 @@ to sockets. .. method:: socket.setsockopt(level, optname, None, optlen: int) :noindex: - .. index:: module: struct + .. index:: pair: module; struct Set the value of the given socket option (see the Unix manual page :manpage:`setsockopt(2)`). The needed symbolic constants are defined in the diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index f6662b4336c2..4c0a213dcbea 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -330,7 +330,7 @@ Notes: (3) .. index:: - module: math + pair: module; math single: floor() (in module math) single: ceil() (in module math) single: trunc() (in module math) @@ -1600,7 +1600,7 @@ String Methods -------------- .. index:: - module: re + pair: module; re Strings implement all of the :ref:`common <typesseq-common>` sequence operations, along with the additional methods described below. @@ -2511,7 +2511,7 @@ Binary Sequence Types --- :class:`bytes`, :class:`bytearray`, :class:`memoryview object: bytes object: bytearray object: memoryview - module: array + pair: module; array The core built-in types for manipulating binary data are :class:`bytes` and :class:`bytearray`. They are supported by :class:`memoryview` which uses @@ -5378,7 +5378,7 @@ Type Objects .. index:: builtin: type - module: types + pair: module; types Type objects represent the various object types. An object's type is accessed by the built-in function :func:`type`. There are no special operations on diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 0731589e4cad..4bdecbf24365 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -297,7 +297,7 @@ traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs. .. index:: - module: sys + pair: module; sys object: traceback Before an :keyword:`!except` clause's suite is executed, diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index c35bf4016a28..9d3ea3f78de1 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -377,7 +377,7 @@ Sequences (and hence unhashable), byte arrays otherwise provide the same interface and functionality as immutable :class:`bytes` objects. - .. index:: module: array + .. index:: pair: module; array The extension module :mod:`array` provides an additional example of a mutable sequence type, as does the :mod:`collections` module. @@ -451,8 +451,8 @@ Mappings section :ref:`dict`). .. index:: - module: dbm.ndbm - module: dbm.gnu + pair: module; dbm.ndbm + pair: module; dbm.gnu The extension modules :mod:`dbm.ndbm` and :mod:`dbm.gnu` provide additional examples of mapping types, as does the :mod:`collections` @@ -909,7 +909,7 @@ Class instances I/O objects (also known as file objects) .. index:: builtin: open - module: io + pair: module; io single: popen() (in module os) single: makefile() (socket method) single: sys.stdin diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index a264015cbf40..8917243999d3 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -151,7 +151,7 @@ to previously bound variables in the nearest enclosing function scope. :exc:`SyntaxError` is raised at compile time if the given name does not exist in any enclosing function scope. -.. index:: module: __main__ +.. index:: pair: module; __main__ The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called :mod:`__main__`. diff --git a/Doc/reference/toplevel_components.rst b/Doc/reference/toplevel_components.rst index 319c9de48424..ee472ace6e21 100644 --- a/Doc/reference/toplevel_components.rst +++ b/Doc/reference/toplevel_components.rst @@ -21,9 +21,9 @@ Complete Python programs .. index:: single: program .. index:: - module: sys - module: __main__ - module: builtins + pair: module; sys + pair: module; __main__ + pair: module; builtins While a language specification need not prescribe how the language interpreter is invoked, it is useful to have a notion of a complete Python program. A @@ -38,7 +38,7 @@ the next section. .. index:: single: interactive mode - module: __main__ + pair: module; __main__ The interpreter may also be invoked in interactive mode; in this case, it does not read and execute a complete program but reads and executes one statement diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 39c7c42e66f9..12d3e382c873 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -689,7 +689,7 @@ def patch_pairindextypes(app) -> None: # away from this, we need Sphinx to believe that these values don't # exist, by deleting them when using the gettext builder. - # pairindextypes.pop('module', None) + pairindextypes.pop('module', None) # pairindextypes.pop('keyword', None) # pairindextypes.pop('operator', None) # pairindextypes.pop('object', None) @@ -697,10 +697,6 @@ def patch_pairindextypes(app) -> None: # pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) - # there needs to be at least one statement in this block, will be - # removed when the first of the below is uncommented. - pass - def setup(app): app.add_role('issue', issue_role) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 3581b3727a53..aeacc1559a22 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -466,7 +466,7 @@ Reference for a complete guide to file objects. Saving structured data with :mod:`json` --------------------------------------- -.. index:: module: json +.. index:: pair: module; json Strings can easily be written to and read from a file. Numbers take a bit more effort, since the :meth:`read` method only returns strings, which will have to diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 4daafa49a34d..3bd034bcc970 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -264,7 +264,7 @@ Some tips for experts: Standard Modules ================ -.. index:: module: sys +.. index:: pair: module; sys Python comes with a library of standard modules, described in a separate document, the Python Library Reference ("Library Reference" hereafter). Some @@ -345,7 +345,7 @@ Without arguments, :func:`dir` lists the names you have defined currently:: Note that it lists all types of names: variables, modules, functions, etc. -.. index:: module: builtins +.. index:: pair: module; builtins :func:`dir` does not list the names of built-in functions and variables. If you want a list of those, they are defined in the standard module From webhook-mailer at python.org Thu May 4 04:39:35 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 08:39:35 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('module') (GH-103996) (#104154) Message-ID: <mailman.142.1683189576.13550.python-checkins@python.org> https://github.com/python/cpython/commit/00563694bb94f61ed4d8d36646a881ed6f028367 commit: 00563694bb94f61ed4d8d36646a881ed6f028367 branch: 3.11 author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T11:39:15+03:00 summary: [3.11] GH-97950: Use new-style index directive ('module') (GH-103996) (#104154) files: M Doc/c-api/exceptions.rst M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/library/_thread.rst M Doc/library/binascii.rst M Doc/library/cmath.rst M Doc/library/copy.rst M Doc/library/copyreg.rst M Doc/library/exceptions.rst M Doc/library/fnmatch.rst M Doc/library/functions.rst M Doc/library/http.client.rst M Doc/library/internet.rst M Doc/library/locale.rst M Doc/library/marshal.rst M Doc/library/os.path.rst M Doc/library/os.rst M Doc/library/pdb.rst M Doc/library/posix.rst M Doc/library/pwd.rst M Doc/library/pyexpat.rst M Doc/library/runpy.rst M Doc/library/shelve.rst M Doc/library/site.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/executionmodel.rst M Doc/reference/toplevel_components.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/inputoutput.rst M Doc/tutorial/modules.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 087e0a61d12d..092e548fb8fd 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -543,7 +543,7 @@ Signal Handling .. c:function:: int PyErr_CheckSignals() .. index:: - module: signal + pair: module; signal single: SIGINT single: KeyboardInterrupt (built-in exception) @@ -574,7 +574,7 @@ Signal Handling .. c:function:: void PyErr_SetInterrupt() .. index:: - module: signal + pair: module; signal single: SIGINT single: KeyboardInterrupt (built-in exception) @@ -589,7 +589,7 @@ Signal Handling .. c:function:: int PyErr_SetInterruptEx(int signum) .. index:: - module: signal + pair: module; signal single: KeyboardInterrupt (built-in exception) Simulate the effect of a signal arriving. The next time diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 615708ea2cce..dda87f4e31a4 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -233,9 +233,9 @@ Initializing and finalizing the interpreter single: PyEval_InitThreads() single: modules (in module sys) single: path (in module sys) - module: builtins - module: __main__ - module: sys + pair: module; builtins + pair: module; __main__ + pair: module; sys triple: module; search; path single: PySys_SetArgv() single: PySys_SetArgvEx() @@ -942,7 +942,7 @@ code, or when embedding the Python interpreter: .. deprecated:: 3.9 - .. index:: module: _thread + .. index:: pair: module; _thread .. c:function:: int PyEval_ThreadsInitialized() @@ -1385,9 +1385,9 @@ function. You can create and destroy them using the following functions: .. c:function:: PyThreadState* Py_NewInterpreter() .. index:: - module: builtins - module: __main__ - module: sys + pair: module; builtins + pair: module; __main__ + pair: module; sys single: stdout (in module sys) single: stderr (in module sys) single: stdin (in module sys) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index a8f9e9b99639..bd37ed58ffdf 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -705,9 +705,9 @@ interpreter can only be used after the interpreter has been initialized. .. index:: single: Py_Initialize() - module: builtins - module: __main__ - module: sys + pair: module; builtins + pair: module; __main__ + pair: module; sys triple: module; search; path single: path (in module sys) diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst index ecd7a68e627f..3d7e354d1e36 100644 --- a/Doc/library/_thread.rst +++ b/Doc/library/_thread.rst @@ -206,7 +206,7 @@ In addition to these methods, lock objects can also be used via the **Caveats:** - .. index:: module: signal + .. index:: pair: module; signal * Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt` exception will be received by an arbitrary thread. (When the :mod:`signal` diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index 5a0815faa38e..21960cb7972e 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -6,8 +6,8 @@ representations. .. index:: - module: uu - module: base64 + pair: module; uu + pair: module; base64 -------------- diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index 5ed7a09b3e9d..b17d58e1cc0c 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -301,7 +301,7 @@ Constants .. versionadded:: 3.6 -.. index:: module: math +.. index:: pair: module; math Note that the selection of functions is similar, but not identical, to that in module :mod:`math`. The reason for having two modules is that some users aren't diff --git a/Doc/library/copy.rst b/Doc/library/copy.rst index a8bc2fa55ea8..8f32477ed508 100644 --- a/Doc/library/copy.rst +++ b/Doc/library/copy.rst @@ -68,7 +68,7 @@ Shallow copies of dictionaries can be made using :meth:`dict.copy`, and of lists by assigning a slice of the entire list, for example, ``copied_list = original_list[:]``. -.. index:: module: pickle +.. index:: pair: module; pickle Classes can use the same interfaces to control copying that they use to control pickling. See the description of module :mod:`pickle` for information on these diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst index afc3e66f0bf7..2a28c043f807 100644 --- a/Doc/library/copyreg.rst +++ b/Doc/library/copyreg.rst @@ -7,8 +7,8 @@ **Source code:** :source:`Lib/copyreg.py` .. index:: - module: pickle - module: copy + pair: module; pickle + pair: module; copy -------------- diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 18c3f47dddc0..aee1cb5cc6a4 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -318,7 +318,7 @@ The following exceptions are the exceptions that are usually raised. .. exception:: OSError([arg]) OSError(errno, strerror[, filename[, winerror[, filename2]]]) - .. index:: module: errno + .. index:: pair: module; errno This exception is raised when a system function returns a system-related error, including I/O failures such as "file not found" or "disk full" diff --git a/Doc/library/fnmatch.rst b/Doc/library/fnmatch.rst index 46bf0fc28480..aed8991d4477 100644 --- a/Doc/library/fnmatch.rst +++ b/Doc/library/fnmatch.rst @@ -8,7 +8,7 @@ .. index:: single: filenames; wildcard expansion -.. index:: module: re +.. index:: pair: module; re -------------- @@ -38,7 +38,7 @@ special characters used in shell-style wildcards are: For a literal match, wrap the meta-characters in brackets. For example, ``'[?]'`` matches the character ``'?'``. -.. index:: module: glob +.. index:: pair: module; glob Note that the filename separator (``'/'`` on Unix) is *not* special to this module. See module :mod:`glob` for pathname expansion (:mod:`glob` uses diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 1c3deb2e78c7..53294aa901a5 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1339,7 +1339,7 @@ are always available. They are listed here in alphabetical order. single: I/O control; buffering single: binary mode single: text mode - module: sys + pair: module; sys See also the file handling modules, such as :mod:`fileinput`, :mod:`io` (where :func:`open` is declared), :mod:`os`, :mod:`os.path`, :mod:`tempfile`, @@ -1979,7 +1979,7 @@ are always available. They are listed here in alphabetical order. .. index:: statement: import - module: imp + pair: module; builtins .. note:: diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index bf0bf0f8c530..9aeb07fade82 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -10,7 +10,7 @@ pair: HTTP; protocol single: HTTP; http.client (standard module) -.. index:: module: urllib.request +.. index:: pair: module; urllib.request -------------- diff --git a/Doc/library/internet.rst b/Doc/library/internet.rst index ff58dcf4d89c..681769a4820d 100644 --- a/Doc/library/internet.rst +++ b/Doc/library/internet.rst @@ -9,7 +9,7 @@ Internet Protocols and Support single: Internet single: World Wide Web -.. index:: module: socket +.. index:: pair: module; socket The modules described in this chapter implement internet protocols and support for related technology. They are all implemented in Python. Most of these diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst index 0614930cb01e..2948105d2925 100644 --- a/Doc/library/locale.rst +++ b/Doc/library/locale.rst @@ -16,7 +16,7 @@ functionality. The POSIX locale mechanism allows programmers to deal with certain cultural issues in an application, without requiring the programmer to know all the specifics of each country where the software is executed. -.. index:: module: _locale +.. index:: pair: module; _locale The :mod:`locale` module is implemented on top of the :mod:`_locale` module, which in turn uses an ANSI C locale implementation if available. @@ -476,7 +476,7 @@ The :mod:`locale` module defines the following exception and functions: .. data:: LC_CTYPE - .. index:: module: string + .. index:: pair: module; string Locale category for the character type functions. Depending on the settings of this category, the functions of module :mod:`string` dealing with case change diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst index 24f9dc1689da..0556f19699dc 100644 --- a/Doc/library/marshal.rst +++ b/Doc/library/marshal.rst @@ -15,8 +15,8 @@ undocumented on purpose; it may change between Python versions (although it rarely does). [#]_ .. index:: - module: pickle - module: shelve + pair: module; pickle + pair: module; shelve This is not a general "persistence" module. For general persistence and transfer of Python objects through RPC calls, see the modules :mod:`pickle` and diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst index 22d07c473838..1a6b121de186 100644 --- a/Doc/library/os.path.rst +++ b/Doc/library/os.path.rst @@ -159,7 +159,7 @@ the :mod:`glob` module.) On Unix and Windows, return the argument with an initial component of ``~`` or ``~user`` replaced by that *user*'s home directory. - .. index:: module: pwd + .. index:: pair: module; pwd On Unix, an initial ``~`` is replaced by the environment variable :envvar:`HOME` if it is set; otherwise the current user's home directory is looked up in the diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 19e5bee34e84..b4812e25256b 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1185,7 +1185,7 @@ or `the MSDN <https://msdn.microsoft.com/en-us/library/z0kc8e3z.aspx>`_ on Windo .. function:: openpty() - .. index:: module: pty + .. index:: pair: module; pty Open a new pseudo-terminal pair. Return a pair of file descriptors ``(master, slave)`` for the pty and the tty, respectively. The new file @@ -2707,7 +2707,7 @@ features: possible and call :func:`lstat` on the result. This does not apply to dangling symlinks or junction points, which will raise the usual exceptions. - .. index:: module: stat + .. index:: pair: module; stat Example:: diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index a556fcc30877..8798155764b1 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -20,8 +20,8 @@ supports post-mortem debugging and can be called under program control. .. index:: single: Pdb (class in pdb) - module: bdb - module: cmd + pair: module; bdb + pair: module; cmd The debugger is extensible -- it is actually defined as the class :class:`Pdb`. This is currently undocumented but easily understood by reading the source. The diff --git a/Doc/library/posix.rst b/Doc/library/posix.rst index ec04b0dcfc16..0413f9d02a8d 100644 --- a/Doc/library/posix.rst +++ b/Doc/library/posix.rst @@ -11,7 +11,7 @@ This module provides access to operating system functionality that is standardized by the C Standard and the POSIX standard (a thinly disguised Unix interface). -.. index:: module: os +.. index:: pair: module; os **Do not import this module directly.** Instead, import the module :mod:`os`, which provides a *portable* version of this interface. On Unix, the :mod:`os` diff --git a/Doc/library/pwd.rst b/Doc/library/pwd.rst index 98f3c45e29cb..7cafc66fd7e9 100644 --- a/Doc/library/pwd.rst +++ b/Doc/library/pwd.rst @@ -39,7 +39,7 @@ raised if the entry asked for cannot be found. .. note:: - .. index:: module: crypt + .. index:: pair: module; crypt In traditional Unix the field ``pw_passwd`` usually contains a password encrypted with a DES derived algorithm (see module :mod:`crypt`). However most diff --git a/Doc/library/pyexpat.rst b/Doc/library/pyexpat.rst index d6581e21b01c..935e872480ef 100644 --- a/Doc/library/pyexpat.rst +++ b/Doc/library/pyexpat.rst @@ -33,7 +33,7 @@ can be set to handler functions. When an XML document is then fed to the parser, the handler functions are called for the character data and markup in the XML document. -.. index:: module: pyexpat +.. index:: pair: module; pyexpat This module uses the :mod:`pyexpat` module to provide access to the Expat parser. Direct use of the :mod:`pyexpat` module is deprecated. diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index 26a4f1435214..e161458040f8 100644 --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -30,7 +30,7 @@ The :mod:`runpy` module provides two functions: .. function:: run_module(mod_name, init_globals=None, run_name=None, alter_sys=False) .. index:: - module: __main__ + pair: module; __main__ Execute the code of the specified module and return the resulting module globals dictionary. The module's code is first located using the standard @@ -96,7 +96,7 @@ The :mod:`runpy` module provides two functions: .. function:: run_path(path_name, init_globals=None, run_name=None) .. index:: - module: __main__ + pair: module; __main__ Execute the code at the named filesystem location and return the resulting module globals dictionary. As with a script name supplied to the CPython diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst index a50fc6f0bf77..dc87af398ed7 100644 --- a/Doc/library/shelve.rst +++ b/Doc/library/shelve.rst @@ -6,7 +6,7 @@ **Source code:** :source:`Lib/shelve.py` -.. index:: module: pickle +.. index:: pair: module; pickle -------------- @@ -95,8 +95,8 @@ Restrictions ------------ .. index:: - module: dbm.ndbm - module: dbm.gnu + pair: module; dbm.ndbm + pair: module; dbm.gnu * The choice of which database package will be used (such as :mod:`dbm.ndbm` or :mod:`dbm.gnu`) depends on which interface is available. Therefore it is not diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 5941739ee694..34b38f4d56f3 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -109,7 +109,7 @@ directory precedes the :file:`foo` directory because :file:`bar.pth` comes alphabetically before :file:`foo.pth`; and :file:`spam` is omitted because it is not mentioned in either path configuration file. -.. index:: module: sitecustomize +.. index:: pair: module; sitecustomize After these path manipulations, an attempt is made to import a module named :mod:`sitecustomize`, which can perform arbitrary site-specific customizations. @@ -121,7 +121,7 @@ with :file:`pythonw.exe` on Windows (which is used by default to start IDLE), attempted output from :mod:`sitecustomize` is ignored. Any other exception causes a silent and perhaps mysterious failure of the process. -.. index:: module: usercustomize +.. index:: pair: module; usercustomize After this, an attempt is made to import a module named :mod:`usercustomize`, which can perform arbitrary user-specific customizations, if diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index d1b5a1ceb737..e222dc70e422 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -1829,7 +1829,7 @@ to sockets. .. method:: socket.setsockopt(level, optname, None, optlen: int) :noindex: - .. index:: module: struct + .. index:: pair: module; struct Set the value of the given socket option (see the Unix manual page :manpage:`setsockopt(2)`). The needed symbolic constants are defined in the diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index e7d43b2809ac..2199829660a7 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -330,7 +330,7 @@ Notes: (3) .. index:: - module: math + pair: module; math single: floor() (in module math) single: ceil() (in module math) single: trunc() (in module math) @@ -1561,7 +1561,7 @@ String Methods -------------- .. index:: - module: re + pair: module; re Strings implement all of the :ref:`common <typesseq-common>` sequence operations, along with the additional methods described below. @@ -2467,7 +2467,7 @@ Binary Sequence Types --- :class:`bytes`, :class:`bytearray`, :class:`memoryview object: bytes object: bytearray object: memoryview - module: array + pair: module; array The core built-in types for manipulating binary data are :class:`bytes` and :class:`bytearray`. They are supported by :class:`memoryview` which uses @@ -5325,7 +5325,7 @@ Type Objects .. index:: builtin: type - module: types + pair: module; types Type objects represent the various object types. An object's type is accessed by the built-in function :func:`type`. There are no special operations on diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 54228b8a4e60..ade59dbe4394 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -297,7 +297,7 @@ traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs. .. index:: - module: sys + pair: module; sys object: traceback Before an :keyword:`!except` clause's suite is executed, diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 277b9e5aa247..e8117d982c2a 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -377,7 +377,7 @@ Sequences (and hence unhashable), byte arrays otherwise provide the same interface and functionality as immutable :class:`bytes` objects. - .. index:: module: array + .. index:: pair: module; array The extension module :mod:`array` provides an additional example of a mutable sequence type, as does the :mod:`collections` module. @@ -451,8 +451,8 @@ Mappings section :ref:`dict`). .. index:: - module: dbm.ndbm - module: dbm.gnu + pair: module; dbm.ndbm + pair: module; dbm.gnu The extension modules :mod:`dbm.ndbm` and :mod:`dbm.gnu` provide additional examples of mapping types, as does the :mod:`collections` @@ -909,7 +909,7 @@ Class instances I/O objects (also known as file objects) .. index:: builtin: open - module: io + pair: module; io single: popen() (in module os) single: makefile() (socket method) single: sys.stdin diff --git a/Doc/reference/executionmodel.rst b/Doc/reference/executionmodel.rst index a264015cbf40..8917243999d3 100644 --- a/Doc/reference/executionmodel.rst +++ b/Doc/reference/executionmodel.rst @@ -151,7 +151,7 @@ to previously bound variables in the nearest enclosing function scope. :exc:`SyntaxError` is raised at compile time if the given name does not exist in any enclosing function scope. -.. index:: module: __main__ +.. index:: pair: module; __main__ The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called :mod:`__main__`. diff --git a/Doc/reference/toplevel_components.rst b/Doc/reference/toplevel_components.rst index 319c9de48424..ee472ace6e21 100644 --- a/Doc/reference/toplevel_components.rst +++ b/Doc/reference/toplevel_components.rst @@ -21,9 +21,9 @@ Complete Python programs .. index:: single: program .. index:: - module: sys - module: __main__ - module: builtins + pair: module; sys + pair: module; __main__ + pair: module; builtins While a language specification need not prescribe how the language interpreter is invoked, it is useful to have a notion of a complete Python program. A @@ -38,7 +38,7 @@ the next section. .. index:: single: interactive mode - module: __main__ + pair: module; __main__ The interpreter may also be invoked in interactive mode; in this case, it does not read and execute a complete program but reads and executes one statement diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 3ff2a91b1fef..1888428437a6 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -694,7 +694,7 @@ def patch_pairindextypes(app) -> None: # away from this, we need Sphinx to believe that these values don't # exist, by deleting them when using the gettext builder. - # pairindextypes.pop('module', None) + pairindextypes.pop('module', None) # pairindextypes.pop('keyword', None) # pairindextypes.pop('operator', None) # pairindextypes.pop('object', None) @@ -702,10 +702,6 @@ def patch_pairindextypes(app) -> None: # pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) - # there needs to be at least one statement in this block, will be - # removed when the first of the below is uncommented. - pass - def setup(app): app.add_role('issue', issue_role) diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 3581b3727a53..aeacc1559a22 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -466,7 +466,7 @@ Reference for a complete guide to file objects. Saving structured data with :mod:`json` --------------------------------------- -.. index:: module: json +.. index:: pair: module; json Strings can easily be written to and read from a file. Numbers take a bit more effort, since the :meth:`read` method only returns strings, which will have to diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 4daafa49a34d..3bd034bcc970 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -264,7 +264,7 @@ Some tips for experts: Standard Modules ================ -.. index:: module: sys +.. index:: pair: module; sys Python comes with a library of standard modules, described in a separate document, the Python Library Reference ("Library Reference" hereafter). Some @@ -345,7 +345,7 @@ Without arguments, :func:`dir` lists the names you have defined currently:: Note that it lists all types of names: variables, modules, functions, etc. -.. index:: module: builtins +.. index:: pair: module; builtins :func:`dir` does not list the names of built-in functions and variables. If you want a list of those, they are defined in the standard module From webhook-mailer at python.org Thu May 4 04:44:19 2023 From: webhook-mailer at python.org (ezio-melotti) Date: Thu, 04 May 2023 08:44:19 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('keyword') (#104153) Message-ID: <mailman.143.1683189860.13550.python-checkins@python.org> https://github.com/python/cpython/commit/33ca322c50baa5152afe388fb3b8b7d63dc5a9b9 commit: 33ca322c50baa5152afe388fb3b8b7d63dc5a9b9 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: ezio-melotti <ezio.melotti at gmail.com> date: 2023-05-04T10:44:12+02:00 summary: GH-97950: Use new-style index directive ('keyword') (#104153) * Uncomment keyword removal in pairindextypes * Use new-style index directive ('keyword') - Reference files: M Doc/reference/compound_stmts.rst M Doc/reference/expressions.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 4bdecbf24365..1f03180f1565 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -85,8 +85,8 @@ The :keyword:`!if` statement .. index:: ! statement: if - keyword: elif - keyword: else + pair: keyword; elif + pair: keyword; else single: : (colon); compound statement The :keyword:`if` statement is used for conditional execution: @@ -110,7 +110,7 @@ The :keyword:`!while` statement .. index:: ! statement: while - keyword: else + pair: keyword; else pair: loop; statement single: : (colon); compound statement @@ -143,8 +143,8 @@ The :keyword:`!for` statement .. index:: ! statement: for - keyword: in - keyword: else + pair: keyword; in + pair: keyword; else pair: target; list pair: loop; statement object: sequence @@ -206,10 +206,10 @@ The :keyword:`!try` statement .. index:: ! statement: try - keyword: except - keyword: finally - keyword: else - keyword: as + pair: keyword; except + pair: keyword; finally + pair: keyword; else + pair: keyword; as single: : (colon); compound statement The :keyword:`!try` statement specifies exception handlers and/or cleanup code @@ -326,7 +326,7 @@ stored in the :mod:`sys` module is reset to its previous value:: .. index:: - keyword: except_star + pair: keyword; except_star .. _except_star: @@ -387,7 +387,7 @@ cannot appear in an :keyword:`!except*` clause. .. index:: - keyword: else + pair: keyword; else statement: return statement: break statement: continue @@ -404,7 +404,7 @@ the :keyword:`!else` clause are not handled by the preceding :keyword:`except` clauses. -.. index:: keyword: finally +.. index:: pair: keyword; finally .. _finally: @@ -469,7 +469,7 @@ The :keyword:`!with` statement .. index:: ! statement: with - keyword: as + pair: keyword; as single: as; with statement single: , (comma); with statement single: : (colon); compound statement @@ -586,10 +586,10 @@ The :keyword:`!match` statement .. index:: ! statement: match - ! keyword: case + ! pair: keyword; case ! single: pattern matching - keyword: if - keyword: as + pair: keyword; if + pair: keyword; as pair: match; case single: as; match statement single: : (colon); compound statement @@ -1474,8 +1474,8 @@ Coroutine function definition : ["->" `expression`] ":" `suite` .. index:: - keyword: async - keyword: await + pair: keyword; async + pair: keyword; await Execution of Python coroutines can be suspended and resumed at many points (see :term:`coroutine`). :keyword:`await` expressions, :keyword:`async for` and diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 1e4a13fbd6a3..fe2b090b23c6 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -415,8 +415,8 @@ Yield expressions ----------------- .. index:: - keyword: yield - keyword: from + pair: keyword; yield + pair: keyword; from pair: yield; expression pair: generator; function @@ -1149,7 +1149,7 @@ a class instance: if that method was called. -.. index:: keyword: await +.. index:: pair: keyword; await .. _await: Await expression diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index c98ac81e415b..5c7b5d7efaa2 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -495,7 +495,7 @@ If an expression list is present, it is evaluated, else ``None`` is substituted. :keyword:`return` leaves the current function call with the expression list (or ``None``) as return value. -.. index:: keyword: finally +.. index:: pair: keyword; finally When :keyword:`return` passes control out of a :keyword:`try` statement with a :keyword:`finally` clause, that :keyword:`!finally` clause is executed before @@ -679,7 +679,7 @@ The :keyword:`!break` statement :keyword:`while` loop, but not nested in a function or class definition within that loop. -.. index:: keyword: else +.. index:: pair: keyword; else pair: loop control; target It terminates the nearest enclosing loop, skipping the optional :keyword:`!else` @@ -688,7 +688,7 @@ clause if the loop has one. If a :keyword:`for` loop is terminated by :keyword:`break`, the loop control target keeps its current value. -.. index:: keyword: finally +.. index:: pair: keyword; finally When :keyword:`break` passes control out of a :keyword:`try` statement with a :keyword:`finally` clause, that :keyword:`!finally` clause is executed before @@ -705,7 +705,7 @@ The :keyword:`!continue` statement statement: for statement: while pair: loop; statement - keyword: finally + pair: keyword; finally .. productionlist:: python-grammar continue_stmt: "continue" @@ -729,8 +729,8 @@ The :keyword:`!import` statement ! statement: import single: module; importing pair: name; binding - keyword: from - keyword: as + pair: keyword; from + pair: keyword; as exception: ImportError single: , (comma); import statement diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 12d3e382c873..c347a327e091 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -690,7 +690,7 @@ def patch_pairindextypes(app) -> None: # exist, by deleting them when using the gettext builder. pairindextypes.pop('module', None) - # pairindextypes.pop('keyword', None) + pairindextypes.pop('keyword', None) # pairindextypes.pop('operator', None) # pairindextypes.pop('object', None) # pairindextypes.pop('exception', None) From webhook-mailer at python.org Thu May 4 04:53:27 2023 From: webhook-mailer at python.org (ezio-melotti) Date: Thu, 04 May 2023 08:53:27 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('keyword') (GH-104153) (#104155) Message-ID: <mailman.144.1683190407.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a9fcf01ed9591e9e68da9a25edc43fca676c276d commit: a9fcf01ed9591e9e68da9a25edc43fca676c276d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ezio-melotti <ezio.melotti at gmail.com> date: 2023-05-04T10:53:19+02:00 summary: [3.11] GH-97950: Use new-style index directive ('keyword') (GH-104153) (#104155) GH-97950: Use new-style index directive ('keyword') (GH-104153) * Uncomment keyword removal in pairindextypes * Use new-style index directive ('keyword') - Reference (cherry picked from commit 33ca322c50baa5152afe388fb3b8b7d63dc5a9b9) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/reference/compound_stmts.rst M Doc/reference/expressions.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index ade59dbe4394..3ed7239cd374 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -85,8 +85,8 @@ The :keyword:`!if` statement .. index:: ! statement: if - keyword: elif - keyword: else + pair: keyword; elif + pair: keyword; else single: : (colon); compound statement The :keyword:`if` statement is used for conditional execution: @@ -110,7 +110,7 @@ The :keyword:`!while` statement .. index:: ! statement: while - keyword: else + pair: keyword; else pair: loop; statement single: : (colon); compound statement @@ -143,8 +143,8 @@ The :keyword:`!for` statement .. index:: ! statement: for - keyword: in - keyword: else + pair: keyword; in + pair: keyword; else pair: target; list pair: loop; statement object: sequence @@ -206,10 +206,10 @@ The :keyword:`!try` statement .. index:: ! statement: try - keyword: except - keyword: finally - keyword: else - keyword: as + pair: keyword; except + pair: keyword; finally + pair: keyword; else + pair: keyword; as single: : (colon); compound statement The :keyword:`!try` statement specifies exception handlers and/or cleanup code @@ -326,7 +326,7 @@ stored in the :mod:`sys` module is reset to its previous value:: .. index:: - keyword: except_star + pair: keyword; except_star .. _except_star: @@ -389,7 +389,7 @@ cannot appear in an :keyword:`!except*` clause. .. index:: - keyword: else + pair: keyword; else statement: return statement: break statement: continue @@ -406,7 +406,7 @@ the :keyword:`!else` clause are not handled by the preceding :keyword:`except` clauses. -.. index:: keyword: finally +.. index:: pair: keyword; finally .. _finally: @@ -471,7 +471,7 @@ The :keyword:`!with` statement .. index:: ! statement: with - keyword: as + pair: keyword; as single: as; with statement single: , (comma); with statement single: : (colon); compound statement @@ -588,10 +588,10 @@ The :keyword:`!match` statement .. index:: ! statement: match - ! keyword: case + ! pair: keyword; case ! single: pattern matching - keyword: if - keyword: as + pair: keyword; if + pair: keyword; as pair: match; case single: as; match statement single: : (colon); compound statement @@ -1476,8 +1476,8 @@ Coroutine function definition : ["->" `expression`] ":" `suite` .. index:: - keyword: async - keyword: await + pair: keyword; async + pair: keyword; await Execution of Python coroutines can be suspended and resumed at many points (see :term:`coroutine`). :keyword:`await` expressions, :keyword:`async for` and diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index ea9db1824c70..0dcd7d89cc54 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -415,8 +415,8 @@ Yield expressions ----------------- .. index:: - keyword: yield - keyword: from + pair: keyword; yield + pair: keyword; from pair: yield; expression pair: generator; function @@ -1138,7 +1138,7 @@ a class instance: if that method was called. -.. index:: keyword: await +.. index:: pair: keyword; await .. _await: Await expression diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index c98ac81e415b..5c7b5d7efaa2 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -495,7 +495,7 @@ If an expression list is present, it is evaluated, else ``None`` is substituted. :keyword:`return` leaves the current function call with the expression list (or ``None``) as return value. -.. index:: keyword: finally +.. index:: pair: keyword; finally When :keyword:`return` passes control out of a :keyword:`try` statement with a :keyword:`finally` clause, that :keyword:`!finally` clause is executed before @@ -679,7 +679,7 @@ The :keyword:`!break` statement :keyword:`while` loop, but not nested in a function or class definition within that loop. -.. index:: keyword: else +.. index:: pair: keyword; else pair: loop control; target It terminates the nearest enclosing loop, skipping the optional :keyword:`!else` @@ -688,7 +688,7 @@ clause if the loop has one. If a :keyword:`for` loop is terminated by :keyword:`break`, the loop control target keeps its current value. -.. index:: keyword: finally +.. index:: pair: keyword; finally When :keyword:`break` passes control out of a :keyword:`try` statement with a :keyword:`finally` clause, that :keyword:`!finally` clause is executed before @@ -705,7 +705,7 @@ The :keyword:`!continue` statement statement: for statement: while pair: loop; statement - keyword: finally + pair: keyword; finally .. productionlist:: python-grammar continue_stmt: "continue" @@ -729,8 +729,8 @@ The :keyword:`!import` statement ! statement: import single: module; importing pair: name; binding - keyword: from - keyword: as + pair: keyword; from + pair: keyword; as exception: ImportError single: , (comma); import statement diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 1888428437a6..52852dd4ce1b 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -695,7 +695,7 @@ def patch_pairindextypes(app) -> None: # exist, by deleting them when using the gettext builder. pairindextypes.pop('module', None) - # pairindextypes.pop('keyword', None) + pairindextypes.pop('keyword', None) # pairindextypes.pop('operator', None) # pairindextypes.pop('object', None) # pairindextypes.pop('exception', None) From webhook-mailer at python.org Thu May 4 05:03:19 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 09:03:19 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('operator') (#104156) Message-ID: <mailman.145.1683191000.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b0ce2db1184124575d5934d205344a9cf5debb79 commit: b0ce2db1184124575d5934d205344a9cf5debb79 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T12:03:11+03:00 summary: GH-97950: Use new-style index directive ('operator') (#104156) files: M Doc/library/stdtypes.rst M Doc/reference/expressions.rst M Doc/tools/extensions/pyspecific.py diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 4c0a213dcbea..46b0389adaa8 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -61,8 +61,8 @@ objects considered false: ``range(0)`` .. index:: - operator: or - operator: and + pair: operator; or + pair: operator; and single: False single: True @@ -95,9 +95,9 @@ These are the Boolean operations, ordered by ascending priority: +-------------+---------------------------------+-------+ .. index:: - operator: and - operator: or - operator: not + pair: operator; and + pair: operator; or + pair: operator; not Notes: @@ -122,14 +122,14 @@ Comparisons .. index:: pair: chaining; comparisons pair: operator; comparison - operator: == - operator: < (less) - operator: <= - operator: > (greater) - operator: >= - operator: != - operator: is - operator: is not + pair: operator; == + pair: operator; < (less) + pair: operator; <= + pair: operator; > (greater) + pair: operator; >= + pair: operator; != + pair: operator; is + pair: operator; is not There are eight comparison operations in Python. They all have the same priority (which is higher than that of the Boolean operations). Comparisons can @@ -192,8 +192,8 @@ customized; also they can be applied to any two objects and never raise an exception. .. index:: - operator: in - operator: not in + pair: operator; in + pair: operator; not in Two more operations with the same syntactic priority, :keyword:`in` and :keyword:`not in`, are supported by types that are :term:`iterable` or @@ -253,11 +253,11 @@ and imaginary parts. single: operator; - (minus) single: - (minus); unary operator single: - (minus); binary operator - operator: * (asterisk) - operator: / (slash) - operator: // - operator: % (percent) - operator: ** + pair: operator; * (asterisk) + pair: operator; / (slash) + pair: operator; // + pair: operator; % (percent) + pair: operator; ** Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the "narrower" type is @@ -392,12 +392,12 @@ Bitwise Operations on Integer Types pair: bitwise; operations pair: shifting; operations pair: masking; operations - operator: | (vertical bar) - operator: ^ (caret) - operator: & (ampersand) - operator: << - operator: >> - operator: ~ (tilde) + pair: operator; | (vertical bar) + pair: operator; ^ (caret) + pair: operator; & (ampersand) + pair: operator; << + pair: operator; >> + pair: operator; ~ (tilde) Bitwise operations only make sense for integers. The result of bitwise operations is calculated as though carried out in two's complement with an @@ -952,8 +952,8 @@ operations have the same priority as the corresponding numeric operations. [3]_ pair: repetition; operation pair: subscript; operation pair: slice; operation - operator: in - operator: not in + pair: operator; in + pair: operator; not in single: count() (sequence method) single: index() (sequence method) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index fe2b090b23c6..b1bb162f62e1 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1171,7 +1171,7 @@ The power operator .. index:: pair: power; operation - operator: ** + pair: operator; ** The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right. The syntax is: @@ -1232,7 +1232,7 @@ operation can be overridden with the :meth:`__pos__` special method. .. index:: single: inversion - operator: ~ (tilde) + pair: operator; ~ (tilde) The unary ``~`` (invert) operator yields the bitwise inversion of its integer argument. The bitwise inversion of ``x`` is defined as ``-(x+1)``. It only @@ -1267,7 +1267,7 @@ operators and one for additive operators: .. index:: single: multiplication - operator: * (asterisk) + pair: operator; * (asterisk) The ``*`` (multiplication) operator yields the product of its arguments. The arguments must either both be numbers, or one argument must be an integer and @@ -1280,7 +1280,7 @@ This operation can be customized using the special :meth:`__mul__` and .. index:: single: matrix multiplication - operator: @ (at) + pair: operator; @ (at) The ``@`` (at) operator is intended to be used for matrix multiplication. No builtin Python types implement this operator. @@ -1290,8 +1290,8 @@ builtin Python types implement this operator. .. index:: exception: ZeroDivisionError single: division - operator: / (slash) - operator: // + pair: operator; / (slash) + pair: operator; // The ``/`` (division) and ``//`` (floor division) operators yield the quotient of their arguments. The numeric arguments are first converted to a common type. @@ -1305,7 +1305,7 @@ This operation can be customized using the special :meth:`__truediv__` and .. index:: single: modulo - operator: % (percent) + pair: operator; % (percent) The ``%`` (modulo) operator yields the remainder from the division of the first argument by the second. The numeric arguments are first converted to a common @@ -1363,8 +1363,8 @@ Shifting operations .. index:: pair: shifting; operation - operator: << - operator: >> + pair: operator; << + pair: operator; >> The shifting operations have lower priority than the arithmetic operations: @@ -1399,7 +1399,7 @@ Each of the three bitwise operations has a different priority level: .. index:: pair: bitwise; and - operator: & (ampersand) + pair: operator; & (ampersand) The ``&`` operator yields the bitwise AND of its arguments, which must be integers or one of them must be a custom object overriding :meth:`__and__` or @@ -1408,7 +1408,7 @@ integers or one of them must be a custom object overriding :meth:`__and__` or .. index:: pair: bitwise; xor pair: exclusive; or - operator: ^ (caret) + pair: operator; ^ (caret) The ``^`` operator yields the bitwise XOR (exclusive OR) of its arguments, which must be integers or one of them must be a custom object overriding :meth:`__xor__` or @@ -1417,7 +1417,7 @@ must be integers or one of them must be a custom object overriding :meth:`__xor_ .. index:: pair: bitwise; or pair: inclusive; or - operator: | (vertical bar) + pair: operator; | (vertical bar) The ``|`` operator yields the bitwise (inclusive) OR of its arguments, which must be integers or one of them must be a custom object overriding :meth:`__or__` or @@ -1432,12 +1432,12 @@ Comparisons .. index:: single: comparison pair: C; language - operator: < (less) - operator: > (greater) - operator: <= - operator: >= - operator: == - operator: != + pair: operator; < (less) + pair: operator; > (greater) + pair: operator; <= + pair: operator; >= + pair: operator; == + pair: operator; != Unlike C, all comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation. Also unlike @@ -1669,8 +1669,8 @@ raises the :exc:`IndexError` exception. (If any other exception is raised, it i if :keyword:`in` raised that exception). .. index:: - operator: in - operator: not in + pair: operator; in + pair: operator; not in pair: membership; test object: sequence @@ -1678,8 +1678,8 @@ The operator :keyword:`not in` is defined to have the inverse truth value of :keyword:`in`. .. index:: - operator: is - operator: is not + pair: operator; is + pair: operator; is not pair: identity; test @@ -1719,17 +1719,17 @@ control flow statements, the following values are interpreted as false: other values are interpreted as true. User-defined objects can customize their truth value by providing a :meth:`__bool__` method. -.. index:: operator: not +.. index:: pair: operator; not The operator :keyword:`not` yields ``True`` if its argument is false, ``False`` otherwise. -.. index:: operator: and +.. index:: pair: operator; and The expression ``x and y`` first evaluates *x*; if *x* is false, its value is returned; otherwise, *y* is evaluated and the resulting value is returned. -.. index:: operator: or +.. index:: pair: operator; or The expression ``x or y`` first evaluates *x*; if *x* is true, its value is returned; otherwise, *y* is evaluated and the resulting value is returned. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index c347a327e091..8ca3ef04523a 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -691,7 +691,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('module', None) pairindextypes.pop('keyword', None) - # pairindextypes.pop('operator', None) + pairindextypes.pop('operator', None) # pairindextypes.pop('object', None) # pairindextypes.pop('exception', None) # pairindextypes.pop('statement', None) From webhook-mailer at python.org Thu May 4 05:27:19 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 09:27:19 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('operator') (GH-104156) (#104157) Message-ID: <mailman.146.1683192441.13550.python-checkins@python.org> https://github.com/python/cpython/commit/693ef48df1891a6a30fca6c6db500c7cd08671df commit: 693ef48df1891a6a30fca6c6db500c7cd08671df branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T12:27:04+03:00 summary: [3.11] GH-97950: Use new-style index directive ('operator') (GH-104156) (#104157) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/library/stdtypes.rst M Doc/reference/expressions.rst M Doc/tools/extensions/pyspecific.py diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 2199829660a7..b636adab60dd 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -61,8 +61,8 @@ objects considered false: ``range(0)`` .. index:: - operator: or - operator: and + pair: operator; or + pair: operator; and single: False single: True @@ -95,9 +95,9 @@ These are the Boolean operations, ordered by ascending priority: +-------------+---------------------------------+-------+ .. index:: - operator: and - operator: or - operator: not + pair: operator; and + pair: operator; or + pair: operator; not Notes: @@ -122,14 +122,14 @@ Comparisons .. index:: pair: chaining; comparisons pair: operator; comparison - operator: == - operator: < (less) - operator: <= - operator: > (greater) - operator: >= - operator: != - operator: is - operator: is not + pair: operator; == + pair: operator; < (less) + pair: operator; <= + pair: operator; > (greater) + pair: operator; >= + pair: operator; != + pair: operator; is + pair: operator; is not There are eight comparison operations in Python. They all have the same priority (which is higher than that of the Boolean operations). Comparisons can @@ -192,8 +192,8 @@ customized; also they can be applied to any two objects and never raise an exception. .. index:: - operator: in - operator: not in + pair: operator; in + pair: operator; not in Two more operations with the same syntactic priority, :keyword:`in` and :keyword:`not in`, are supported by types that are :term:`iterable` or @@ -253,11 +253,11 @@ and imaginary parts. single: operator; - (minus) single: - (minus); unary operator single: - (minus); binary operator - operator: * (asterisk) - operator: / (slash) - operator: // - operator: % (percent) - operator: ** + pair: operator; * (asterisk) + pair: operator; / (slash) + pair: operator; // + pair: operator; % (percent) + pair: operator; ** Python fully supports mixed arithmetic: when a binary arithmetic operator has operands of different numeric types, the operand with the "narrower" type is @@ -392,12 +392,12 @@ Bitwise Operations on Integer Types pair: bitwise; operations pair: shifting; operations pair: masking; operations - operator: | (vertical bar) - operator: ^ (caret) - operator: & (ampersand) - operator: << - operator: >> - operator: ~ (tilde) + pair: operator; | (vertical bar) + pair: operator; ^ (caret) + pair: operator; & (ampersand) + pair: operator; << + pair: operator; >> + pair: operator; ~ (tilde) Bitwise operations only make sense for integers. The result of bitwise operations is calculated as though carried out in two's complement with an @@ -913,8 +913,8 @@ operations have the same priority as the corresponding numeric operations. [3]_ pair: repetition; operation pair: subscript; operation pair: slice; operation - operator: in - operator: not in + pair: operator; in + pair: operator; not in single: count() (sequence method) single: index() (sequence method) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 0dcd7d89cc54..46e8c7c0e5c6 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -1160,7 +1160,7 @@ The power operator .. index:: pair: power; operation - operator: ** + pair: operator; ** The power operator binds more tightly than unary operators on its left; it binds less tightly than unary operators on its right. The syntax is: @@ -1221,7 +1221,7 @@ operation can be overridden with the :meth:`__pos__` special method. .. index:: single: inversion - operator: ~ (tilde) + pair: operator; ~ (tilde) The unary ``~`` (invert) operator yields the bitwise inversion of its integer argument. The bitwise inversion of ``x`` is defined as ``-(x+1)``. It only @@ -1256,7 +1256,7 @@ operators and one for additive operators: .. index:: single: multiplication - operator: * (asterisk) + pair: operator; * (asterisk) The ``*`` (multiplication) operator yields the product of its arguments. The arguments must either both be numbers, or one argument must be an integer and @@ -1269,7 +1269,7 @@ This operation can be customized using the special :meth:`__mul__` and .. index:: single: matrix multiplication - operator: @ (at) + pair: operator; @ (at) The ``@`` (at) operator is intended to be used for matrix multiplication. No builtin Python types implement this operator. @@ -1279,8 +1279,8 @@ builtin Python types implement this operator. .. index:: exception: ZeroDivisionError single: division - operator: / (slash) - operator: // + pair: operator; / (slash) + pair: operator; // The ``/`` (division) and ``//`` (floor division) operators yield the quotient of their arguments. The numeric arguments are first converted to a common type. @@ -1294,7 +1294,7 @@ This operation can be customized using the special :meth:`__truediv__` and .. index:: single: modulo - operator: % (percent) + pair: operator; % (percent) The ``%`` (modulo) operator yields the remainder from the division of the first argument by the second. The numeric arguments are first converted to a common @@ -1352,8 +1352,8 @@ Shifting operations .. index:: pair: shifting; operation - operator: << - operator: >> + pair: operator; << + pair: operator; >> The shifting operations have lower priority than the arithmetic operations: @@ -1388,7 +1388,7 @@ Each of the three bitwise operations has a different priority level: .. index:: pair: bitwise; and - operator: & (ampersand) + pair: operator; & (ampersand) The ``&`` operator yields the bitwise AND of its arguments, which must be integers or one of them must be a custom object overriding :meth:`__and__` or @@ -1397,7 +1397,7 @@ integers or one of them must be a custom object overriding :meth:`__and__` or .. index:: pair: bitwise; xor pair: exclusive; or - operator: ^ (caret) + pair: operator; ^ (caret) The ``^`` operator yields the bitwise XOR (exclusive OR) of its arguments, which must be integers or one of them must be a custom object overriding :meth:`__xor__` or @@ -1406,7 +1406,7 @@ must be integers or one of them must be a custom object overriding :meth:`__xor_ .. index:: pair: bitwise; or pair: inclusive; or - operator: | (vertical bar) + pair: operator; | (vertical bar) The ``|`` operator yields the bitwise (inclusive) OR of its arguments, which must be integers or one of them must be a custom object overriding :meth:`__or__` or @@ -1421,12 +1421,12 @@ Comparisons .. index:: single: comparison pair: C; language - operator: < (less) - operator: > (greater) - operator: <= - operator: >= - operator: == - operator: != + pair: operator; < (less) + pair: operator; > (greater) + pair: operator; <= + pair: operator; >= + pair: operator; == + pair: operator; != Unlike C, all comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation. Also unlike @@ -1658,8 +1658,8 @@ raises the :exc:`IndexError` exception. (If any other exception is raised, it i if :keyword:`in` raised that exception). .. index:: - operator: in - operator: not in + pair: operator; in + pair: operator; not in pair: membership; test object: sequence @@ -1667,8 +1667,8 @@ The operator :keyword:`not in` is defined to have the inverse truth value of :keyword:`in`. .. index:: - operator: is - operator: is not + pair: operator; is + pair: operator; is not pair: identity; test @@ -1708,17 +1708,17 @@ control flow statements, the following values are interpreted as false: other values are interpreted as true. User-defined objects can customize their truth value by providing a :meth:`__bool__` method. -.. index:: operator: not +.. index:: pair: operator; not The operator :keyword:`not` yields ``True`` if its argument is false, ``False`` otherwise. -.. index:: operator: and +.. index:: pair: operator; and The expression ``x and y`` first evaluates *x*; if *x* is false, its value is returned; otherwise, *y* is evaluated and the resulting value is returned. -.. index:: operator: or +.. index:: pair: operator; or The expression ``x or y`` first evaluates *x*; if *x* is true, its value is returned; otherwise, *y* is evaluated and the resulting value is returned. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 52852dd4ce1b..d6034e1bb718 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -696,7 +696,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('module', None) pairindextypes.pop('keyword', None) - # pairindextypes.pop('operator', None) + pairindextypes.pop('operator', None) # pairindextypes.pop('object', None) # pairindextypes.pop('exception', None) # pairindextypes.pop('statement', None) From webhook-mailer at python.org Thu May 4 06:05:27 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 10:05:27 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('object') (#104158) Message-ID: <mailman.147.1683194728.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6ab463684b9d79880d98cd1f1406aa86af65985e commit: 6ab463684b9d79880d98cd1f1406aa86af65985e branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T13:04:41+03:00 summary: GH-97950: Use new-style index directive ('object') (#104158) * Uncomment object removal in pairindextypes * Use new-style index directive ('object') - C API * Use new-style index directive ('object') - Library * Use new-style index directive ('object') - Reference * Use new-style index directive ('object') - Tutorial files: M Doc/c-api/bytearray.rst M Doc/c-api/bytes.rst M Doc/c-api/capsule.rst M Doc/c-api/complex.rst M Doc/c-api/concrete.rst M Doc/c-api/dict.rst M Doc/c-api/file.rst M Doc/c-api/float.rst M Doc/c-api/function.rst M Doc/c-api/intro.rst M Doc/c-api/list.rst M Doc/c-api/long.rst M Doc/c-api/memoryview.rst M Doc/c-api/method.rst M Doc/c-api/module.rst M Doc/c-api/none.rst M Doc/c-api/set.rst M Doc/c-api/tuple.rst M Doc/c-api/type.rst M Doc/library/functions.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/library/sys.rst M Doc/library/traceback.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/expressions.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/classes.rst M Doc/tutorial/inputoutput.rst diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst index 4bf3cfe100cd..456f7d89bca0 100644 --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -5,7 +5,7 @@ Byte Array Objects ------------------ -.. index:: object: bytearray +.. index:: pair: object; bytearray .. c:type:: PyByteArrayObject diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index d62962cab45f..9f48f2ffafe1 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -8,7 +8,7 @@ Bytes Objects These functions raise :exc:`TypeError` when expecting a bytes parameter and called with a non-bytes parameter. -.. index:: object: bytes +.. index:: pair: object; bytes .. c:type:: PyBytesObject diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 1c8f432505ef..427ed959c585 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -5,7 +5,7 @@ Capsules -------- -.. index:: object: Capsule +.. index:: pair: object; Capsule Refer to :ref:`using-capsules` for more information on using these objects. diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 9228ce852000..344da903da4c 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -5,7 +5,7 @@ Complex Number Objects ---------------------- -.. index:: object: complex number +.. index:: pair: object; complex number Python's complex number objects are implemented as two distinct types when viewed from the C API: one is the Python object exposed to Python programs, and diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst index 8d3124a12fa9..880f7b15ce68 100644 --- a/Doc/c-api/concrete.rst +++ b/Doc/c-api/concrete.rst @@ -40,7 +40,7 @@ This section describes Python type objects and the singleton object ``None``. Numeric Objects =============== -.. index:: object: numeric +.. index:: pair: object; numeric .. toctree:: @@ -55,7 +55,7 @@ Numeric Objects Sequence Objects ================ -.. index:: object: sequence +.. index:: pair: object; sequence Generic operations on sequence objects were discussed in the previous chapter; this section deals with the specific kinds of sequence objects that are @@ -77,7 +77,7 @@ intrinsic to the Python language. Container Objects ================= -.. index:: object: mapping +.. index:: pair: object; mapping .. toctree:: diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index b9f84cea7856..f02abb01f022 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -5,7 +5,7 @@ Dictionary Objects ------------------ -.. index:: object: dictionary +.. index:: pair: object; dictionary .. c:type:: PyDictObject diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 58ed58e54668..f32ecba9f270 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -5,7 +5,7 @@ File Objects ------------ -.. index:: object: file +.. index:: pair: object; file These APIs are a minimal emulation of the Python 2 C API for built-in file objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 023b12c20b7c..05b2d100d575 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -5,7 +5,7 @@ Floating Point Objects ---------------------- -.. index:: object: floating point +.. index:: pair: object; floating point .. c:type:: PyFloatObject diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst index 947ed7040408..5857dba82c11 100644 --- a/Doc/c-api/function.rst +++ b/Doc/c-api/function.rst @@ -5,7 +5,7 @@ Function Objects ---------------- -.. index:: object: function +.. index:: pair: object; function There are a few functions specific to Python functions. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 1a200b919f0e..8de76e55cd05 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -261,7 +261,7 @@ complete listing. Objects, Types and Reference Counts =================================== -.. index:: object: type +.. index:: pair: object; type Most Python/C API functions have one or more arguments as well as a return value of type :c:expr:`PyObject*`. This type is a pointer to an opaque data type diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index f9e65354a259..317421f0db84 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -5,7 +5,7 @@ List Objects ------------ -.. index:: object: list +.. index:: pair: object; list .. c:type:: PyListObject diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 41b5632d2300..4a71c89ad85d 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -5,8 +5,8 @@ Integer Objects --------------- -.. index:: object: long integer - object: integer +.. index:: pair: object; long integer + pair: object; integer All integers are implemented as "long" integer objects of arbitrary size. diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index ebd5c7760437..2aa43318e7a4 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -3,7 +3,7 @@ .. _memoryview-objects: .. index:: - object: memoryview + pair: object; memoryview MemoryView objects ------------------ diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst index 6e7e1e21aa93..93ad30cd4f7a 100644 --- a/Doc/c-api/method.rst +++ b/Doc/c-api/method.rst @@ -5,7 +5,7 @@ Instance Method Objects ----------------------- -.. index:: object: instancemethod +.. index:: pair: object; instancemethod An instance method is a wrapper for a :c:data:`PyCFunction` and the new way to bind a :c:data:`PyCFunction` to a class object. It replaces the former call @@ -47,7 +47,7 @@ to bind a :c:data:`PyCFunction` to a class object. It replaces the former call Method Objects -------------- -.. index:: object: method +.. index:: pair: object; method Methods are bound function objects. Methods are always bound to an instance of a user-defined class. Unbound methods (methods bound to a class object) are diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index c0351c8a6c72..230b471d473b 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -5,7 +5,7 @@ Module Objects -------------- -.. index:: object: module +.. index:: pair: object; module .. c:var:: PyTypeObject PyModule_Type diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst index 26d2b7aab201..b84a16a28ead 100644 --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -5,7 +5,7 @@ The ``None`` Object ------------------- -.. index:: object: None +.. index:: pair: object; None Note that the :c:type:`PyTypeObject` for ``None`` is not directly exposed in the Python/C API. Since ``None`` is a singleton, testing for object identity (using diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index f0d905bae8ae..8e8af6025225 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -9,8 +9,8 @@ Set Objects .. index:: - object: set - object: frozenset + pair: object; set + pair: object; frozenset This section details the public API for :class:`set` and :class:`frozenset` objects. Any functionality not listed below is best accessed using either diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 5acddf7849aa..ac62058676ee 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -5,7 +5,7 @@ Tuple Objects ------------- -.. index:: object: tuple +.. index:: pair: object; tuple .. c:type:: PyTupleObject diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index c21fd9255d28..fb38935e0033 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -5,7 +5,7 @@ Type Objects ------------ -.. index:: object: type +.. index:: pair: object; type .. c:type:: PyTypeObject diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index ddb918de115f..5a022edb75b7 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1830,7 +1830,7 @@ are always available. They are listed here in alphabetical order. .. class:: type(object) type(name, bases, dict, **kwds) - .. index:: object: type + .. index:: pair: object; type With one argument, return the type of an *object*. The return value is a type object and generally the same object as returned by diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 150c1f93afd9..4ee0897db940 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -19,7 +19,7 @@ all modern Unix systems, Windows, MacOS, and probably additional platforms. .. include:: ../includes/wasm-notavail.rst -.. index:: object: socket +.. index:: pair: object; socket The Python interface is a straightforward transliteration of the Unix system call and library interface for sockets to Python's object-oriented style: the diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 46b0389adaa8..2f549f2e97c1 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -205,11 +205,11 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex` ================================================================ .. index:: - object: numeric - object: Boolean - object: integer - object: floating point - object: complex number + pair: object; numeric + pair: object; Boolean + pair: object; integer + pair: object; floating point + pair: object; complex number pair: C; language There are three distinct numeric types: :dfn:`integers`, :dfn:`floating @@ -927,7 +927,7 @@ described in dedicated sections. Common Sequence Operations -------------------------- -.. index:: object: sequence +.. index:: pair: object; sequence The operations in the following table are supported by most sequence types, both mutable and immutable. The :class:`collections.abc.Sequence` ABC is @@ -1112,7 +1112,7 @@ Immutable Sequence Types .. index:: triple: immutable; sequence; types - object: tuple + pair: object; tuple builtin: hash The only operation that immutable sequence types generally implement that is @@ -1134,8 +1134,8 @@ Mutable Sequence Types .. index:: triple: mutable; sequence; types - object: list - object: bytearray + pair: object; list + pair: object; bytearray The operations in the following table are defined on mutable sequence types. The :class:`collections.abc.MutableSequence` ABC is provided to make it @@ -1252,7 +1252,7 @@ Notes: Lists ----- -.. index:: object: list +.. index:: pair: object; list Lists are mutable sequences, typically used to store collections of homogeneous items (where the precise degree of similarity will vary by @@ -1331,7 +1331,7 @@ application). Tuples ------ -.. index:: object: tuple +.. index:: pair: object; tuple Tuples are immutable sequences, typically used to store collections of heterogeneous data (such as the 2-tuples produced by the :func:`enumerate` @@ -1375,7 +1375,7 @@ choice than a simple tuple object. Ranges ------ -.. index:: object: range +.. index:: pair: object; range The :class:`range` type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in :keyword:`for` @@ -1500,7 +1500,7 @@ objects that compare equal might have different :attr:`~range.start`, .. index:: single: string; text sequence type single: str (built-in class); (see also string) - object: string + pair: object; string .. _textseq: @@ -1534,7 +1534,7 @@ Since there is no separate "character" type, indexing a string produces strings of length 1. That is, for a non-empty string *s*, ``s[0] == s[0:1]``. .. index:: - object: io.StringIO + pair: object; io.StringIO There is also no mutable string type, but :meth:`str.join` or :class:`io.StringIO` can be used to efficiently construct strings from @@ -2508,9 +2508,9 @@ Binary Sequence Types --- :class:`bytes`, :class:`bytearray`, :class:`memoryview ================================================================================= .. index:: - object: bytes - object: bytearray - object: memoryview + pair: object; bytes + pair: object; bytearray + pair: object; memoryview pair: module; array The core built-in types for manipulating binary data are :class:`bytes` and @@ -2526,7 +2526,7 @@ The :mod:`array` module supports efficient storage of basic data types like Bytes Objects ------------- -.. index:: object: bytes +.. index:: pair: object; bytes Bytes objects are immutable sequences of single bytes. Since many major binary protocols are based on the ASCII text encoding, bytes objects offer @@ -2633,7 +2633,7 @@ always convert a bytes object into a list of integers using ``list(b)``. Bytearray Objects ----------------- -.. index:: object: bytearray +.. index:: pair: object; bytearray :class:`bytearray` objects are a mutable counterpart to :class:`bytes` objects. @@ -4212,7 +4212,7 @@ copying. Set Types --- :class:`set`, :class:`frozenset` ============================================== -.. index:: object: set +.. index:: pair: object; set A :dfn:`set` object is an unordered collection of distinct :term:`hashable` objects. Common uses include membership testing, removing duplicates from a sequence, and @@ -4414,8 +4414,8 @@ Mapping Types --- :class:`dict` =============================== .. index:: - object: mapping - object: dictionary + pair: object; mapping + pair: object; dictionary triple: operations on; mapping; types triple: operations on; dictionary; type statement: del @@ -4889,7 +4889,7 @@ Generic Alias Type ------------------ .. index:: - object: GenericAlias + pair: object; GenericAlias pair: Generic; Alias ``GenericAlias`` objects are generally created by @@ -5144,7 +5144,7 @@ Union Type ---------- .. index:: - object: Union + pair: object; Union pair: union; type A union object holds the value of the ``|`` (bitwise or) operation on @@ -5301,7 +5301,7 @@ See :ref:`function` for more information. Methods ------- -.. index:: object: method +.. index:: pair: object; method Methods are functions that are called using the attribute notation. There are two flavors: built-in methods (such as :meth:`append` on lists) and class diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 57a0d0a1258c..bacf8ceac504 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -444,7 +444,7 @@ always available. object <traceback-objects>` which typically encapsulates the call stack at the point where the exception last occurred. - .. index:: object: traceback + .. index:: pair: object; traceback If no exception is being handled anywhere on the stack, this function return a tuple containing three ``None`` values. diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 561c85290463..5c0e261b9076 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -14,7 +14,7 @@ interpreter when it prints a stack trace. This is useful when you want to print stack traces under program control, such as in a "wrapper" around the interpreter. -.. index:: object: traceback +.. index:: pair: object; traceback The module uses traceback objects --- these are objects of type :class:`types.TracebackType`, which are assigned to the ``__traceback__`` field of :class:`BaseException` instances. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 1f03180f1565..5750d3149c8e 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -147,7 +147,7 @@ The :keyword:`!for` statement pair: keyword; else pair: target; list pair: loop; statement - object: sequence + pair: object; sequence single: : (colon); compound statement The :keyword:`for` statement is used to iterate over the elements of a sequence @@ -298,7 +298,7 @@ keeping all locals in that frame alive until the next garbage collection occurs. .. index:: pair: module; sys - object: traceback + pair: object; traceback Before an :keyword:`!except` clause's suite is executed, the exception is stored in the :mod:`sys` module, where it can be accessed @@ -1194,8 +1194,8 @@ Function definitions pair: function; definition pair: function; name pair: name; binding - object: user-defined function - object: function + pair: object; user-defined function + pair: object; function pair: function; name pair: name; binding single: () (parentheses); function definition @@ -1363,7 +1363,7 @@ Class definitions ================= .. index:: - object: class + pair: object; class statement: class pair: class; definition pair: class; name diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 9d3ea3f78de1..18906a005b27 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -142,7 +142,7 @@ attributes.' These are attributes that provide access to the implementation and are not intended for general use. Their definition may change in the future. None - .. index:: object: None + .. index:: pair: object; None This type has a single value. There is a single object with this value. This object is accessed through the built-in name ``None``. It is used to signify the @@ -150,7 +150,7 @@ None don't explicitly return anything. Its truth value is false. NotImplemented - .. index:: object: NotImplemented + .. index:: pair: object; NotImplemented This type has a single value. There is a single object with this value. This object is accessed through the built-in name ``NotImplemented``. Numeric methods @@ -171,7 +171,7 @@ NotImplemented Ellipsis .. index:: - object: Ellipsis + pair: object; Ellipsis single: ...; ellipsis literal This type has a single value. There is a single object with this value. This @@ -179,7 +179,7 @@ Ellipsis ``Ellipsis``. Its truth value is true. :class:`numbers.Number` - .. index:: object: numeric + .. index:: pair: object; numeric These are created by numeric literals and returned as results by arithmetic operators and arithmetic built-in functions. Numeric objects are immutable; @@ -209,7 +209,7 @@ Ellipsis numbers: :class:`numbers.Integral` - .. index:: object: integer + .. index:: pair: object; integer These represent elements from the mathematical set of integers (positive and negative). @@ -225,7 +225,7 @@ Ellipsis Booleans (:class:`bool`) .. index:: - object: Boolean + pair: object; Boolean single: False single: True @@ -242,7 +242,7 @@ Ellipsis :class:`numbers.Real` (:class:`float`) .. index:: - object: floating point + pair: object; floating point pair: floating point; number pair: C; language pair: Java; language @@ -257,7 +257,7 @@ Ellipsis :class:`numbers.Complex` (:class:`complex`) .. index:: - object: complex + pair: object; complex pair: complex; number These represent complex numbers as a pair of machine-level double precision @@ -268,7 +268,7 @@ Ellipsis Sequences .. index:: builtin: len - object: sequence + pair: object; sequence single: index operation single: item selection single: subscription @@ -293,8 +293,8 @@ Sequences Immutable sequences .. index:: - object: immutable sequence - object: immutable + pair: object; immutable sequence + pair: object; immutable An object of an immutable sequence type cannot change once it is created. (If the object contains references to other objects, these other objects may be @@ -328,7 +328,7 @@ Sequences Tuples .. index:: - object: tuple + pair: object; tuple pair: singleton; tuple pair: empty; tuple @@ -350,8 +350,8 @@ Sequences Mutable sequences .. index:: - object: mutable sequence - object: mutable + pair: object; mutable sequence + pair: object; mutable pair: assignment; statement single: subscription single: slicing @@ -363,7 +363,7 @@ Sequences There are currently two intrinsic mutable sequence types: Lists - .. index:: object: list + .. index:: pair: object; list The items of a list are arbitrary Python objects. Lists are formed by placing a comma-separated list of expressions in square brackets. (Note @@ -385,7 +385,7 @@ Sequences Set types .. index:: builtin: len - object: set type + pair: object; set type These represent unordered, finite sets of unique, immutable objects. As such, they cannot be indexed by any subscript. However, they can be iterated over, and @@ -402,14 +402,14 @@ Set types There are currently two intrinsic set types: Sets - .. index:: object: set + .. index:: pair: object; set These represent a mutable set. They are created by the built-in :func:`set` constructor and can be modified afterwards by several methods, such as :meth:`~set.add`. Frozen sets - .. index:: object: frozenset + .. index:: pair: object; frozenset These represent an immutable set. They are created by the built-in :func:`frozenset` constructor. As a frozenset is immutable and @@ -420,7 +420,7 @@ Mappings .. index:: builtin: len single: subscription - object: mapping + pair: object; mapping These represent finite sets of objects indexed by arbitrary index sets. The subscript notation ``a[k]`` selects the item indexed by ``k`` from the mapping @@ -431,7 +431,7 @@ Mappings There is currently a single intrinsic mapping type: Dictionaries - .. index:: object: dictionary + .. index:: pair: object; dictionary These represent finite sets of objects indexed by nearly arbitrary values. The only types of values not acceptable as keys are values containing lists or @@ -465,7 +465,7 @@ Mappings Callable types .. index:: - object: callable + pair: object; callable pair: function; call single: invocation pair: function; argument @@ -476,8 +476,8 @@ Callable types User-defined functions .. index:: pair: user-defined; function - object: function - object: user-defined function + pair: object; function + pair: object; user-defined function A user-defined function object is created by a function definition (see section :ref:`function`). It should be called with an argument list @@ -580,8 +580,8 @@ Callable types Instance methods .. index:: - object: method - object: user-defined method + pair: object; method + pair: object; user-defined method pair: user-defined; method An instance method object combines a class, a class instance and any @@ -688,8 +688,8 @@ Callable types Built-in functions .. index:: - object: built-in function - object: function + pair: object; built-in function + pair: object; function pair: C; language A built-in function object is a wrapper around a C function. Examples of @@ -703,8 +703,8 @@ Callable types Built-in methods .. index:: - object: built-in method - object: method + pair: object; built-in method + pair: object; method pair: built-in; method This is really a different disguise of a built-in function, this time containing @@ -728,7 +728,7 @@ Callable types Modules .. index:: statement: import - object: module + pair: object; module Modules are a basic organizational unit of Python code, and are created by the :ref:`import system <importsystem>` as invoked either by the @@ -805,12 +805,12 @@ Custom classes .. XXX: Could we add that MRO doc as an appendix to the language ref? .. index:: - object: class - object: class instance - object: instance + pair: object; class + pair: object; class instance + pair: object; instance pair: class object; call single: container - object: dictionary + pair: object; dictionary pair: class; attribute When a class attribute reference (for class :class:`C`, say) would yield a @@ -865,8 +865,8 @@ Custom classes Class instances .. index:: - object: class instance - object: instance + pair: object; class instance + pair: object; instance pair: class; instance pair: class instance; attribute @@ -892,9 +892,9 @@ Class instances dictionary directly. .. index:: - object: numeric - object: sequence - object: mapping + pair: object; numeric + pair: object; sequence + pair: object; mapping Class instances can pretend to be numbers, sequences, or mappings if they have methods with certain special names. See section :ref:`specialnames`. @@ -996,7 +996,7 @@ Internal types required stack size; :attr:`co_flags` is an integer encoding a number of flags for the interpreter. - .. index:: object: generator + .. index:: pair: object; generator The following flag bits are defined for :attr:`co_flags`: bit ``0x04`` is set if the function uses the ``*arguments`` syntax to accept an arbitrary number of @@ -1053,7 +1053,7 @@ Internal types .. _frame-objects: Frame objects - .. index:: object: frame + .. index:: pair: object; frame Frame objects represent execution frames. They may occur in traceback objects (see below), and are also passed to registered trace functions. @@ -1116,7 +1116,7 @@ Internal types Traceback objects .. index:: - object: traceback + pair: object; traceback pair: stack; trace pair: exception; handler pair: execution; stack @@ -1498,7 +1498,7 @@ Basic customization .. method:: object.__hash__(self) .. index:: - object: dictionary + pair: object; dictionary builtin: hash Called by built-in function :func:`hash` and for operations on members of @@ -2506,7 +2506,7 @@ through the object's keys; for sequences, it should iterate through the values. .. versionadded:: 3.4 -.. index:: object: slice +.. index:: pair: object; slice .. note:: diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index b1bb162f62e1..78185657bf82 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -245,7 +245,7 @@ List displays pair: list; display pair: list; comprehensions pair: empty; list - object: list + pair: object; list single: [] (square brackets); list expression single: , (comma); expression list @@ -270,7 +270,7 @@ Set displays .. index:: pair: set; display pair: set; comprehensions - object: set + pair: object; set single: {} (curly brackets); set expression single: , (comma); expression list @@ -299,7 +299,7 @@ Dictionary displays pair: dictionary; display pair: dictionary; comprehensions key, datum, key/datum pair - object: dictionary + pair: object; dictionary single: {} (curly brackets); dictionary expression single: : (colon); in dictionary expressions single: , (comma); in dictionary displays @@ -361,7 +361,7 @@ Generator expressions .. index:: pair: generator; expression - object: generator + pair: object; generator single: () (parentheses); generator expression A generator expression is a compact generator notation in parentheses: @@ -522,7 +522,7 @@ on the right hand side of an assignment statement. The proposal that expanded on :pep:`492` by adding generator capabilities to coroutine functions. -.. index:: object: generator +.. index:: pair: object; generator .. _generator-methods: Generator-iterator methods @@ -701,7 +701,7 @@ of a *finalizer* method see the implementation of The expression ``yield from <expr>`` is a syntax error when used in an asynchronous generator function. -.. index:: object: asynchronous-generator +.. index:: pair: object; asynchronous-generator .. _asynchronous-generator-methods: Asynchronous generator-iterator methods @@ -811,8 +811,8 @@ An attribute reference is a primary followed by a period and a name: .. index:: exception: AttributeError - object: module - object: list + pair: object; module + pair: object; list The primary must evaluate to an object of a type that supports attribute references, which most objects do. This object is then asked to produce the @@ -833,12 +833,12 @@ Subscriptions single: [] (square brackets); subscription .. index:: - object: sequence - object: mapping - object: string - object: tuple - object: list - object: dictionary + pair: object; sequence + pair: object; mapping + pair: object; string + pair: object; tuple + pair: object; list + pair: object; dictionary pair: sequence; item The subscription of an instance of a :ref:`container class <sequence-types>` @@ -906,10 +906,10 @@ Slicings single: , (comma); slicing .. index:: - object: sequence - object: string - object: tuple - object: list + pair: object; sequence + pair: object; string + pair: object; tuple + pair: object; list A slicing selects a range of items in a sequence object (e.g., a string, tuple or list). Slicings may be used as expressions or as targets in assignment or @@ -950,7 +950,7 @@ substituting ``None`` for missing expressions. .. index:: - object: callable + pair: object; callable single: call single: argument; call semantics single: () (parentheses); call @@ -1100,8 +1100,8 @@ a user-defined function: .. index:: pair: function; call triple: user-defined; function; call - object: user-defined function - object: function + pair: object; user-defined function + pair: object; function The code block for the function is executed, passing it the argument list. The first thing the code block will do is bind the formal parameters to the @@ -1115,25 +1115,25 @@ a built-in function or method: pair: built-in function; call pair: method; call pair: built-in method; call - object: built-in method - object: built-in function - object: method - object: function + pair: object; built-in method + pair: object; built-in function + pair: object; method + pair: object; function The result is up to the interpreter; see :ref:`built-in-funcs` for the descriptions of built-in functions and methods. a class object: .. index:: - object: class + pair: object; class pair: class object; call A new instance of that class is returned. a class instance method: .. index:: - object: class instance - object: instance + pair: object; class instance + pair: object; instance pair: class instance; call The corresponding user-defined function is called, with an argument list that is @@ -1672,7 +1672,7 @@ if :keyword:`in` raised that exception). pair: operator; in pair: operator; not in pair: membership; test - object: sequence + pair: object; sequence The operator :keyword:`not in` is defined to have the inverse truth value of :keyword:`in`. @@ -1854,7 +1854,7 @@ Expression lists starred_expression: `expression` | (`starred_item` ",")* [`starred_item`] starred_item: `assignment_expression` | "*" `or_expr` -.. index:: object: tuple +.. index:: pair: object; tuple Except when part of a list or set display, an expression list containing at least one comma yields a tuple. The length of diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 5c7b5d7efaa2..acc3998e09be 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -54,7 +54,7 @@ expression). .. index:: builtin: repr - object: None + pair: object; None pair: string; conversion single: output pair: standard; output @@ -76,7 +76,7 @@ Assignment statements pair: assignment; statement pair: binding; name pair: rebinding; name - object: mutable + pair: object; mutable pair: attribute; assignment Assignment statements are used to (re)bind names to values and to modify @@ -185,7 +185,7 @@ Assignment of an object to a single target is recursively defined as follows. .. index:: pair: subscription; assignment - object: mutable + pair: object; mutable * If the target is a subscription: The primary expression in the reference is evaluated. It should yield either a mutable sequence object (such as a list) @@ -193,8 +193,8 @@ Assignment of an object to a single target is recursively defined as follows. evaluated. .. index:: - object: sequence - object: list + pair: object; sequence + pair: object; list If the primary is a mutable sequence object (such as a list), the subscript must yield an integer. If it is negative, the sequence's length is added to @@ -204,8 +204,8 @@ Assignment of an object to a single target is recursively defined as follows. raised (assignment to a subscripted sequence cannot add new items to a list). .. index:: - object: mapping - object: dictionary + pair: object; mapping + pair: object; dictionary If the primary is a mapping object (such as a dictionary), the subscript must have a type compatible with the mapping's key type, and the mapping is then @@ -574,7 +574,7 @@ instantiating the class with no arguments. The :dfn:`type` of the exception is the exception instance's class, the :dfn:`value` is the instance itself. -.. index:: object: traceback +.. index:: pair: object; traceback A traceback object is normally created automatically when an exception is raised and attached to it as the :attr:`__traceback__` attribute, which is writable. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 8ca3ef04523a..41016113d257 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -692,7 +692,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('module', None) pairindextypes.pop('keyword', None) pairindextypes.pop('operator', None) - # pairindextypes.pop('object', None) + pairindextypes.pop('object', None) # pairindextypes.pop('exception', None) # pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 116801177a3a..06445e000c1e 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -344,7 +344,7 @@ list objects have methods called append, insert, remove, sort, and so on. However, in the following discussion, we'll use the term method exclusively to mean methods of class instance objects, unless explicitly stated otherwise.) -.. index:: object: method +.. index:: pair: object; method Valid method names of an instance object depend on its class. By definition, all attributes of a class that are function objects define corresponding diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index aeacc1559a22..3fcf4e3f43a3 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -286,7 +286,7 @@ Reading and Writing Files .. index:: builtin: open - object: file + pair: object; file :func:`open` returns a :term:`file object`, and is most commonly used with two positional arguments and one keyword argument: From webhook-mailer at python.org Thu May 4 06:14:24 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 10:14:24 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('object') (GH-104158) (#104159) Message-ID: <mailman.148.1683195265.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c463796ba7f18079bf2554650bc9ac09bca49dca commit: c463796ba7f18079bf2554650bc9ac09bca49dca branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T13:14:16+03:00 summary: [3.11] GH-97950: Use new-style index directive ('object') (GH-104158) (#104159) GH-97950: Use new-style index directive ('object') (GH-104158) * Uncomment object removal in pairindextypes * Use new-style index directive ('object') - C API * Use new-style index directive ('object') - Library * Use new-style index directive ('object') - Reference * Use new-style index directive ('object') - Tutorial (cherry picked from commit 6ab463684b9d79880d98cd1f1406aa86af65985e) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/bytearray.rst M Doc/c-api/bytes.rst M Doc/c-api/capsule.rst M Doc/c-api/complex.rst M Doc/c-api/concrete.rst M Doc/c-api/dict.rst M Doc/c-api/file.rst M Doc/c-api/float.rst M Doc/c-api/function.rst M Doc/c-api/intro.rst M Doc/c-api/list.rst M Doc/c-api/long.rst M Doc/c-api/memoryview.rst M Doc/c-api/method.rst M Doc/c-api/module.rst M Doc/c-api/none.rst M Doc/c-api/set.rst M Doc/c-api/tuple.rst M Doc/c-api/type.rst M Doc/library/functions.rst M Doc/library/socket.rst M Doc/library/stdtypes.rst M Doc/library/sys.rst M Doc/library/traceback.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/expressions.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/classes.rst M Doc/tutorial/inputoutput.rst diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst index 4bf3cfe100cd..456f7d89bca0 100644 --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -5,7 +5,7 @@ Byte Array Objects ------------------ -.. index:: object: bytearray +.. index:: pair: object; bytearray .. c:type:: PyByteArrayObject diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index 7617487a462d..21a5ab931c8b 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -8,7 +8,7 @@ Bytes Objects These functions raise :exc:`TypeError` when expecting a bytes parameter and called with a non-bytes parameter. -.. index:: object: bytes +.. index:: pair: object; bytes .. c:type:: PyBytesObject diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index 1c8f432505ef..427ed959c585 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -5,7 +5,7 @@ Capsules -------- -.. index:: object: Capsule +.. index:: pair: object; Capsule Refer to :ref:`using-capsules` for more information on using these objects. diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 9228ce852000..344da903da4c 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -5,7 +5,7 @@ Complex Number Objects ---------------------- -.. index:: object: complex number +.. index:: pair: object; complex number Python's complex number objects are implemented as two distinct types when viewed from the C API: one is the Python object exposed to Python programs, and diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst index 8d3124a12fa9..880f7b15ce68 100644 --- a/Doc/c-api/concrete.rst +++ b/Doc/c-api/concrete.rst @@ -40,7 +40,7 @@ This section describes Python type objects and the singleton object ``None``. Numeric Objects =============== -.. index:: object: numeric +.. index:: pair: object; numeric .. toctree:: @@ -55,7 +55,7 @@ Numeric Objects Sequence Objects ================ -.. index:: object: sequence +.. index:: pair: object; sequence Generic operations on sequence objects were discussed in the previous chapter; this section deals with the specific kinds of sequence objects that are @@ -77,7 +77,7 @@ intrinsic to the Python language. Container Objects ================= -.. index:: object: mapping +.. index:: pair: object; mapping .. toctree:: diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index be7b5f135243..4bfd1d01590b 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -5,7 +5,7 @@ Dictionary Objects ------------------ -.. index:: object: dictionary +.. index:: pair: object; dictionary .. c:type:: PyDictObject diff --git a/Doc/c-api/file.rst b/Doc/c-api/file.rst index 58ed58e54668..f32ecba9f270 100644 --- a/Doc/c-api/file.rst +++ b/Doc/c-api/file.rst @@ -5,7 +5,7 @@ File Objects ------------ -.. index:: object: file +.. index:: pair: object; file These APIs are a minimal emulation of the Python 2 C API for built-in file objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 023b12c20b7c..05b2d100d575 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -5,7 +5,7 @@ Floating Point Objects ---------------------- -.. index:: object: floating point +.. index:: pair: object; floating point .. c:type:: PyFloatObject diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst index 56c18396d322..1f28a685978b 100644 --- a/Doc/c-api/function.rst +++ b/Doc/c-api/function.rst @@ -5,7 +5,7 @@ Function Objects ---------------- -.. index:: object: function +.. index:: pair: object; function There are a few functions specific to Python functions. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index bd37ed58ffdf..17710b02abbc 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -261,7 +261,7 @@ complete listing. Objects, Types and Reference Counts =================================== -.. index:: object: type +.. index:: pair: object; type Most Python/C API functions have one or more arguments as well as a return value of type :c:expr:`PyObject*`. This type is a pointer to an opaque data type diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index f9e65354a259..317421f0db84 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -5,7 +5,7 @@ List Objects ------------ -.. index:: object: list +.. index:: pair: object; list .. c:type:: PyListObject diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index b3e455d0a89c..7b0d55dac879 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -5,8 +5,8 @@ Integer Objects --------------- -.. index:: object: long integer - object: integer +.. index:: pair: object; long integer + pair: object; integer All integers are implemented as "long" integer objects of arbitrary size. diff --git a/Doc/c-api/memoryview.rst b/Doc/c-api/memoryview.rst index ebd5c7760437..2aa43318e7a4 100644 --- a/Doc/c-api/memoryview.rst +++ b/Doc/c-api/memoryview.rst @@ -3,7 +3,7 @@ .. _memoryview-objects: .. index:: - object: memoryview + pair: object; memoryview MemoryView objects ------------------ diff --git a/Doc/c-api/method.rst b/Doc/c-api/method.rst index 6e7e1e21aa93..93ad30cd4f7a 100644 --- a/Doc/c-api/method.rst +++ b/Doc/c-api/method.rst @@ -5,7 +5,7 @@ Instance Method Objects ----------------------- -.. index:: object: instancemethod +.. index:: pair: object; instancemethod An instance method is a wrapper for a :c:data:`PyCFunction` and the new way to bind a :c:data:`PyCFunction` to a class object. It replaces the former call @@ -47,7 +47,7 @@ to bind a :c:data:`PyCFunction` to a class object. It replaces the former call Method Objects -------------- -.. index:: object: method +.. index:: pair: object; method Methods are bound function objects. Methods are always bound to an instance of a user-defined class. Unbound methods (methods bound to a class object) are diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index c0351c8a6c72..230b471d473b 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -5,7 +5,7 @@ Module Objects -------------- -.. index:: object: module +.. index:: pair: object; module .. c:var:: PyTypeObject PyModule_Type diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst index 26d2b7aab201..b84a16a28ead 100644 --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -5,7 +5,7 @@ The ``None`` Object ------------------- -.. index:: object: None +.. index:: pair: object; None Note that the :c:type:`PyTypeObject` for ``None`` is not directly exposed in the Python/C API. Since ``None`` is a singleton, testing for object identity (using diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index f0d905bae8ae..8e8af6025225 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -9,8 +9,8 @@ Set Objects .. index:: - object: set - object: frozenset + pair: object; set + pair: object; frozenset This section details the public API for :class:`set` and :class:`frozenset` objects. Any functionality not listed below is best accessed using either diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 0bfd4b308d93..0982d29e48de 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -5,7 +5,7 @@ Tuple Objects ------------- -.. index:: object: tuple +.. index:: pair: object; tuple .. c:type:: PyTupleObject diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index ac352047798e..52eeef0a0086 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -5,7 +5,7 @@ Type Objects ------------ -.. index:: object: type +.. index:: pair: object; type .. c:type:: PyTypeObject diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 53294aa901a5..c5bdfc21e183 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1822,7 +1822,7 @@ are always available. They are listed here in alphabetical order. .. class:: type(object) type(name, bases, dict, **kwds) - .. index:: object: type + .. index:: pair: object; type With one argument, return the type of an *object*. The return value is a type object and generally the same object as returned by diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index e222dc70e422..ab38b1d1da06 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -19,7 +19,7 @@ all modern Unix systems, Windows, MacOS, and probably additional platforms. .. include:: ../includes/wasm-notavail.rst -.. index:: object: socket +.. index:: pair: object; socket The Python interface is a straightforward transliteration of the Unix system call and library interface for sockets to Python's object-oriented style: the diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index b636adab60dd..960959073c4b 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -205,11 +205,11 @@ Numeric Types --- :class:`int`, :class:`float`, :class:`complex` ================================================================ .. index:: - object: numeric - object: Boolean - object: integer - object: floating point - object: complex number + pair: object; numeric + pair: object; Boolean + pair: object; integer + pair: object; floating point + pair: object; complex number pair: C; language There are three distinct numeric types: :dfn:`integers`, :dfn:`floating @@ -888,7 +888,7 @@ described in dedicated sections. Common Sequence Operations -------------------------- -.. index:: object: sequence +.. index:: pair: object; sequence The operations in the following table are supported by most sequence types, both mutable and immutable. The :class:`collections.abc.Sequence` ABC is @@ -1073,7 +1073,7 @@ Immutable Sequence Types .. index:: triple: immutable; sequence; types - object: tuple + pair: object; tuple builtin: hash The only operation that immutable sequence types generally implement that is @@ -1095,8 +1095,8 @@ Mutable Sequence Types .. index:: triple: mutable; sequence; types - object: list - object: bytearray + pair: object; list + pair: object; bytearray The operations in the following table are defined on mutable sequence types. The :class:`collections.abc.MutableSequence` ABC is provided to make it @@ -1213,7 +1213,7 @@ Notes: Lists ----- -.. index:: object: list +.. index:: pair: object; list Lists are mutable sequences, typically used to store collections of homogeneous items (where the precise degree of similarity will vary by @@ -1292,7 +1292,7 @@ application). Tuples ------ -.. index:: object: tuple +.. index:: pair: object; tuple Tuples are immutable sequences, typically used to store collections of heterogeneous data (such as the 2-tuples produced by the :func:`enumerate` @@ -1336,7 +1336,7 @@ choice than a simple tuple object. Ranges ------ -.. index:: object: range +.. index:: pair: object; range The :class:`range` type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in :keyword:`for` @@ -1461,7 +1461,7 @@ objects that compare equal might have different :attr:`~range.start`, .. index:: single: string; text sequence type single: str (built-in class); (see also string) - object: string + pair: object; string .. _textseq: @@ -1495,7 +1495,7 @@ Since there is no separate "character" type, indexing a string produces strings of length 1. That is, for a non-empty string *s*, ``s[0] == s[0:1]``. .. index:: - object: io.StringIO + pair: object; io.StringIO There is also no mutable string type, but :meth:`str.join` or :class:`io.StringIO` can be used to efficiently construct strings from @@ -2464,9 +2464,9 @@ Binary Sequence Types --- :class:`bytes`, :class:`bytearray`, :class:`memoryview ================================================================================= .. index:: - object: bytes - object: bytearray - object: memoryview + pair: object; bytes + pair: object; bytearray + pair: object; memoryview pair: module; array The core built-in types for manipulating binary data are :class:`bytes` and @@ -2482,7 +2482,7 @@ The :mod:`array` module supports efficient storage of basic data types like Bytes Objects ------------- -.. index:: object: bytes +.. index:: pair: object; bytes Bytes objects are immutable sequences of single bytes. Since many major binary protocols are based on the ASCII text encoding, bytes objects offer @@ -2589,7 +2589,7 @@ always convert a bytes object into a list of integers using ``list(b)``. Bytearray Objects ----------------- -.. index:: object: bytearray +.. index:: pair: object; bytearray :class:`bytearray` objects are a mutable counterpart to :class:`bytes` objects. @@ -4165,7 +4165,7 @@ copying. Set Types --- :class:`set`, :class:`frozenset` ============================================== -.. index:: object: set +.. index:: pair: object; set A :dfn:`set` object is an unordered collection of distinct :term:`hashable` objects. Common uses include membership testing, removing duplicates from a sequence, and @@ -4367,8 +4367,8 @@ Mapping Types --- :class:`dict` =============================== .. index:: - object: mapping - object: dictionary + pair: object; mapping + pair: object; dictionary triple: operations on; mapping; types triple: operations on; dictionary; type statement: del @@ -4836,7 +4836,7 @@ Generic Alias Type ------------------ .. index:: - object: GenericAlias + pair: object; GenericAlias pair: Generic; Alias ``GenericAlias`` objects are generally created by @@ -5091,7 +5091,7 @@ Union Type ---------- .. index:: - object: Union + pair: object; Union pair: union; type A union object holds the value of the ``|`` (bitwise or) operation on @@ -5248,7 +5248,7 @@ See :ref:`function` for more information. Methods ------- -.. index:: object: method +.. index:: pair: object; method Methods are functions that are called using the attribute notation. There are two flavors: built-in methods (such as :meth:`append` on lists) and class diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 6f90e6b42216..32713b2a8879 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -440,7 +440,7 @@ always available. object <traceback-objects>` which typically encapsulates the call stack at the point where the exception last occurred. - .. index:: object: traceback + .. index:: pair: object; traceback If no exception is being handled anywhere on the stack, this function return a tuple containing three ``None`` values. diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 053e97325e31..fd6a70cdfab1 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -14,7 +14,7 @@ interpreter when it prints a stack trace. This is useful when you want to print stack traces under program control, such as in a "wrapper" around the interpreter. -.. index:: object: traceback +.. index:: pair: object; traceback The module uses traceback objects --- these are objects of type :class:`types.TracebackType`, which are assigned to the ``__traceback__`` field of :class:`BaseException` instances. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 3ed7239cd374..4578e662ada6 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -147,7 +147,7 @@ The :keyword:`!for` statement pair: keyword; else pair: target; list pair: loop; statement - object: sequence + pair: object; sequence single: : (colon); compound statement The :keyword:`for` statement is used to iterate over the elements of a sequence @@ -298,7 +298,7 @@ keeping all locals in that frame alive until the next garbage collection occurs. .. index:: pair: module; sys - object: traceback + pair: object; traceback Before an :keyword:`!except` clause's suite is executed, the exception is stored in the :mod:`sys` module, where it can be accessed @@ -1196,8 +1196,8 @@ Function definitions pair: function; definition pair: function; name pair: name; binding - object: user-defined function - object: function + pair: object; user-defined function + pair: object; function pair: function; name pair: name; binding single: () (parentheses); function definition @@ -1365,7 +1365,7 @@ Class definitions ================= .. index:: - object: class + pair: object; class statement: class pair: class; definition pair: class; name diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e8117d982c2a..3f3a37dacc15 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -142,7 +142,7 @@ attributes.' These are attributes that provide access to the implementation and are not intended for general use. Their definition may change in the future. None - .. index:: object: None + .. index:: pair: object; None This type has a single value. There is a single object with this value. This object is accessed through the built-in name ``None``. It is used to signify the @@ -150,7 +150,7 @@ None don't explicitly return anything. Its truth value is false. NotImplemented - .. index:: object: NotImplemented + .. index:: pair: object; NotImplemented This type has a single value. There is a single object with this value. This object is accessed through the built-in name ``NotImplemented``. Numeric methods @@ -171,7 +171,7 @@ NotImplemented Ellipsis .. index:: - object: Ellipsis + pair: object; Ellipsis single: ...; ellipsis literal This type has a single value. There is a single object with this value. This @@ -179,7 +179,7 @@ Ellipsis ``Ellipsis``. Its truth value is true. :class:`numbers.Number` - .. index:: object: numeric + .. index:: pair: object; numeric These are created by numeric literals and returned as results by arithmetic operators and arithmetic built-in functions. Numeric objects are immutable; @@ -209,7 +209,7 @@ Ellipsis numbers: :class:`numbers.Integral` - .. index:: object: integer + .. index:: pair: object; integer These represent elements from the mathematical set of integers (positive and negative). @@ -225,7 +225,7 @@ Ellipsis Booleans (:class:`bool`) .. index:: - object: Boolean + pair: object; Boolean single: False single: True @@ -242,7 +242,7 @@ Ellipsis :class:`numbers.Real` (:class:`float`) .. index:: - object: floating point + pair: object; floating point pair: floating point; number pair: C; language pair: Java; language @@ -257,7 +257,7 @@ Ellipsis :class:`numbers.Complex` (:class:`complex`) .. index:: - object: complex + pair: object; complex pair: complex; number These represent complex numbers as a pair of machine-level double precision @@ -268,7 +268,7 @@ Ellipsis Sequences .. index:: builtin: len - object: sequence + pair: object; sequence single: index operation single: item selection single: subscription @@ -293,8 +293,8 @@ Sequences Immutable sequences .. index:: - object: immutable sequence - object: immutable + pair: object; immutable sequence + pair: object; immutable An object of an immutable sequence type cannot change once it is created. (If the object contains references to other objects, these other objects may be @@ -328,7 +328,7 @@ Sequences Tuples .. index:: - object: tuple + pair: object; tuple pair: singleton; tuple pair: empty; tuple @@ -350,8 +350,8 @@ Sequences Mutable sequences .. index:: - object: mutable sequence - object: mutable + pair: object; mutable sequence + pair: object; mutable pair: assignment; statement single: subscription single: slicing @@ -363,7 +363,7 @@ Sequences There are currently two intrinsic mutable sequence types: Lists - .. index:: object: list + .. index:: pair: object; list The items of a list are arbitrary Python objects. Lists are formed by placing a comma-separated list of expressions in square brackets. (Note @@ -385,7 +385,7 @@ Sequences Set types .. index:: builtin: len - object: set type + pair: object; set type These represent unordered, finite sets of unique, immutable objects. As such, they cannot be indexed by any subscript. However, they can be iterated over, and @@ -402,14 +402,14 @@ Set types There are currently two intrinsic set types: Sets - .. index:: object: set + .. index:: pair: object; set These represent a mutable set. They are created by the built-in :func:`set` constructor and can be modified afterwards by several methods, such as :meth:`~set.add`. Frozen sets - .. index:: object: frozenset + .. index:: pair: object; frozenset These represent an immutable set. They are created by the built-in :func:`frozenset` constructor. As a frozenset is immutable and @@ -420,7 +420,7 @@ Mappings .. index:: builtin: len single: subscription - object: mapping + pair: object; mapping These represent finite sets of objects indexed by arbitrary index sets. The subscript notation ``a[k]`` selects the item indexed by ``k`` from the mapping @@ -431,7 +431,7 @@ Mappings There is currently a single intrinsic mapping type: Dictionaries - .. index:: object: dictionary + .. index:: pair: object; dictionary These represent finite sets of objects indexed by nearly arbitrary values. The only types of values not acceptable as keys are values containing lists or @@ -465,7 +465,7 @@ Mappings Callable types .. index:: - object: callable + pair: object; callable pair: function; call single: invocation pair: function; argument @@ -476,8 +476,8 @@ Callable types User-defined functions .. index:: pair: user-defined; function - object: function - object: user-defined function + pair: object; function + pair: object; user-defined function A user-defined function object is created by a function definition (see section :ref:`function`). It should be called with an argument list @@ -580,8 +580,8 @@ Callable types Instance methods .. index:: - object: method - object: user-defined method + pair: object; method + pair: object; user-defined method pair: user-defined; method An instance method object combines a class, a class instance and any @@ -688,8 +688,8 @@ Callable types Built-in functions .. index:: - object: built-in function - object: function + pair: object; built-in function + pair: object; function pair: C; language A built-in function object is a wrapper around a C function. Examples of @@ -703,8 +703,8 @@ Callable types Built-in methods .. index:: - object: built-in method - object: method + pair: object; built-in method + pair: object; method pair: built-in; method This is really a different disguise of a built-in function, this time containing @@ -728,7 +728,7 @@ Callable types Modules .. index:: statement: import - object: module + pair: object; module Modules are a basic organizational unit of Python code, and are created by the :ref:`import system <importsystem>` as invoked either by the @@ -805,12 +805,12 @@ Custom classes .. XXX: Could we add that MRO doc as an appendix to the language ref? .. index:: - object: class - object: class instance - object: instance + pair: object; class + pair: object; class instance + pair: object; instance pair: class object; call single: container - object: dictionary + pair: object; dictionary pair: class; attribute When a class attribute reference (for class :class:`C`, say) would yield a @@ -865,8 +865,8 @@ Custom classes Class instances .. index:: - object: class instance - object: instance + pair: object; class instance + pair: object; instance pair: class; instance pair: class instance; attribute @@ -892,9 +892,9 @@ Class instances dictionary directly. .. index:: - object: numeric - object: sequence - object: mapping + pair: object; numeric + pair: object; sequence + pair: object; mapping Class instances can pretend to be numbers, sequences, or mappings if they have methods with certain special names. See section :ref:`specialnames`. @@ -995,7 +995,7 @@ Internal types required stack size; :attr:`co_flags` is an integer encoding a number of flags for the interpreter. - .. index:: object: generator + .. index:: pair: object; generator The following flag bits are defined for :attr:`co_flags`: bit ``0x04`` is set if the function uses the ``*arguments`` syntax to accept an arbitrary number of @@ -1052,7 +1052,7 @@ Internal types .. _frame-objects: Frame objects - .. index:: object: frame + .. index:: pair: object; frame Frame objects represent execution frames. They may occur in traceback objects (see below), and are also passed to registered trace functions. @@ -1115,7 +1115,7 @@ Internal types Traceback objects .. index:: - object: traceback + pair: object; traceback pair: stack; trace pair: exception; handler pair: execution; stack @@ -1497,7 +1497,7 @@ Basic customization .. method:: object.__hash__(self) .. index:: - object: dictionary + pair: object; dictionary builtin: hash Called by built-in function :func:`hash` and for operations on members of @@ -2501,7 +2501,7 @@ through the object's keys; for sequences, it should iterate through the values. .. versionadded:: 3.4 -.. index:: object: slice +.. index:: pair: object; slice .. note:: diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 46e8c7c0e5c6..ba0f8d87ba9e 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -245,7 +245,7 @@ List displays pair: list; display pair: list; comprehensions pair: empty; list - object: list + pair: object; list single: [] (square brackets); list expression single: , (comma); expression list @@ -270,7 +270,7 @@ Set displays .. index:: pair: set; display pair: set; comprehensions - object: set + pair: object; set single: {} (curly brackets); set expression single: , (comma); expression list @@ -299,7 +299,7 @@ Dictionary displays pair: dictionary; display pair: dictionary; comprehensions key, datum, key/datum pair - object: dictionary + pair: object; dictionary single: {} (curly brackets); dictionary expression single: : (colon); in dictionary expressions single: , (comma); in dictionary displays @@ -361,7 +361,7 @@ Generator expressions .. index:: pair: generator; expression - object: generator + pair: object; generator single: () (parentheses); generator expression A generator expression is a compact generator notation in parentheses: @@ -522,7 +522,7 @@ on the right hand side of an assignment statement. The proposal that expanded on :pep:`492` by adding generator capabilities to coroutine functions. -.. index:: object: generator +.. index:: pair: object; generator .. _generator-methods: Generator-iterator methods @@ -696,7 +696,7 @@ of a *finalizer* method see the implementation of The expression ``yield from <expr>`` is a syntax error when used in an asynchronous generator function. -.. index:: object: asynchronous-generator +.. index:: pair: object; asynchronous-generator .. _asynchronous-generator-methods: Asynchronous generator-iterator methods @@ -800,8 +800,8 @@ An attribute reference is a primary followed by a period and a name: .. index:: exception: AttributeError - object: module - object: list + pair: object; module + pair: object; list The primary must evaluate to an object of a type that supports attribute references, which most objects do. This object is then asked to produce the @@ -822,12 +822,12 @@ Subscriptions single: [] (square brackets); subscription .. index:: - object: sequence - object: mapping - object: string - object: tuple - object: list - object: dictionary + pair: object; sequence + pair: object; mapping + pair: object; string + pair: object; tuple + pair: object; list + pair: object; dictionary pair: sequence; item The subscription of an instance of a :ref:`container class <sequence-types>` @@ -895,10 +895,10 @@ Slicings single: , (comma); slicing .. index:: - object: sequence - object: string - object: tuple - object: list + pair: object; sequence + pair: object; string + pair: object; tuple + pair: object; list A slicing selects a range of items in a sequence object (e.g., a string, tuple or list). Slicings may be used as expressions or as targets in assignment or @@ -939,7 +939,7 @@ substituting ``None`` for missing expressions. .. index:: - object: callable + pair: object; callable single: call single: argument; call semantics single: () (parentheses); call @@ -1089,8 +1089,8 @@ a user-defined function: .. index:: pair: function; call triple: user-defined; function; call - object: user-defined function - object: function + pair: object; user-defined function + pair: object; function The code block for the function is executed, passing it the argument list. The first thing the code block will do is bind the formal parameters to the @@ -1104,25 +1104,25 @@ a built-in function or method: pair: built-in function; call pair: method; call pair: built-in method; call - object: built-in method - object: built-in function - object: method - object: function + pair: object; built-in method + pair: object; built-in function + pair: object; method + pair: object; function The result is up to the interpreter; see :ref:`built-in-funcs` for the descriptions of built-in functions and methods. a class object: .. index:: - object: class + pair: object; class pair: class object; call A new instance of that class is returned. a class instance method: .. index:: - object: class instance - object: instance + pair: object; class instance + pair: object; instance pair: class instance; call The corresponding user-defined function is called, with an argument list that is @@ -1661,7 +1661,7 @@ if :keyword:`in` raised that exception). pair: operator; in pair: operator; not in pair: membership; test - object: sequence + pair: object; sequence The operator :keyword:`not in` is defined to have the inverse truth value of :keyword:`in`. @@ -1843,7 +1843,7 @@ Expression lists starred_expression: `expression` | (`starred_item` ",")* [`starred_item`] starred_item: `assignment_expression` | "*" `or_expr` -.. index:: object: tuple +.. index:: pair: object; tuple Except when part of a list or set display, an expression list containing at least one comma yields a tuple. The length of diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 5c7b5d7efaa2..acc3998e09be 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -54,7 +54,7 @@ expression). .. index:: builtin: repr - object: None + pair: object; None pair: string; conversion single: output pair: standard; output @@ -76,7 +76,7 @@ Assignment statements pair: assignment; statement pair: binding; name pair: rebinding; name - object: mutable + pair: object; mutable pair: attribute; assignment Assignment statements are used to (re)bind names to values and to modify @@ -185,7 +185,7 @@ Assignment of an object to a single target is recursively defined as follows. .. index:: pair: subscription; assignment - object: mutable + pair: object; mutable * If the target is a subscription: The primary expression in the reference is evaluated. It should yield either a mutable sequence object (such as a list) @@ -193,8 +193,8 @@ Assignment of an object to a single target is recursively defined as follows. evaluated. .. index:: - object: sequence - object: list + pair: object; sequence + pair: object; list If the primary is a mutable sequence object (such as a list), the subscript must yield an integer. If it is negative, the sequence's length is added to @@ -204,8 +204,8 @@ Assignment of an object to a single target is recursively defined as follows. raised (assignment to a subscripted sequence cannot add new items to a list). .. index:: - object: mapping - object: dictionary + pair: object; mapping + pair: object; dictionary If the primary is a mapping object (such as a dictionary), the subscript must have a type compatible with the mapping's key type, and the mapping is then @@ -574,7 +574,7 @@ instantiating the class with no arguments. The :dfn:`type` of the exception is the exception instance's class, the :dfn:`value` is the instance itself. -.. index:: object: traceback +.. index:: pair: object; traceback A traceback object is normally created automatically when an exception is raised and attached to it as the :attr:`__traceback__` attribute, which is writable. diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index d6034e1bb718..01c1c5cd7784 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -697,7 +697,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('module', None) pairindextypes.pop('keyword', None) pairindextypes.pop('operator', None) - # pairindextypes.pop('object', None) + pairindextypes.pop('object', None) # pairindextypes.pop('exception', None) # pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 30450c70f3e8..db4ca92ae342 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -344,7 +344,7 @@ list objects have methods called append, insert, remove, sort, and so on. However, in the following discussion, we'll use the term method exclusively to mean methods of class instance objects, unless explicitly stated otherwise.) -.. index:: object: method +.. index:: pair: object; method Valid method names of an instance object depend on its class. By definition, all attributes of a class that are function objects define corresponding diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index aeacc1559a22..3fcf4e3f43a3 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -286,7 +286,7 @@ Reading and Writing Files .. index:: builtin: open - object: file + pair: object; file :func:`open` returns a :term:`file object`, and is most commonly used with two positional arguments and one keyword argument: From webhook-mailer at python.org Thu May 4 06:20:28 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 04 May 2023 10:20:28 -0000 Subject: [Python-checkins] gh-104089: catch DeprecationWarning in `test_fstring` (#104137) Message-ID: <mailman.149.1683195628.13550.python-checkins@python.org> https://github.com/python/cpython/commit/83751bbd142c23ca3f6af34ec617630dc3173b2a commit: 83751bbd142c23ca3f6af34ec617630dc3173b2a branch: main author: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-04T11:20:20+01:00 summary: gh-104089: catch DeprecationWarning in `test_fstring` (#104137) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Lib/test/test_fstring.py diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index be71fde5aaba..58e2550715ce 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -980,11 +980,18 @@ def test_roundtrip_raw_quotes(self): 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\\}') + deprecated_cases = [ + (r"f'\{{\}}'", '\\{\\}'), + (r"f'\{{'", '\\{'), + (r"f'\{{{1+1}'", '\\{2'), + (r"f'\}}{1+1}'", '\\}2'), + (r"f'{1+1}\}}'", '2\\}') + ] + for case, expected_result in deprecated_cases: + with self.subTest(case=case, expected_result=expected_result): + with self.assertWarns(DeprecationWarning): + result = eval(case) + self.assertEqual(result, expected_result) self.assertEqual(fr'\{{\}}', '\\{\\}') self.assertEqual(fr'\{{', '\\{') self.assertEqual(fr'\{{{1+1}', '\\{2') From webhook-mailer at python.org Thu May 4 06:30:40 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 10:30:40 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('exception') (#104160) Message-ID: <mailman.150.1683196242.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3e7995ca119d4253d05a520f35ab3efca793ee49 commit: 3e7995ca119d4253d05a520f35ab3efca793ee49 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T13:30:24+03:00 summary: GH-97950: Use new-style index directive ('exception') (#104160) files: M Doc/reference/expressions.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 78185657bf82..b97a08f25d92 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -71,7 +71,7 @@ An identifier occurring as an atom is a name. See section :ref:`identifiers` for lexical definition and section :ref:`naming` for documentation of naming and binding. -.. index:: exception: NameError +.. index:: pair: exception; NameError When the name is bound to an object, evaluation of the atom yields that object. When a name is not bound, an attempt to evaluate it raises a :exc:`NameError` @@ -534,7 +534,7 @@ be used to control the execution of a generator function. Note that calling any of the generator methods below when the generator is already executing raises a :exc:`ValueError` exception. -.. index:: exception: StopIteration +.. index:: pair: exception; StopIteration .. method:: generator.__next__() @@ -589,7 +589,7 @@ is already executing raises a :exc:`ValueError` exception. The second signature \(type\[, value\[, traceback\]\]\) is deprecated and may be removed in a future version of Python. -.. index:: exception: GeneratorExit +.. index:: pair: exception; GeneratorExit .. method:: generator.close() @@ -711,7 +711,7 @@ This subsection describes the methods of an asynchronous generator iterator, which are used to control the execution of a generator function. -.. index:: exception: StopAsyncIteration +.. index:: pair: exception; StopAsyncIteration .. coroutinemethod:: agen.__anext__() @@ -763,7 +763,7 @@ which are used to control the execution of a generator function. The second signature \(type\[, value\[, traceback\]\]\) is deprecated and may be removed in a future version of Python. -.. index:: exception: GeneratorExit +.. index:: pair: exception; GeneratorExit .. coroutinemethod:: agen.aclose() @@ -810,7 +810,7 @@ An attribute reference is a primary followed by a period and a name: attributeref: `primary` "." `identifier` .. index:: - exception: AttributeError + pair: exception; AttributeError pair: object; module pair: object; list @@ -1241,7 +1241,7 @@ applies to integral numbers or to custom objects that override the -.. index:: exception: TypeError +.. index:: pair: exception; TypeError In all three cases, if the argument does not have the proper type, a :exc:`TypeError` exception is raised. @@ -1288,7 +1288,7 @@ builtin Python types implement this operator. .. versionadded:: 3.5 .. index:: - exception: ZeroDivisionError + pair: exception; ZeroDivisionError single: division pair: operator; / (slash) pair: operator; // @@ -1377,7 +1377,7 @@ the left or right by the number of bits given by the second argument. This operation can be customized using the special :meth:`__lshift__` and :meth:`__rshift__` methods. -.. index:: exception: ValueError +.. index:: pair: exception; ValueError A right shift by *n* bits is defined as floor division by ``pow(2,n)``. A left shift by *n* bits is defined as multiplication with ``pow(2,n)``. diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index acc3998e09be..7cf096019631 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -398,7 +398,7 @@ The extended form, ``assert expression1, expression2``, is equivalent to :: .. index:: single: __debug__ - exception: AssertionError + pair: exception; AssertionError These equivalences assume that :const:`__debug__` and :exc:`AssertionError` refer to the built-in variables with those names. In the current implementation, the @@ -521,7 +521,7 @@ The :keyword:`!yield` statement single: generator; function single: generator; iterator single: function; generator - exception: StopIteration + pair: exception; StopIteration .. productionlist:: python-grammar yield_stmt: `yield_expression` @@ -731,7 +731,7 @@ The :keyword:`!import` statement pair: name; binding pair: keyword; from pair: keyword; as - exception: ImportError + pair: exception; ImportError single: , (comma); import statement .. productionlist:: python-grammar diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 41016113d257..9a62ae748e07 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -693,7 +693,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('keyword', None) pairindextypes.pop('operator', None) pairindextypes.pop('object', None) - # pairindextypes.pop('exception', None) + pairindextypes.pop('exception', None) # pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) From webhook-mailer at python.org Thu May 4 06:48:53 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 10:48:53 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('statement') (#104162) Message-ID: <mailman.151.1683197333.13550.python-checkins@python.org> https://github.com/python/cpython/commit/55d50d147c953fab37b273bca9ab010f40e067d3 commit: 55d50d147c953fab37b273bca9ab010f40e067d3 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T13:48:45+03:00 summary: GH-97950: Use new-style index directive ('statement') (#104162) files: M Doc/library/exceptions.rst M Doc/library/functions.rst M Doc/library/site.rst M Doc/library/stdtypes.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/controlflow.rst diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index aee1cb5cc6a4..4c84e5f85543 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -4,8 +4,8 @@ Built-in Exceptions =================== .. index:: - statement: try - statement: except + pair: statement; try + pair: statement; except In Python, all exceptions must be instances of a class that derives from :class:`BaseException`. In a :keyword:`try` statement with an :keyword:`except` @@ -14,7 +14,7 @@ classes derived from that class (but not exception classes from which *it* is derived). Two exception classes that are not related via subclassing are never equivalent, even if they have the same name. -.. index:: statement: raise +.. index:: pair: statement; raise The built-in exceptions listed below can be generated by the interpreter or built-in functions. Except where mentioned, they have an "associated value" @@ -175,7 +175,7 @@ The following exceptions are the exceptions that are usually raised. .. exception:: AssertionError - .. index:: statement: assert + .. index:: pair: statement; assert Raised when an :keyword:`assert` statement fails. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 5a022edb75b7..80b7b8b4f4ed 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1986,7 +1986,7 @@ are always available. They are listed here in alphabetical order. .. function:: __import__(name, globals=None, locals=None, fromlist=(), level=0) .. index:: - statement: import + pair: statement; import pair: module; builtins .. note:: diff --git a/Doc/library/site.rst b/Doc/library/site.rst index a4efefd587a6..44f90a3b9e49 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -51,7 +51,7 @@ searched for site-packages; otherwise they will. .. index:: single: # (hash); comment - statement: import + pair: statement; import A path configuration file is a file whose name has the form :file:`{name}.pth` and exists in one of the four directories mentioned above; its contents are diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 2f549f2e97c1..c739485c5564 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -32,8 +32,8 @@ Truth Value Testing =================== .. index:: - statement: if - statement: while + pair: statement; if + pair: statement; while pair: truth; value pair: Boolean; operations single: false @@ -1152,7 +1152,7 @@ accepts integers that meet the value restriction ``0 <= x <= 255``). triple: operations on; list; type pair: subscript; assignment pair: slice; assignment - statement: del + pair: statement; del single: append() (sequence method) single: clear() (sequence method) single: copy() (sequence method) @@ -4418,7 +4418,7 @@ Mapping Types --- :class:`dict` pair: object; dictionary triple: operations on; mapping; types triple: operations on; dictionary; type - statement: del + pair: statement; del builtin: len A :term:`mapping` object maps :term:`hashable` values to arbitrary objects. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 5750d3149c8e..e9c1c493ae42 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -84,7 +84,7 @@ The :keyword:`!if` statement ============================ .. index:: - ! statement: if + ! pair: statement; if pair: keyword; elif pair: keyword; else single: : (colon); compound statement @@ -109,7 +109,7 @@ The :keyword:`!while` statement =============================== .. index:: - ! statement: while + ! pair: statement; while pair: keyword; else pair: loop; statement single: : (colon); compound statement @@ -127,8 +127,8 @@ suite of the :keyword:`!else` clause, if present, is executed and the loop terminates. .. index:: - statement: break - statement: continue + pair: statement; break + pair: statement; continue A :keyword:`break` statement executed in the first suite terminates the loop without executing the :keyword:`!else` clause's suite. A :keyword:`continue` @@ -142,7 +142,7 @@ The :keyword:`!for` statement ============================= .. index:: - ! statement: for + ! pair: statement; for pair: keyword; in pair: keyword; else pair: target; list @@ -167,8 +167,8 @@ the suite in the :keyword:`!else` clause, if present, is executed, and the loop terminates. .. index:: - statement: break - statement: continue + pair: statement; break + pair: statement; continue A :keyword:`break` statement executed in the first suite terminates the loop without executing the :keyword:`!else` clause's suite. A :keyword:`continue` @@ -205,7 +205,7 @@ The :keyword:`!try` statement ============================= .. index:: - ! statement: try + ! pair: statement; try pair: keyword; except pair: keyword; finally pair: keyword; else @@ -388,9 +388,9 @@ cannot appear in an :keyword:`!except*` clause. .. index:: pair: keyword; else - statement: return - statement: break - statement: continue + pair: statement; return + pair: statement; break + pair: statement; continue .. _except_else: @@ -434,9 +434,9 @@ The exception information is not available to the program during execution of the :keyword:`!finally` clause. .. index:: - statement: return - statement: break - statement: continue + pair: statement; return + pair: statement; break + pair: statement; continue When a :keyword:`return`, :keyword:`break` or :keyword:`continue` statement is executed in the :keyword:`try` suite of a :keyword:`!try`...\ :keyword:`!finally` @@ -468,7 +468,7 @@ The :keyword:`!with` statement ============================== .. index:: - ! statement: with + ! pair: statement; with pair: keyword; as single: as; with statement single: , (comma); with statement @@ -585,7 +585,7 @@ The :keyword:`!match` statement =============================== .. index:: - ! statement: match + ! pair: statement; match ! pair: keyword; case ! single: pattern matching pair: keyword; if @@ -1190,7 +1190,7 @@ Function definitions ==================== .. index:: - statement: def + pair: statement; def pair: function; definition pair: function; name pair: name; binding @@ -1364,7 +1364,7 @@ Class definitions .. index:: pair: object; class - statement: class + pair: statement; class pair: class; definition pair: class; name pair: name; binding @@ -1463,7 +1463,7 @@ Coroutines .. versionadded:: 3.5 -.. index:: statement: async def +.. index:: pair: statement; async def .. _`async def`: Coroutine function definition @@ -1497,7 +1497,7 @@ An example of a coroutine function:: ``await`` and ``async`` are now keywords; previously they were only treated as such inside the body of a coroutine function. -.. index:: statement: async for +.. index:: pair: statement; async for .. _`async for`: The :keyword:`!async for` statement @@ -1542,7 +1542,7 @@ It is a :exc:`SyntaxError` to use an ``async for`` statement outside the body of a coroutine function. -.. index:: statement: async with +.. index:: pair: statement; async with .. _`async with`: The :keyword:`!async with` statement diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 18906a005b27..1294d683e268 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -727,7 +727,7 @@ Callable types Modules .. index:: - statement: import + pair: statement; import pair: object; module Modules are a basic organizational unit of Python code, and are created by @@ -1151,7 +1151,7 @@ Internal types single: tb_frame (traceback attribute) single: tb_lineno (traceback attribute) single: tb_lasti (traceback attribute) - statement: try + pair: statement; try Special read-only attributes: :attr:`tb_frame` points to the execution frame of the current level; @@ -1310,7 +1310,7 @@ Basic customization .. index:: single: destructor single: finalizer - statement: del + pair: statement; del Called when the instance is about to be destroyed. This is also called a finalizer or (improperly) a destructor. If a base class has a @@ -2796,7 +2796,7 @@ execution of the block of code. Context managers are normally invoked using the used by directly invoking their methods. .. index:: - statement: with + pair: statement; with single: context manager Typical uses of context managers include saving and restoring various kinds of diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 7cf096019631..ca1aa744389b 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -376,7 +376,7 @@ The :keyword:`!assert` statement ================================ .. index:: - ! statement: assert + ! pair: statement; assert pair: debugging; assertions single: , (comma); expression list @@ -419,7 +419,7 @@ The :keyword:`!pass` statement ============================== .. index:: - statement: pass + pair: statement; pass pair: null; operation pair: null; operation @@ -441,7 +441,7 @@ The :keyword:`!del` statement ============================= .. index:: - ! statement: del + ! pair: statement; del pair: deletion; target triple: deletion; target; list @@ -454,7 +454,7 @@ Rather than spelling it out in full details, here are some hints. Deletion of a target list recursively deletes each target, from left to right. .. index:: - statement: global + pair: statement; global pair: unbinding; name Deletion of a name removes the binding of that name from the local or global @@ -480,7 +480,7 @@ The :keyword:`!return` statement ================================ .. index:: - ! statement: return + ! pair: statement; return pair: function; definition pair: class; definition @@ -517,7 +517,7 @@ The :keyword:`!yield` statement =============================== .. index:: - statement: yield + pair: statement; yield single: generator; function single: generator; iterator single: function; generator @@ -553,7 +553,7 @@ The :keyword:`!raise` statement =============================== .. index:: - ! statement: raise + ! pair: statement; raise single: exception pair: raising; exception single: __traceback__ (exception attribute) @@ -667,9 +667,9 @@ The :keyword:`!break` statement =============================== .. index:: - ! statement: break - statement: for - statement: while + ! pair: statement; break + pair: statement; for + pair: statement; while pair: loop; statement .. productionlist:: python-grammar @@ -701,9 +701,9 @@ The :keyword:`!continue` statement ================================== .. index:: - ! statement: continue - statement: for - statement: while + ! pair: statement; continue + pair: statement; for + pair: statement; while pair: loop; statement pair: keyword; finally @@ -726,7 +726,7 @@ The :keyword:`!import` statement ================================ .. index:: - ! statement: import + ! pair: statement; import single: module; importing pair: name; binding pair: keyword; from @@ -942,7 +942,7 @@ The :keyword:`!global` statement ================================ .. index:: - ! statement: global + ! pair: statement; global triple: global; name; binding single: , (comma); identifier list @@ -988,7 +988,7 @@ call. The same applies to the :func:`eval` and :func:`compile` functions. The :keyword:`!nonlocal` statement ================================== -.. index:: statement: nonlocal +.. index:: pair: statement; nonlocal single: , (comma); identifier list .. productionlist:: python-grammar diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 9a62ae748e07..8fc44cab4445 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -694,7 +694,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('operator', None) pairindextypes.pop('object', None) pairindextypes.pop('exception', None) - # pairindextypes.pop('statement', None) + pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 52db51e84cd5..c9b3d982c31c 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -46,7 +46,7 @@ details see :ref:`tut-match`. ========================== .. index:: - statement: for + pair: statement; for The :keyword:`for` statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression From webhook-mailer at python.org Thu May 4 06:49:05 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 10:49:05 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('exception') (GH-104160) (#104161) Message-ID: <mailman.152.1683197346.13550.python-checkins@python.org> https://github.com/python/cpython/commit/99e6314d938c43f6071d850264218173655c43ff commit: 99e6314d938c43f6071d850264218173655c43ff branch: 3.11 author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T13:48:57+03:00 summary: [3.11] GH-97950: Use new-style index directive ('exception') (GH-104160) (#104161) files: M Doc/reference/expressions.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index ba0f8d87ba9e..f669d9718a49 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -71,7 +71,7 @@ An identifier occurring as an atom is a name. See section :ref:`identifiers` for lexical definition and section :ref:`naming` for documentation of naming and binding. -.. index:: exception: NameError +.. index:: pair: exception; NameError When the name is bound to an object, evaluation of the atom yields that object. When a name is not bound, an attempt to evaluate it raises a :exc:`NameError` @@ -534,7 +534,7 @@ be used to control the execution of a generator function. Note that calling any of the generator methods below when the generator is already executing raises a :exc:`ValueError` exception. -.. index:: exception: StopIteration +.. index:: pair: exception; StopIteration .. method:: generator.__next__() @@ -584,7 +584,7 @@ is already executing raises a :exc:`ValueError` exception. :attr:`~BaseException.__traceback__` attribute stored in *value* may be cleared. -.. index:: exception: GeneratorExit +.. index:: pair: exception; GeneratorExit .. method:: generator.close() @@ -706,7 +706,7 @@ This subsection describes the methods of an asynchronous generator iterator, which are used to control the execution of a generator function. -.. index:: exception: StopAsyncIteration +.. index:: pair: exception; StopAsyncIteration .. coroutinemethod:: agen.__anext__() @@ -752,7 +752,7 @@ which are used to control the execution of a generator function. raises a different exception, then when the awaitable is run that exception propagates to the caller of the awaitable. -.. index:: exception: GeneratorExit +.. index:: pair: exception; GeneratorExit .. coroutinemethod:: agen.aclose() @@ -799,7 +799,7 @@ An attribute reference is a primary followed by a period and a name: attributeref: `primary` "." `identifier` .. index:: - exception: AttributeError + pair: exception; AttributeError pair: object; module pair: object; list @@ -1230,7 +1230,7 @@ applies to integral numbers or to custom objects that override the -.. index:: exception: TypeError +.. index:: pair: exception; TypeError In all three cases, if the argument does not have the proper type, a :exc:`TypeError` exception is raised. @@ -1277,7 +1277,7 @@ builtin Python types implement this operator. .. versionadded:: 3.5 .. index:: - exception: ZeroDivisionError + pair: exception; ZeroDivisionError single: division pair: operator; / (slash) pair: operator; // @@ -1366,7 +1366,7 @@ the left or right by the number of bits given by the second argument. This operation can be customized using the special :meth:`__lshift__` and :meth:`__rshift__` methods. -.. index:: exception: ValueError +.. index:: pair: exception; ValueError A right shift by *n* bits is defined as floor division by ``pow(2,n)``. A left shift by *n* bits is defined as multiplication with ``pow(2,n)``. diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index acc3998e09be..7cf096019631 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -398,7 +398,7 @@ The extended form, ``assert expression1, expression2``, is equivalent to :: .. index:: single: __debug__ - exception: AssertionError + pair: exception; AssertionError These equivalences assume that :const:`__debug__` and :exc:`AssertionError` refer to the built-in variables with those names. In the current implementation, the @@ -521,7 +521,7 @@ The :keyword:`!yield` statement single: generator; function single: generator; iterator single: function; generator - exception: StopIteration + pair: exception; StopIteration .. productionlist:: python-grammar yield_stmt: `yield_expression` @@ -731,7 +731,7 @@ The :keyword:`!import` statement pair: name; binding pair: keyword; from pair: keyword; as - exception: ImportError + pair: exception; ImportError single: , (comma); import statement .. productionlist:: python-grammar diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 01c1c5cd7784..469b43254090 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -698,7 +698,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('keyword', None) pairindextypes.pop('operator', None) pairindextypes.pop('object', None) - # pairindextypes.pop('exception', None) + pairindextypes.pop('exception', None) # pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) From webhook-mailer at python.org Thu May 4 06:57:22 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 10:57:22 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('statement') (GH-104162) (#104163) Message-ID: <mailman.153.1683197844.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6a970ae66669153c62a128c0854ea364e29b69a0 commit: 6a970ae66669153c62a128c0854ea364e29b69a0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T13:57:14+03:00 summary: [3.11] GH-97950: Use new-style index directive ('statement') (GH-104162) (#104163) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/library/exceptions.rst M Doc/library/functions.rst M Doc/library/site.rst M Doc/library/stdtypes.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/simple_stmts.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/controlflow.rst diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index aee1cb5cc6a4..4c84e5f85543 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -4,8 +4,8 @@ Built-in Exceptions =================== .. index:: - statement: try - statement: except + pair: statement; try + pair: statement; except In Python, all exceptions must be instances of a class that derives from :class:`BaseException`. In a :keyword:`try` statement with an :keyword:`except` @@ -14,7 +14,7 @@ classes derived from that class (but not exception classes from which *it* is derived). Two exception classes that are not related via subclassing are never equivalent, even if they have the same name. -.. index:: statement: raise +.. index:: pair: statement; raise The built-in exceptions listed below can be generated by the interpreter or built-in functions. Except where mentioned, they have an "associated value" @@ -175,7 +175,7 @@ The following exceptions are the exceptions that are usually raised. .. exception:: AssertionError - .. index:: statement: assert + .. index:: pair: statement; assert Raised when an :keyword:`assert` statement fails. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index c5bdfc21e183..1a7311911ba7 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1978,7 +1978,7 @@ are always available. They are listed here in alphabetical order. .. function:: __import__(name, globals=None, locals=None, fromlist=(), level=0) .. index:: - statement: import + pair: statement; import pair: module; builtins .. note:: diff --git a/Doc/library/site.rst b/Doc/library/site.rst index 34b38f4d56f3..5b70dbced13e 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -51,7 +51,7 @@ searched for site-packages; otherwise they will. .. index:: single: # (hash); comment - statement: import + pair: statement; import A path configuration file is a file whose name has the form :file:`{name}.pth` and exists in one of the four directories mentioned above; its contents are diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 960959073c4b..d57581f1d535 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -32,8 +32,8 @@ Truth Value Testing =================== .. index:: - statement: if - statement: while + pair: statement; if + pair: statement; while pair: truth; value pair: Boolean; operations single: false @@ -1113,7 +1113,7 @@ accepts integers that meet the value restriction ``0 <= x <= 255``). triple: operations on; list; type pair: subscript; assignment pair: slice; assignment - statement: del + pair: statement; del single: append() (sequence method) single: clear() (sequence method) single: copy() (sequence method) @@ -4371,7 +4371,7 @@ Mapping Types --- :class:`dict` pair: object; dictionary triple: operations on; mapping; types triple: operations on; dictionary; type - statement: del + pair: statement; del builtin: len A :term:`mapping` object maps :term:`hashable` values to arbitrary objects. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 4578e662ada6..cd448d213487 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -84,7 +84,7 @@ The :keyword:`!if` statement ============================ .. index:: - ! statement: if + ! pair: statement; if pair: keyword; elif pair: keyword; else single: : (colon); compound statement @@ -109,7 +109,7 @@ The :keyword:`!while` statement =============================== .. index:: - ! statement: while + ! pair: statement; while pair: keyword; else pair: loop; statement single: : (colon); compound statement @@ -127,8 +127,8 @@ suite of the :keyword:`!else` clause, if present, is executed and the loop terminates. .. index:: - statement: break - statement: continue + pair: statement; break + pair: statement; continue A :keyword:`break` statement executed in the first suite terminates the loop without executing the :keyword:`!else` clause's suite. A :keyword:`continue` @@ -142,7 +142,7 @@ The :keyword:`!for` statement ============================= .. index:: - ! statement: for + ! pair: statement; for pair: keyword; in pair: keyword; else pair: target; list @@ -167,8 +167,8 @@ the suite in the :keyword:`!else` clause, if present, is executed, and the loop terminates. .. index:: - statement: break - statement: continue + pair: statement; break + pair: statement; continue A :keyword:`break` statement executed in the first suite terminates the loop without executing the :keyword:`!else` clause's suite. A :keyword:`continue` @@ -205,7 +205,7 @@ The :keyword:`!try` statement ============================= .. index:: - ! statement: try + ! pair: statement; try pair: keyword; except pair: keyword; finally pair: keyword; else @@ -390,9 +390,9 @@ cannot appear in an :keyword:`!except*` clause. .. index:: pair: keyword; else - statement: return - statement: break - statement: continue + pair: statement; return + pair: statement; break + pair: statement; continue .. _except_else: @@ -436,9 +436,9 @@ The exception information is not available to the program during execution of the :keyword:`!finally` clause. .. index:: - statement: return - statement: break - statement: continue + pair: statement; return + pair: statement; break + pair: statement; continue When a :keyword:`return`, :keyword:`break` or :keyword:`continue` statement is executed in the :keyword:`try` suite of a :keyword:`!try`...\ :keyword:`!finally` @@ -470,7 +470,7 @@ The :keyword:`!with` statement ============================== .. index:: - ! statement: with + ! pair: statement; with pair: keyword; as single: as; with statement single: , (comma); with statement @@ -587,7 +587,7 @@ The :keyword:`!match` statement =============================== .. index:: - ! statement: match + ! pair: statement; match ! pair: keyword; case ! single: pattern matching pair: keyword; if @@ -1192,7 +1192,7 @@ Function definitions ==================== .. index:: - statement: def + pair: statement; def pair: function; definition pair: function; name pair: name; binding @@ -1366,7 +1366,7 @@ Class definitions .. index:: pair: object; class - statement: class + pair: statement; class pair: class; definition pair: class; name pair: name; binding @@ -1465,7 +1465,7 @@ Coroutines .. versionadded:: 3.5 -.. index:: statement: async def +.. index:: pair: statement; async def .. _`async def`: Coroutine function definition @@ -1499,7 +1499,7 @@ An example of a coroutine function:: ``await`` and ``async`` are now keywords; previously they were only treated as such inside the body of a coroutine function. -.. index:: statement: async for +.. index:: pair: statement; async for .. _`async for`: The :keyword:`!async for` statement @@ -1544,7 +1544,7 @@ It is a :exc:`SyntaxError` to use an ``async for`` statement outside the body of a coroutine function. -.. index:: statement: async with +.. index:: pair: statement; async with .. _`async with`: The :keyword:`!async with` statement diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 3f3a37dacc15..73eb402b7166 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -727,7 +727,7 @@ Callable types Modules .. index:: - statement: import + pair: statement; import pair: object; module Modules are a basic organizational unit of Python code, and are created by @@ -1150,7 +1150,7 @@ Internal types single: tb_frame (traceback attribute) single: tb_lineno (traceback attribute) single: tb_lasti (traceback attribute) - statement: try + pair: statement; try Special read-only attributes: :attr:`tb_frame` points to the execution frame of the current level; @@ -1309,7 +1309,7 @@ Basic customization .. index:: single: destructor single: finalizer - statement: del + pair: statement; del Called when the instance is about to be destroyed. This is also called a finalizer or (improperly) a destructor. If a base class has a @@ -2791,7 +2791,7 @@ execution of the block of code. Context managers are normally invoked using the used by directly invoking their methods. .. index:: - statement: with + pair: statement; with single: context manager Typical uses of context managers include saving and restoring various kinds of diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 7cf096019631..ca1aa744389b 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -376,7 +376,7 @@ The :keyword:`!assert` statement ================================ .. index:: - ! statement: assert + ! pair: statement; assert pair: debugging; assertions single: , (comma); expression list @@ -419,7 +419,7 @@ The :keyword:`!pass` statement ============================== .. index:: - statement: pass + pair: statement; pass pair: null; operation pair: null; operation @@ -441,7 +441,7 @@ The :keyword:`!del` statement ============================= .. index:: - ! statement: del + ! pair: statement; del pair: deletion; target triple: deletion; target; list @@ -454,7 +454,7 @@ Rather than spelling it out in full details, here are some hints. Deletion of a target list recursively deletes each target, from left to right. .. index:: - statement: global + pair: statement; global pair: unbinding; name Deletion of a name removes the binding of that name from the local or global @@ -480,7 +480,7 @@ The :keyword:`!return` statement ================================ .. index:: - ! statement: return + ! pair: statement; return pair: function; definition pair: class; definition @@ -517,7 +517,7 @@ The :keyword:`!yield` statement =============================== .. index:: - statement: yield + pair: statement; yield single: generator; function single: generator; iterator single: function; generator @@ -553,7 +553,7 @@ The :keyword:`!raise` statement =============================== .. index:: - ! statement: raise + ! pair: statement; raise single: exception pair: raising; exception single: __traceback__ (exception attribute) @@ -667,9 +667,9 @@ The :keyword:`!break` statement =============================== .. index:: - ! statement: break - statement: for - statement: while + ! pair: statement; break + pair: statement; for + pair: statement; while pair: loop; statement .. productionlist:: python-grammar @@ -701,9 +701,9 @@ The :keyword:`!continue` statement ================================== .. index:: - ! statement: continue - statement: for - statement: while + ! pair: statement; continue + pair: statement; for + pair: statement; while pair: loop; statement pair: keyword; finally @@ -726,7 +726,7 @@ The :keyword:`!import` statement ================================ .. index:: - ! statement: import + ! pair: statement; import single: module; importing pair: name; binding pair: keyword; from @@ -942,7 +942,7 @@ The :keyword:`!global` statement ================================ .. index:: - ! statement: global + ! pair: statement; global triple: global; name; binding single: , (comma); identifier list @@ -988,7 +988,7 @@ call. The same applies to the :func:`eval` and :func:`compile` functions. The :keyword:`!nonlocal` statement ================================== -.. index:: statement: nonlocal +.. index:: pair: statement; nonlocal single: , (comma); identifier list .. productionlist:: python-grammar diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 469b43254090..f9b2bfdc639a 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -699,7 +699,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('operator', None) pairindextypes.pop('object', None) pairindextypes.pop('exception', None) - # pairindextypes.pop('statement', None) + pairindextypes.pop('statement', None) # pairindextypes.pop('builtin', None) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 52db51e84cd5..c9b3d982c31c 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -46,7 +46,7 @@ details see :ref:`tut-match`. ========================== .. index:: - statement: for + pair: statement; for The :keyword:`for` statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression From webhook-mailer at python.org Thu May 4 08:26:30 2023 From: webhook-mailer at python.org (lysnikolaou) Date: Thu, 04 May 2023 12:26:30 -0000 Subject: [Python-checkins] gh-97556: Raise null bytes syntax error upon null in multiline string (GH-104136) Message-ID: <mailman.154.1683203192.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ef0df5284f929719b2ef3955b1b569ade0a5193c commit: ef0df5284f929719b2ef3955b1b569ade0a5193c branch: main author: Lysandros Nikolaou <lisandrosnik at gmail.com> committer: lysnikolaou <lisandrosnik at gmail.com> date: 2023-05-04T14:26:23+02:00 summary: gh-97556: Raise null bytes syntax error upon null in multiline string (GH-104136) files: M Lib/test/test_cmd_line_script.py M Parser/tokenizer.c diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index d98e23855e0c..8bf299382e9c 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -669,6 +669,19 @@ def test_syntaxerror_null_bytes(self): ], ) + def test_syntaxerror_null_bytes_in_multiline_string(self): + scripts = ["\n'''\nmultilinestring\0\n'''", "\nf'''\nmultilinestring\0\n'''"] # Both normal and f-strings + with os_helper.temp_dir() as script_dir: + for script in scripts: + script_name = _make_test_script(script_dir, 'script', script) + _, _, stderr = assert_python_failure(script_name) + self.assertEqual( + stderr.splitlines()[-2:], + [ b" multilinestring", + b'SyntaxError: source code cannot contain null bytes' + ] + ) + def test_consistent_sys_path_for_direct_execution(self): # This test case ensures that the following all give the same # sys.path configuration: diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index d2f9fee110eb..7c07d2011fda 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -2301,8 +2301,12 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t /* Get rest of string */ while (end_quote_size != quote_size) { c = tok_nextc(tok); - if (tok->done == E_DECODE) + if (tok->done == E_ERROR) { + return MAKE_TOKEN(ERRORTOKEN); + } + if (tok->done == E_DECODE) { break; + } if (c == EOF || (quote_size == 1 && c == '\n')) { assert(tok->multi_line_start != NULL); // shift the tok_state's location into @@ -2554,6 +2558,9 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct while (end_quote_size != current_tok->f_string_quote_size) { int c = tok_nextc(tok); + if (tok->done == E_ERROR) { + return MAKE_TOKEN(ERRORTOKEN); + } if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) { if (tok->decoding_erred) { return MAKE_TOKEN(ERRORTOKEN); From webhook-mailer at python.org Thu May 4 09:03:32 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 04 May 2023 13:03:32 -0000 Subject: [Python-checkins] gh-103092: Port _ctypes.COMError to heap type (#104020) Message-ID: <mailman.155.1683205413.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4f524da4843fb71b3ba43d89cd0265e4ecb29798 commit: 4f524da4843fb71b3ba43d89cd0265e4ecb29798 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-04T13:03:24Z summary: gh-103092: Port _ctypes.COMError to heap type (#104020) files: M Modules/_ctypes/_ctypes.c M Modules/_ctypes/callproc.c M Modules/_ctypes/ctypes.h diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index c7ed6bd2229c..f6cda45eaeac 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -139,10 +139,6 @@ static PyTypeObject Simple_Type; strong reference to _ctypes._unpickle() function */ static PyObject *_unpickle; -#ifdef MS_WIN32 -PyObject *ComError; // Borrowed reference to: &PyComError_Type -#endif - /****************************************************************/ @@ -5480,46 +5476,38 @@ comerror_init(PyObject *self, PyObject *args, PyObject *kwds) return 0; } -static PyTypeObject PyComError_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ctypes.COMError", /* tp_name */ - sizeof(PyBaseExceptionObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* 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, /* tp_flags */ - PyDoc_STR(comerror_doc), /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* 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 */ - (initproc)comerror_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ +static int +comerror_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +comerror_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot comerror_slots[] = { + {Py_tp_doc, (void *)PyDoc_STR(comerror_doc)}, + {Py_tp_init, comerror_init}, + {Py_tp_traverse, comerror_traverse}, + {Py_tp_dealloc, comerror_dealloc}, + {0, NULL}, }; + +static PyType_Spec comerror_spec = { + .name = "_ctypes.COMError", + .basicsize = sizeof(PyBaseExceptionObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = comerror_slots, +}; + #endif // MS_WIN32 static PyObject * @@ -5661,8 +5649,9 @@ _ctypes_add_types(PyObject *mod) } \ } while (0) -#define CREATE_TYPE(MOD, TP, SPEC) do { \ - PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, NULL); \ +#define CREATE_TYPE(MOD, TP, SPEC, BASE) do { \ + PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, \ + (PyObject *)BASE); \ if (type == NULL) { \ return -1; \ } \ @@ -5675,8 +5664,8 @@ _ctypes_add_types(PyObject *mod) ob_type is the metatype (the 'type'), defaults to PyType_Type, tp_base is the base type, defaults to 'object' aka PyBaseObject_Type. */ - CREATE_TYPE(mod, st->PyCArg_Type, &carg_spec); - CREATE_TYPE(mod, st->PyCThunk_Type, &cthunk_spec); + CREATE_TYPE(mod, st->PyCArg_Type, &carg_spec, NULL); + CREATE_TYPE(mod, st->PyCThunk_Type, &cthunk_spec, NULL); TYPE_READY(&PyCData_Type); /* StgDict is derived from PyDict_Type */ TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type); @@ -5709,18 +5698,18 @@ _ctypes_add_types(PyObject *mod) * Simple classes */ - CREATE_TYPE(mod, st->PyCField_Type, &cfield_spec); + CREATE_TYPE(mod, st->PyCField_Type, &cfield_spec, NULL); /************************************************* * * Other stuff */ - CREATE_TYPE(mod, st->DictRemover_Type, &dictremover_spec); - CREATE_TYPE(mod, st->StructParam_Type, &structparam_spec); + CREATE_TYPE(mod, st->DictRemover_Type, &dictremover_spec, NULL); + CREATE_TYPE(mod, st->StructParam_Type, &structparam_spec, NULL); #ifdef MS_WIN32 - TYPE_READY_BASE(&PyComError_Type, (PyTypeObject*)PyExc_Exception); + CREATE_TYPE(mod, st->PyComError_Type, &comerror_spec, PyExc_Exception); #endif #undef TYPE_READY @@ -5750,7 +5739,8 @@ _ctypes_add_objects(PyObject *mod) MOD_ADD("_pointer_type_cache", Py_NewRef(_ctypes_ptrtype_cache)); #ifdef MS_WIN32 - MOD_ADD("COMError", Py_NewRef(ComError)); + ctypes_state *st = GLOBAL_STATE(); + MOD_ADD("COMError", Py_NewRef(st->PyComError_Type)); MOD_ADD("FUNCFLAG_HRESULT", PyLong_FromLong(FUNCFLAG_HRESULT)); MOD_ADD("FUNCFLAG_STDCALL", PyLong_FromLong(FUNCFLAG_STDCALL)); #endif @@ -5807,9 +5797,6 @@ _ctypes_mod_exec(PyObject *mod) if (_ctypes_add_types(mod) < 0) { return -1; } -#ifdef MS_WIN32 - ComError = (PyObject*)&PyComError_Type; -#endif if (_ctypes_add_objects(mod) < 0) { return -1; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index f10cf58216ac..d2fe525dd4d3 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1115,7 +1115,8 @@ GetComError(HRESULT errcode, GUID *riid, IUnknown *pIunk) descr, source, helpfile, helpcontext, progid); if (obj) { - PyErr_SetObject(ComError, obj); + ctypes_state *st = GLOBAL_STATE(); + PyErr_SetObject((PyObject *)st->PyComError_Type, obj); Py_DECREF(obj); } LocalFree(text); diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 252d9da7dbb5..8891a0a741de 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -37,6 +37,9 @@ typedef struct { PyTypeObject *PyCArg_Type; PyTypeObject *PyCField_Type; PyTypeObject *PyCThunk_Type; +#ifdef MS_WIN32 + PyTypeObject *PyComError_Type; +#endif PyTypeObject *StructParam_Type; } ctypes_state; @@ -392,10 +395,6 @@ extern int _ctypes_simple_instance(PyObject *obj); extern PyObject *_ctypes_ptrtype_cache; PyObject *_ctypes_get_errobj(int **pspace); -#ifdef MS_WIN32 -extern PyObject *ComError; -#endif - #ifdef USING_MALLOC_CLOSURE_DOT_C void Py_ffi_closure_free(void *p); void *Py_ffi_closure_alloc(size_t size, void** codeloc); From webhook-mailer at python.org Thu May 4 09:04:01 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 04 May 2023 13:04:01 -0000 Subject: [Python-checkins] =?utf-8?b?Rml4IHR5cG8gImludm9sdmluIiDihpIgImlu?= =?utf-8?b?dm9sdmluZyIgKCMxMDQxNjYp?= Message-ID: <mailman.156.1683205442.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e2ef5015d1b6cb56f1a7988583f2fb8c0e6d65fc commit: e2ef5015d1b6cb56f1a7988583f2fb8c0e6d65fc branch: main author: Christopher Chavez <chrischavez at gmx.us> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-04T13:03:52Z summary: Fix typo "involvin" ? "involving" (#104166) files: M Lib/test/test_idle.py M Lib/test/test_tix.py diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py index b94b18a541a7..90cff9002b75 100644 --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -3,7 +3,7 @@ from test.support import check_sanitizer if check_sanitizer(address=True, memory=True): - raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") + raise unittest.SkipTest("Tests involving libX11 can SEGFAULT on ASAN/MSAN builds") # Skip test_idle if _tkinter wasn't built, if tkinter is missing, # if tcl/tk is not the 8.5+ needed for ttk widgets, diff --git a/Lib/test/test_tix.py b/Lib/test/test_tix.py index 454baeb38a93..d0d2a164ad2c 100644 --- a/Lib/test/test_tix.py +++ b/Lib/test/test_tix.py @@ -5,7 +5,7 @@ from test.support import check_sanitizer if check_sanitizer(address=True, memory=True): - raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") + raise unittest.SkipTest("Tests involving libX11 can SEGFAULT on ASAN/MSAN builds") # Skip this test if the _tkinter module wasn't built. From webhook-mailer at python.org Thu May 4 10:15:33 2023 From: webhook-mailer at python.org (pablogsal) Date: Thu, 04 May 2023 14:15:33 -0000 Subject: [Python-checkins] gh-104169: Ensure the tokenizer doesn't overwrite previous errors (#104170) Message-ID: <mailman.157.1683209735.13550.python-checkins@python.org> https://github.com/python/cpython/commit/eba64d2afb4c429e80d863dc0dd7808bdbef30d3 commit: eba64d2afb4c429e80d863dc0dd7808bdbef30d3 branch: main author: Pablo Galindo Salgado <Pablogsal at gmail.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-04T15:15:26+01:00 summary: gh-104169: Ensure the tokenizer doesn't overwrite previous errors (#104170) files: M Parser/tokenizer.c diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 7c07d2011fda..52d0d9a534cb 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1277,6 +1277,12 @@ _syntaxerror_range(struct tok_state *tok, const char *format, int col_offset, int end_col_offset, va_list vargs) { + // In release builds, we don't want to overwrite a previous error, but in debug builds we + // want to fail if we are not doing it so we can fix it. + assert(tok->done != E_ERROR); + if (tok->done == E_ERROR) { + return ERRORTOKEN; + } PyObject *errmsg, *errtext, *args; errmsg = PyUnicode_FromFormatV(format, vargs); if (!errmsg) { From webhook-mailer at python.org Thu May 4 10:21:09 2023 From: webhook-mailer at python.org (vstinner) Date: Thu, 04 May 2023 14:21:09 -0000 Subject: [Python-checkins] gh-103323: Remove PyRuntimeState_GetThreadState() (#104171) Message-ID: <mailman.158.1683210070.13550.python-checkins@python.org> https://github.com/python/cpython/commit/45398ad51220b63b8df08fb5551c6b736205daed commit: 45398ad51220b63b8df08fb5551c6b736205daed branch: main author: Victor Stinner <vstinner at python.org> committer: vstinner <vstinner at python.org> date: 2023-05-04T16:21:01+02:00 summary: gh-103323: Remove PyRuntimeState_GetThreadState() (#104171) This function no longer makes sense, since its runtime parameter is no longer used. Use directly _PyThreadState_GET() and _PyInterpreterState_GET() instead. files: M Include/internal/pycore_pystate.h M Python/ceval_gil.c M Python/pylifecycle.c M Python/pystate.c M Python/sysmodule.c diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 180ea676bc22..daa40cf4bcd8 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -68,7 +68,7 @@ _Py_ThreadCanHandlePendingCalls(void) } -/* Variable and macro for in-line access to current thread +/* Variable and static inline functions for in-line access to current thread and interpreter state */ #if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE) @@ -93,12 +93,6 @@ _PyThreadState_GET(void) #endif } -static inline PyThreadState* -_PyRuntimeState_GetThreadState(_PyRuntimeState *Py_UNUSED(runtime)) -{ - return _PyThreadState_GET(); -} - static inline void _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) @@ -118,7 +112,7 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) /* Get the current interpreter state. - The macro is unsafe: it does not check for error and it can return NULL. + The function is unsafe: it does not check for error and it can return NULL. The caller must hold the GIL. diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 29796be4b80e..4d501c896617 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -546,8 +546,7 @@ _PyEval_Fini(void) void PyEval_AcquireLock(void) { - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + PyThreadState *tstate = _PyThreadState_GET(); _Py_EnsureTstateNotNULL(tstate); take_gil(tstate); @@ -557,7 +556,7 @@ void PyEval_ReleaseLock(void) { _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + PyThreadState *tstate = _PyThreadState_GET(); /* This function must succeed when the current thread state is NULL. We therefore avoid PyThreadState_Get() which dumps a fatal error in debug mode. */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index b9add89b9c6c..97957d3f17e6 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1303,8 +1303,7 @@ _Py_InitializeMain(void) if (_PyStatus_EXCEPTION(status)) { return status; } - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + PyThreadState *tstate = _PyThreadState_GET(); return pyinit_main(tstate); } @@ -1755,7 +1754,7 @@ Py_FinalizeEx(void) } /* Get current thread state and interpreter pointer */ - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + PyThreadState *tstate = _PyThreadState_GET(); // XXX assert(_Py_IsMainInterpreter(tstate->interp)); // XXX assert(_Py_IsMainThread()); @@ -2800,7 +2799,7 @@ fatal_error(int fd, int header, const char *prefix, const char *msg, tss_tstate != tstate if the current Python thread does not hold the GIL. */ - PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); + PyThreadState *tstate = _PyThreadState_GET(); PyInterpreterState *interp = NULL; PyThreadState *tss_tstate = PyGILState_GetThisThreadState(); if (tstate != NULL) { diff --git a/Python/pystate.c b/Python/pystate.c index f103a059f0f3..f09d37657f9c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1809,7 +1809,7 @@ int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) { _PyRuntimeState *runtime = &_PyRuntime; - PyInterpreterState *interp = _PyRuntimeState_GetThreadState(runtime)->interp; + PyInterpreterState *interp = _PyInterpreterState_GET(); /* Although the GIL is held, a few C API functions can be called * without the GIL held, and in particular some that create and diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 781588b0df4e..894a3e8a98fd 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -365,7 +365,7 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData) _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate; if (runtime->initialized) { - tstate = _PyRuntimeState_GetThreadState(runtime); + tstate = _PyThreadState_GET(); } else { tstate = NULL; From webhook-mailer at python.org Thu May 4 10:38:45 2023 From: webhook-mailer at python.org (vstinner) Date: Thu, 04 May 2023 14:38:45 -0000 Subject: [Python-checkins] gh-102795: Fix use of poll in test_epoll's test_control_and_wait (#102796) Message-ID: <mailman.159.1683211125.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c9ecd3ee75b472bb0a7538e0288c5cfea146da83 commit: c9ecd3ee75b472bb0a7538e0288c5cfea146da83 branch: main author: Kevin Krakauer <kevinGC at users.noreply.github.com> committer: vstinner <vstinner at python.org> date: 2023-05-04T14:38:20Z summary: gh-102795: Fix use of poll in test_epoll's test_control_and_wait (#102796) This test can fail unnecessarily. In the test we wait for events on two file descriptors. This is done in a single call to select.epoll's poll() function. However, it is valid for the OS to return only one event via poll() and the next via a subsequent call to poll(). This rarely happens, but it can cause the test to fail despite properly functioning polling. Instead, we poll a second time when necessary. files: A Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst M Lib/test/test_epoll.py diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py index b623852f9eb4..c94946a6ae6b 100644 --- a/Lib/test/test_epoll.py +++ b/Lib/test/test_epoll.py @@ -27,6 +27,7 @@ import socket import time import unittest +from test import support if not hasattr(select, "epoll"): raise unittest.SkipTest("test works only on Linux 2.6") @@ -186,10 +187,16 @@ def test_control_and_wait(self): client.sendall(b"Hello!") server.sendall(b"world!!!") - now = time.monotonic() - events = ep.poll(1.0, 4) - then = time.monotonic() - self.assertFalse(then - now > 0.01) + # we might receive events one at a time, necessitating multiple calls to + # poll + events = [] + for _ in support.busy_retry(support.SHORT_TIMEOUT): + now = time.monotonic() + events += ep.poll(1.0, 4) + then = time.monotonic() + self.assertFalse(then - now > 0.01) + if len(events) >= 2: + break expected = [(client.fileno(), select.EPOLLIN | select.EPOLLOUT), (server.fileno(), select.EPOLLIN | select.EPOLLOUT)] diff --git a/Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst b/Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst new file mode 100644 index 000000000000..fe2afff91ece --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst @@ -0,0 +1 @@ +fix use of poll in test_epoll's test_control_and_wait From webhook-mailer at python.org Thu May 4 10:50:46 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 04 May 2023 14:50:46 -0000 Subject: [Python-checkins] gh-104066: Improve performance of hasattr for module objects (#104063) Message-ID: <mailman.160.1683211847.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fdcb49c36b2ed8347d8d9f2dcd7052cc90207beb commit: fdcb49c36b2ed8347d8d9f2dcd7052cc90207beb branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: carljm <carl at oddbird.net> date: 2023-05-04T08:50:26-06:00 summary: gh-104066: Improve performance of hasattr for module objects (#104063) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst M Include/internal/pycore_moduleobject.h M Objects/moduleobject.c M Objects/object.c diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h index 76361b8dff11..15a1bcb6ae51 100644 --- a/Include/internal/pycore_moduleobject.h +++ b/Include/internal/pycore_moduleobject.h @@ -36,6 +36,9 @@ static inline PyObject* _PyModule_GetDict(PyObject *mod) { return dict; } +PyObject* _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress); +PyObject* _Py_module_getattro(PyModuleObject *m, PyObject *name); + #ifdef __cplusplus } #endif diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst new file mode 100644 index 000000000000..97e0c01689cb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst @@ -0,0 +1,2 @@ +Improve the performance of :func:`hasattr` for module objects with a missing +attribute. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index a0be19a3ca8a..ffcd90ed122e 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -702,7 +702,11 @@ int _PyModuleSpec_IsInitializing(PyObject *spec) { if (spec != NULL) { - PyObject *value = PyObject_GetAttr(spec, &_Py_ID(_initializing)); + PyObject *value; + int ok = _PyObject_LookupAttr(spec, &_Py_ID(_initializing), &value); + if (ok == 0) { + return 0; + } if (value != NULL) { int initializing = PyObject_IsTrue(value); Py_DECREF(value); @@ -738,19 +742,37 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name) return is_uninitialized; } -static PyObject* -module_getattro(PyModuleObject *m, PyObject *name) +PyObject* +_Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress) { + // When suppress=1, this function suppresses AttributeError. PyObject *attr, *mod_name, *getattr; - attr = PyObject_GenericGetAttr((PyObject *)m, name); - if (attr || !PyErr_ExceptionMatches(PyExc_AttributeError)) { + attr = _PyObject_GenericGetAttrWithDict((PyObject *)m, name, NULL, suppress); + if (attr) { return attr; } - PyErr_Clear(); + if (suppress == 1) { + if (PyErr_Occurred()) { + // pass up non-AttributeError exception + return NULL; + } + } + else { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + // pass up non-AttributeError exception + return NULL; + } + PyErr_Clear(); + } assert(m->md_dict != NULL); getattr = PyDict_GetItemWithError(m->md_dict, &_Py_ID(__getattr__)); if (getattr) { - return PyObject_CallOneArg(getattr, name); + PyObject *result = PyObject_CallOneArg(getattr, name); + if (result == NULL && suppress == 1 && PyErr_ExceptionMatches(PyExc_AttributeError)) { + // suppress AttributeError + PyErr_Clear(); + } + return result; } if (PyErr_Occurred()) { return NULL; @@ -763,37 +785,48 @@ module_getattro(PyModuleObject *m, PyObject *name) Py_DECREF(mod_name); return NULL; } - Py_XINCREF(spec); - if (_PyModuleSpec_IsInitializing(spec)) { - PyErr_Format(PyExc_AttributeError, - "partially initialized " - "module '%U' has no attribute '%U' " - "(most likely due to a circular import)", - mod_name, name); - } - else if (_PyModuleSpec_IsUninitializedSubmodule(spec, name)) { - PyErr_Format(PyExc_AttributeError, - "cannot access submodule '%U' of module '%U' " - "(most likely due to a circular import)", - name, mod_name); - } - else { - PyErr_Format(PyExc_AttributeError, - "module '%U' has no attribute '%U'", - mod_name, name); + if (suppress != 1) { + Py_XINCREF(spec); + if (_PyModuleSpec_IsInitializing(spec)) { + PyErr_Format(PyExc_AttributeError, + "partially initialized " + "module '%U' has no attribute '%U' " + "(most likely due to a circular import)", + mod_name, name); + } + else if (_PyModuleSpec_IsUninitializedSubmodule(spec, name)) { + PyErr_Format(PyExc_AttributeError, + "cannot access submodule '%U' of module '%U' " + "(most likely due to a circular import)", + name, mod_name); + } + else { + PyErr_Format(PyExc_AttributeError, + "module '%U' has no attribute '%U'", + mod_name, name); + } + Py_XDECREF(spec); } - Py_XDECREF(spec); Py_DECREF(mod_name); return NULL; } else if (PyErr_Occurred()) { return NULL; } - PyErr_Format(PyExc_AttributeError, - "module has no attribute '%U'", name); + if (suppress != 1) { + PyErr_Format(PyExc_AttributeError, + "module has no attribute '%U'", name); + } return NULL; } + +PyObject* +_Py_module_getattro(PyModuleObject *m, PyObject *name) +{ + return _Py_module_getattro_impl(m, name, 0); +} + static int module_traverse(PyModuleObject *m, visitproc visit, void *arg) { @@ -951,7 +984,7 @@ PyTypeObject PyModule_Type = { 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ - (getattrofunc)module_getattro, /* tp_getattro */ + (getattrofunc)_Py_module_getattro, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | diff --git a/Objects/object.c b/Objects/object.c index c6ef59281648..41c52e21045a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1085,6 +1085,17 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) return 0; } } + else if (tp->tp_getattro == (getattrofunc)_Py_module_getattro) { + // optimization: suppress attribute error from module getattro method + *result = _Py_module_getattro_impl((PyModuleObject*)v, name, 1); + if (*result != NULL) { + return 1; + } + if (PyErr_Occurred()) { + return -1; + } + return 0; + } else if (tp->tp_getattro != NULL) { *result = (*tp->tp_getattro)(v, name); } From webhook-mailer at python.org Thu May 4 10:57:13 2023 From: webhook-mailer at python.org (vstinner) Date: Thu, 04 May 2023 14:57:13 -0000 Subject: [Python-checkins] gh-96534: socketmodule: support FreeBSD divert(4) socket (#96536) Message-ID: <mailman.161.1683212234.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b17d32c1142d16a5fea0c95bce185bf9be696491 commit: b17d32c1142d16a5fea0c95bce185bf9be696491 branch: main author: Gleb Smirnoff <glebius at FreeBSD.org> committer: vstinner <vstinner at python.org> date: 2023-05-04T14:57:05Z summary: gh-96534: socketmodule: support FreeBSD divert(4) socket (#96536) files: A Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst M Doc/library/socket.rst M Modules/socketmodule.c diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 4ee0897db940..13a82cf82d59 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -509,6 +509,17 @@ Constants .. versionadded:: 3.9 +.. data:: AF_DIVERT + PF_DIVERT + + These two constants, documented in the FreeBSD divert(4) manual page, are + also defined in the socket module. + + .. availability:: FreeBSD >= 14.0. + + .. versionadded:: 3.12 + + .. data:: AF_PACKET PF_PACKET PACKET_* diff --git a/Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst b/Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst new file mode 100644 index 000000000000..0497d9eb6916 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst @@ -0,0 +1 @@ +Support divert(4) added in FreeBSD 14. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index f11d4b1a6e05..e5478382e11f 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1903,6 +1903,11 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, /* RDS sockets use sockaddr_in: fall-through */ #endif /* AF_RDS */ +#ifdef AF_DIVERT + case AF_DIVERT: + /* FreeBSD divert(4) sockets use sockaddr_in: fall-through */ +#endif /* AF_DIVERT */ + case AF_INET: { struct maybe_idna host = {NULL, NULL}; @@ -7683,6 +7688,14 @@ socket_exec(PyObject *m) ADD_INT_MACRO(m, AF_SYSTEM); #endif +/* FreeBSD divert(4) */ +#ifdef PF_DIVERT + PyModule_AddIntMacro(m, PF_DIVERT); +#endif +#ifdef AF_DIVERT + PyModule_AddIntMacro(m, AF_DIVERT); +#endif + #ifdef AF_PACKET ADD_INT_MACRO(m, AF_PACKET); #endif From webhook-mailer at python.org Thu May 4 10:59:55 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 04 May 2023 14:59:55 -0000 Subject: [Python-checkins] gh-102500: Implement PEP 688 (#102521) Message-ID: <mailman.162.1683212397.13550.python-checkins@python.org> https://github.com/python/cpython/commit/04f673327530f47f002e784459037231de478412 commit: 04f673327530f47f002e784459037231de478412 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-04T07:59:46-07:00 summary: gh-102500: Implement PEP 688 (#102521) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Include/internal/pycore_memoryobject.h A Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst A Modules/_testcapi/buffer.c M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_typeobject.h M Include/internal/pycore_unicodeobject_generated.h M Include/pybuffer.h M Lib/_collections_abc.py M Lib/inspect.py M Lib/test/test_buffer.py M Lib/test/test_collections.py M Lib/test/test_doctest.py M Modules/Setup.stdlib.in M Modules/_testcapi/parts.h M Modules/_testcapimodule.c M Objects/clinic/memoryobject.c.h M Objects/memoryobject.c M Objects/object.c M Objects/typeobject.c M PCbuild/_testcapi.vcxproj M PCbuild/_testcapi.vcxproj.filters M Tools/build/generate_global_objects.py M Tools/c-analyzer/cpython/globals-to-fix.tsv M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index f0740b68dd11..9377fd8526e3 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -593,6 +593,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__await__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bases__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bool__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__buffer__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__build_class__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__builtins__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bytes__)); @@ -692,6 +693,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rdivmod__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reduce__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reduce_ex__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__release_buffer__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__repr__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__reversed__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rfloordiv__)); @@ -1122,6 +1124,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reducer_override)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(registry)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(release)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reload)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(repl)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(replace)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 234d5e2a0989..ed9b2bb44ddf 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -81,6 +81,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__await__) STRUCT_FOR_ID(__bases__) STRUCT_FOR_ID(__bool__) + STRUCT_FOR_ID(__buffer__) STRUCT_FOR_ID(__build_class__) STRUCT_FOR_ID(__builtins__) STRUCT_FOR_ID(__bytes__) @@ -180,6 +181,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__rdivmod__) STRUCT_FOR_ID(__reduce__) STRUCT_FOR_ID(__reduce_ex__) + STRUCT_FOR_ID(__release_buffer__) STRUCT_FOR_ID(__repr__) STRUCT_FOR_ID(__reversed__) STRUCT_FOR_ID(__rfloordiv__) @@ -610,6 +612,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(reducer_override) STRUCT_FOR_ID(registry) STRUCT_FOR_ID(rel_tol) + STRUCT_FOR_ID(release) STRUCT_FOR_ID(reload) STRUCT_FOR_ID(repl) STRUCT_FOR_ID(replace) diff --git a/Include/internal/pycore_memoryobject.h b/Include/internal/pycore_memoryobject.h new file mode 100644 index 000000000000..acc12c927517 --- /dev/null +++ b/Include/internal/pycore_memoryobject.h @@ -0,0 +1,17 @@ +#ifndef Py_INTERNAL_MEMORYOBJECT_H +#define Py_INTERNAL_MEMORYOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +PyObject * +PyMemoryView_FromObjectAndFlags(PyObject *v, int flags); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_MEMORYOBJECT_H */ diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 16f2147aa8e9..6ade8fb6eade 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -587,6 +587,7 @@ extern "C" { INIT_ID(__await__), \ INIT_ID(__bases__), \ INIT_ID(__bool__), \ + INIT_ID(__buffer__), \ INIT_ID(__build_class__), \ INIT_ID(__builtins__), \ INIT_ID(__bytes__), \ @@ -686,6 +687,7 @@ extern "C" { INIT_ID(__rdivmod__), \ INIT_ID(__reduce__), \ INIT_ID(__reduce_ex__), \ + INIT_ID(__release_buffer__), \ INIT_ID(__repr__), \ INIT_ID(__reversed__), \ INIT_ID(__rfloordiv__), \ @@ -1116,6 +1118,7 @@ extern "C" { INIT_ID(reducer_override), \ INIT_ID(registry), \ INIT_ID(rel_tol), \ + INIT_ID(release), \ INIT_ID(reload), \ INIT_ID(repl), \ INIT_ID(replace), \ diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 6a5ab7e63f85..f42f8f62de2c 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -138,6 +138,8 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name); PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name); PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); +PyAPI_DATA(PyTypeObject) _PyBufferWrapper_Type; + PyObject * _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found); PyObject * diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index cd41b731537f..0b33ea187e60 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -96,6 +96,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(__bool__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(__buffer__); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__build_class__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -393,6 +396,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(__reduce_ex__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(__release_buffer__); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__repr__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1683,6 +1689,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(rel_tol); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(release); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reload); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Include/pybuffer.h b/Include/pybuffer.h index bbac60972f51..ca1c6058d905 100644 --- a/Include/pybuffer.h +++ b/Include/pybuffer.h @@ -104,7 +104,7 @@ PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); /* Maximum number of dimensions */ #define PyBUF_MAX_NDIM 64 -/* Flags for getting buffers */ +/* Flags for getting buffers. Keep these in sync with inspect.BufferFlags. */ #define PyBUF_SIMPLE 0 #define PyBUF_WRITABLE 0x0001 diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 9d7724c33474..2117190cf8b6 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -49,7 +49,7 @@ def _f(): pass "Mapping", "MutableMapping", "MappingView", "KeysView", "ItemsView", "ValuesView", "Sequence", "MutableSequence", - "ByteString", + "ByteString", "Buffer", ] # This module has been renamed from collections.abc to _collections_abc to @@ -439,6 +439,21 @@ def __subclasshook__(cls, C): return NotImplemented +class Buffer(metaclass=ABCMeta): + + __slots__ = () + + @abstractmethod + def __buffer__(self, flags: int, /) -> memoryview: + raise NotImplementedError + + @classmethod + def __subclasshook__(cls, C): + if cls is Buffer: + return _check_methods(C, "__buffer__") + return NotImplemented + + class _CallableGenericAlias(GenericAlias): """ Represent `Callable[argtypes, resulttype]`. diff --git a/Lib/inspect.py b/Lib/inspect.py index 92c2675cfd7d..95da7fb71a39 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -43,6 +43,7 @@ "Attribute", "BlockFinder", "BoundArguments", + "BufferFlags", "CORO_CLOSED", "CORO_CREATED", "CORO_RUNNING", @@ -3312,6 +3313,28 @@ def signature(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=F globals=globals, locals=locals, eval_str=eval_str) +class BufferFlags(enum.IntFlag): + SIMPLE = 0x0 + WRITABLE = 0x1 + FORMAT = 0x4 + ND = 0x8 + STRIDES = 0x10 | ND + C_CONTIGUOUS = 0x20 | STRIDES + F_CONTIGUOUS = 0x40 | STRIDES + ANY_CONTIGUOUS = 0x80 | STRIDES + INDIRECT = 0x100 | STRIDES + CONTIG = ND | WRITABLE + CONTIG_RO = ND + STRIDED = STRIDES | WRITABLE + STRIDED_RO = STRIDES + RECORDS = STRIDES | WRITABLE | FORMAT + RECORDS_RO = STRIDES | FORMAT + FULL = INDIRECT | WRITABLE | FORMAT + FULL_RO = INDIRECT | FORMAT + READ = 0x100 + WRITE = 0x200 + + def _main(): """ Logic for inspecting an object given at command line """ import argparse diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 098d2d999643..b6e82ad4db26 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -17,6 +17,7 @@ import unittest from test import support from test.support import os_helper +import inspect from itertools import permutations, product from random import randrange, sample, choice import warnings @@ -4438,5 +4439,146 @@ def test_pybuffer_size_from_format(self): struct.calcsize(format)) +class TestPythonBufferProtocol(unittest.TestCase): + def test_basic(self): + class MyBuffer: + def __buffer__(self, flags): + return memoryview(b"hello") + + mv = memoryview(MyBuffer()) + self.assertEqual(mv.tobytes(), b"hello") + self.assertEqual(bytes(MyBuffer()), b"hello") + + def test_bad_buffer_method(self): + class MustReturnMV: + def __buffer__(self, flags): + return 42 + + self.assertRaises(TypeError, memoryview, MustReturnMV()) + + class NoBytesEither: + def __buffer__(self, flags): + return b"hello" + + self.assertRaises(TypeError, memoryview, NoBytesEither()) + + class WrongArity: + def __buffer__(self): + return memoryview(b"hello") + + self.assertRaises(TypeError, memoryview, WrongArity()) + + def test_release_buffer(self): + class WhatToRelease: + def __init__(self): + self.held = False + self.ba = bytearray(b"hello") + + def __buffer__(self, flags): + if self.held: + raise TypeError("already held") + self.held = True + return memoryview(self.ba) + + def __release_buffer__(self, buffer): + self.held = False + + wr = WhatToRelease() + self.assertFalse(wr.held) + with memoryview(wr) as mv: + self.assertTrue(wr.held) + self.assertEqual(mv.tobytes(), b"hello") + self.assertFalse(wr.held) + + def test_same_buffer_returned(self): + class WhatToRelease: + def __init__(self): + self.held = False + self.ba = bytearray(b"hello") + self.created_mv = None + + def __buffer__(self, flags): + if self.held: + raise TypeError("already held") + self.held = True + self.created_mv = memoryview(self.ba) + return self.created_mv + + def __release_buffer__(self, buffer): + assert buffer is self.created_mv + self.held = False + + wr = WhatToRelease() + self.assertFalse(wr.held) + with memoryview(wr) as mv: + self.assertTrue(wr.held) + self.assertEqual(mv.tobytes(), b"hello") + self.assertFalse(wr.held) + + def test_buffer_flags(self): + class PossiblyMutable: + def __init__(self, data, mutable) -> None: + self._data = bytearray(data) + self._mutable = mutable + + def __buffer__(self, flags): + if flags & inspect.BufferFlags.WRITABLE: + if not self._mutable: + raise RuntimeError("not mutable") + return memoryview(self._data) + else: + return memoryview(bytes(self._data)) + + mutable = PossiblyMutable(b"hello", True) + immutable = PossiblyMutable(b"hello", False) + with memoryview._from_flags(mutable, inspect.BufferFlags.WRITABLE) as mv: + self.assertEqual(mv.tobytes(), b"hello") + mv[0] = ord(b'x') + self.assertEqual(mv.tobytes(), b"xello") + with memoryview._from_flags(mutable, inspect.BufferFlags.SIMPLE) as mv: + self.assertEqual(mv.tobytes(), b"xello") + with self.assertRaises(TypeError): + mv[0] = ord(b'h') + self.assertEqual(mv.tobytes(), b"xello") + with memoryview._from_flags(immutable, inspect.BufferFlags.SIMPLE) as mv: + self.assertEqual(mv.tobytes(), b"hello") + with self.assertRaises(TypeError): + mv[0] = ord(b'x') + self.assertEqual(mv.tobytes(), b"hello") + + with self.assertRaises(RuntimeError): + memoryview._from_flags(immutable, inspect.BufferFlags.WRITABLE) + with memoryview(immutable) as mv: + self.assertEqual(mv.tobytes(), b"hello") + with self.assertRaises(TypeError): + mv[0] = ord(b'x') + self.assertEqual(mv.tobytes(), b"hello") + + def test_call_builtins(self): + ba = bytearray(b"hello") + mv = ba.__buffer__(0) + self.assertEqual(mv.tobytes(), b"hello") + ba.__release_buffer__(mv) + with self.assertRaises(OverflowError): + ba.__buffer__(sys.maxsize + 1) + + @unittest.skipIf(_testcapi is None, "requires _testcapi") + def test_c_buffer(self): + buf = _testcapi.testBuf() + self.assertEqual(buf.references, 0) + mv = buf.__buffer__(0) + self.assertIsInstance(mv, memoryview) + self.assertEqual(mv.tobytes(), b"test") + self.assertEqual(buf.references, 1) + buf.__release_buffer__(mv) + self.assertEqual(buf.references, 0) + with self.assertRaises(ValueError): + mv.tobytes() + # Calling it again doesn't cause issues + with self.assertRaises(ValueError): + buf.__release_buffer__(mv) + self.assertEqual(buf.references, 0) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index fb568a483964..8fc28a6bf98e 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -25,7 +25,7 @@ from collections.abc import Set, MutableSet from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView from collections.abc import Sequence, MutableSequence -from collections.abc import ByteString +from collections.abc import ByteString, Buffer class TestUserObjects(unittest.TestCase): @@ -1949,6 +1949,15 @@ def test_ByteString(self): self.assertFalse(issubclass(memoryview, ByteString)) self.validate_abstract_methods(ByteString, '__getitem__', '__len__') + def test_Buffer(self): + for sample in [bytes, bytearray, memoryview]: + self.assertIsInstance(sample(b"x"), Buffer) + self.assertTrue(issubclass(sample, Buffer)) + for sample in [str, list, tuple]: + self.assertNotIsInstance(sample(), Buffer) + self.assertFalse(issubclass(sample, Buffer)) + self.validate_abstract_methods(Buffer, '__buffer__') + def test_MutableSequence(self): for sample in [tuple, str, bytes]: self.assertNotIsInstance(sample(), MutableSequence) diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 3491d4cdb1c1..542fcdb5cf6f 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -707,7 +707,7 @@ def non_Python_modules(): r""" >>> import builtins >>> tests = doctest.DocTestFinder().find(builtins) - >>> 830 < len(tests) < 850 # approximate number of objects with docstrings + >>> 830 < len(tests) < 860 # approximate number of objects with docstrings True >>> real_tests = [t for t in tests if len(t.examples) > 0] >>> len(real_tests) # objects that actually have doctests diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst new file mode 100644 index 000000000000..e03113ba05cd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst @@ -0,0 +1,3 @@ +Make the buffer protocol accessible in Python code using the new +``__buffer__`` and ``__release_buffer__`` magic methods. See :pep:`688` for +details. Patch by Jelle Zijlstra. diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 6b4833419537..a7803cf7c00e 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE at _xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE at _testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE at _testinternalcapi _testinternalcapi.c - at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c + at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c @MODULE__TESTCLINIC_TRUE at _testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/buffer.c b/Modules/_testcapi/buffer.c new file mode 100644 index 000000000000..aff9a477eff5 --- /dev/null +++ b/Modules/_testcapi/buffer.c @@ -0,0 +1,102 @@ +/* Test PEP 688 - Buffers */ + +#include "parts.h" + +#include "structmember.h" // PyMemberDef +#include <stddef.h> // offsetof + +typedef struct { + PyObject_HEAD + PyObject *obj; + Py_ssize_t references; +} testBufObject; + +static PyObject * +testbuf_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *obj = PyBytes_FromString("test"); + if (obj == NULL) { + return NULL; + } + testBufObject *self = (testBufObject *)type->tp_alloc(type, 0); + if (self == NULL) { + Py_DECREF(obj); + return NULL; + } + self->obj = obj; + self->references = 0; + return (PyObject *)self; +} + +static int +testbuf_traverse(testBufObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->obj); + return 0; +} + +static int +testbuf_clear(testBufObject *self) +{ + Py_CLEAR(self->obj); + return 0; +} + +static void +testbuf_dealloc(testBufObject *self) +{ + PyObject_GC_UnTrack(self); + Py_XDECREF(self->obj); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static int +testbuf_getbuf(testBufObject *self, Py_buffer *view, int flags) +{ + int buf = PyObject_GetBuffer(self->obj, view, flags); + Py_SETREF(view->obj, Py_NewRef(self)); + self->references++; + return buf; +} + +static void +testbuf_releasebuf(testBufObject *self, Py_buffer *view) +{ + self->references--; + assert(self->references >= 0); +} + +static PyBufferProcs testbuf_as_buffer = { + .bf_getbuffer = (getbufferproc) testbuf_getbuf, + .bf_releasebuffer = (releasebufferproc) testbuf_releasebuf, +}; + +static struct PyMemberDef testbuf_members[] = { + {"references", T_PYSSIZET, offsetof(testBufObject, references), READONLY}, + {NULL}, +}; + +static PyTypeObject testBufType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "testBufType", + .tp_basicsize = sizeof(testBufObject), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_new = testbuf_new, + .tp_dealloc = (destructor) testbuf_dealloc, + .tp_traverse = (traverseproc) testbuf_traverse, + .tp_clear = (inquiry) testbuf_clear, + .tp_as_buffer = &testbuf_as_buffer, + .tp_members = testbuf_members +}; + +int +_PyTestCapi_Init_Buffer(PyObject *m) { + if (PyType_Ready(&testBufType) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index d75412d51160..663d4f2255de 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -38,6 +38,7 @@ int _PyTestCapi_Init_Float(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); +int _PyTestCapi_Init_Buffer(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module); int _PyTestCapi_Init_Immortal(PyObject *module); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 1ecc44205808..38f4758e6575 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3959,7 +3959,6 @@ static PyTypeObject MyList_Type = { MyList_new, /* tp_new */ }; - /* Test PEP 560 */ typedef struct { @@ -4310,6 +4309,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Code(m) < 0) { return NULL; } + if (_PyTestCapi_Init_Buffer(m) < 0) { + return NULL; + } if (_PyTestCapi_Init_PyOS(m) < 0) { return NULL; } diff --git a/Objects/clinic/memoryobject.c.h b/Objects/clinic/memoryobject.c.h index ff7b50bb114b..25a223411859 100644 --- a/Objects/clinic/memoryobject.c.h +++ b/Objects/clinic/memoryobject.c.h @@ -62,6 +62,66 @@ memoryview(PyTypeObject *type, PyObject *args, PyObject *kwargs) return return_value; } +PyDoc_STRVAR(memoryview__from_flags__doc__, +"_from_flags($type, /, object, flags)\n" +"--\n" +"\n" +"Create a new memoryview object which references the given object."); + +#define MEMORYVIEW__FROM_FLAGS_METHODDEF \ + {"_from_flags", _PyCFunction_CAST(memoryview__from_flags), METH_FASTCALL|METH_KEYWORDS|METH_CLASS, memoryview__from_flags__doc__}, + +static PyObject * +memoryview__from_flags_impl(PyTypeObject *type, PyObject *object, int flags); + +static PyObject * +memoryview__from_flags(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(object), &_Py_ID(flags), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"object", "flags", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "_from_flags", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject *object; + int flags; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + object = args[0]; + flags = _PyLong_AsInt(args[1]); + if (flags == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = memoryview__from_flags_impl(type, object, flags); + +exit: + return return_value; +} + PyDoc_STRVAR(memoryview_release__doc__, "release($self, /)\n" "--\n" @@ -356,4 +416,4 @@ memoryview_hex(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs exit: return return_value; } -/*[clinic end generated code: output=a832f2fc44e4794c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=01613814112cedd7 input=a9049054013a1b77]*/ diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 34cc797b404c..f008a8cc3e04 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -85,7 +85,7 @@ mbuf_alloc(void) } static PyObject * -_PyManagedBuffer_FromObject(PyObject *base) +_PyManagedBuffer_FromObject(PyObject *base, int flags) { _PyManagedBufferObject *mbuf; @@ -93,7 +93,7 @@ _PyManagedBuffer_FromObject(PyObject *base) if (mbuf == NULL) return NULL; - if (PyObject_GetBuffer(base, &mbuf->master, PyBUF_FULL_RO) < 0) { + if (PyObject_GetBuffer(base, &mbuf->master, flags) < 0) { mbuf->master.obj = NULL; Py_DECREF(mbuf); return NULL; @@ -777,11 +777,12 @@ PyMemoryView_FromBuffer(const Py_buffer *info) return mv; } -/* Create a memoryview from an object that implements the buffer protocol. +/* Create a memoryview from an object that implements the buffer protocol, + using the given flags. If the object is a memoryview, the new memoryview must be registered with the same managed buffer. Otherwise, a new managed buffer is created. */ PyObject * -PyMemoryView_FromObject(PyObject *v) +PyMemoryView_FromObjectAndFlags(PyObject *v, int flags) { _PyManagedBufferObject *mbuf; @@ -792,7 +793,7 @@ PyMemoryView_FromObject(PyObject *v) } else if (PyObject_CheckBuffer(v)) { PyObject *ret; - mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v); + mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(v, flags); if (mbuf == NULL) return NULL; ret = mbuf_add_view(mbuf, NULL); @@ -805,6 +806,14 @@ PyMemoryView_FromObject(PyObject *v) Py_TYPE(v)->tp_name); return NULL; } +/* Create a memoryview from an object that implements the buffer protocol. + If the object is a memoryview, the new memoryview must be registered + with the same managed buffer. Otherwise, a new managed buffer is created. */ +PyObject * +PyMemoryView_FromObject(PyObject *v) +{ + return PyMemoryView_FromObjectAndFlags(v, PyBUF_FULL_RO); +} /* Copy the format string from a base object that might vanish. */ static int @@ -851,7 +860,7 @@ memory_from_contiguous_copy(const Py_buffer *src, char order) if (bytes == NULL) return NULL; - mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes); + mbuf = (_PyManagedBufferObject *)_PyManagedBuffer_FromObject(bytes, PyBUF_FULL_RO); Py_DECREF(bytes); if (mbuf == NULL) return NULL; @@ -968,6 +977,24 @@ memoryview_impl(PyTypeObject *type, PyObject *object) } +/*[clinic input] + at classmethod +memoryview._from_flags + + object: object + flags: int + +Create a new memoryview object which references the given object. +[clinic start generated code]*/ + +static PyObject * +memoryview__from_flags_impl(PyTypeObject *type, PyObject *object, int flags) +/*[clinic end generated code: output=bf71f9906c266ee2 input=f5f82fd0e744356b]*/ +{ + return PyMemoryView_FromObjectAndFlags(object, flags); +} + + /****************************************************************************/ /* Previously in abstract.c */ /****************************************************************************/ @@ -3184,6 +3211,7 @@ static PyMethodDef memory_methods[] = { MEMORYVIEW_TOLIST_METHODDEF MEMORYVIEW_CAST_METHODDEF MEMORYVIEW_TOREADONLY_METHODDEF + MEMORYVIEW__FROM_FLAGS_METHODDEF {"__enter__", memory_enter, METH_NOARGS, NULL}, {"__exit__", memory_exit, METH_VARARGS, NULL}, {NULL, NULL} diff --git a/Objects/object.c b/Objects/object.c index 41c52e21045a..a7c79c673d5f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -14,6 +14,7 @@ #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntry_Type +#include "pycore_typeobject.h" // _PyBufferWrapper_Type #include "pycore_unionobject.h" // _PyUnion_Type #include "pycore_interpreteridobject.h" // _PyInterpreterID_Type @@ -2084,6 +2085,7 @@ static PyTypeObject* static_types[] = { &_PyAsyncGenASend_Type, &_PyAsyncGenAThrow_Type, &_PyAsyncGenWrappedValue_Type, + &_PyBufferWrapper_Type, &_PyContextTokenMissing_Type, &_PyCoroWrapper_Type, &_Py_GenericAliasIterType, diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 171c76a59a55..456b10ee01d6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6,6 +6,7 @@ #include "pycore_symtable.h" // _Py_Mangle() #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_memoryobject.h" // PyMemoryView_FromObjectAndFlags() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() #include "pycore_long.h" // _PyLong_IsNegative() @@ -8059,6 +8060,58 @@ wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped) Py_RETURN_NONE; } +static PyObject * +wrap_buffer(PyObject *self, PyObject *args, void *wrapped) +{ + PyObject *arg = NULL; + + if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) { + return NULL; + } + Py_ssize_t flags = PyNumber_AsSsize_t(arg, PyExc_OverflowError); + if (flags == -1 && PyErr_Occurred()) { + return NULL; + } + if (flags > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "buffer flags too large"); + return NULL; + } + + return PyMemoryView_FromObjectAndFlags(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int)); +} + +static PyObject * +wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped) +{ + PyObject *arg = NULL; + if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) { + return NULL; + } + if (!PyMemoryView_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "expected a memoryview object"); + return NULL; + } + PyMemoryViewObject *mview = (PyMemoryViewObject *)arg; + if (mview->view.obj != self) { + PyErr_SetString(PyExc_ValueError, + "memoryview's buffer is not this object"); + return NULL; + } + if (mview->flags & _Py_MEMORYVIEW_RELEASED) { + PyErr_SetString(PyExc_ValueError, + "memoryview's buffer has already been released"); + return NULL; + } + PyObject *res = PyObject_CallMethodNoArgs((PyObject *)mview, &_Py_ID(release)); + if (res == NULL) { + return NULL; + } + Py_DECREF(res); + Py_RETURN_NONE; +} + static PyObject * wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) { @@ -8895,6 +8948,132 @@ slot_tp_finalize(PyObject *self) PyErr_SetRaisedException(exc); } +typedef struct _PyBufferWrapper { + PyObject_HEAD + PyObject *mv; + PyObject *obj; +} PyBufferWrapper; + +static int +bufferwrapper_traverse(PyBufferWrapper *self, visitproc visit, void *arg) +{ + Py_VISIT(self->mv); + Py_VISIT(self->obj); + return 0; +} + +static void +bufferwrapper_dealloc(PyObject *self) +{ + PyBufferWrapper *bw = (PyBufferWrapper *)self; + + _PyObject_GC_UNTRACK(self); + Py_XDECREF(bw->mv); + Py_XDECREF(bw->obj); + Py_TYPE(self)->tp_free(self); +} + +static void +bufferwrapper_releasebuf(PyObject *self, Py_buffer *view) +{ + PyBufferWrapper *bw = (PyBufferWrapper *)self; + + assert(PyMemoryView_Check(bw->mv)); + Py_TYPE(bw->mv)->tp_as_buffer->bf_releasebuffer(bw->mv, view); + if (Py_TYPE(bw->obj)->tp_as_buffer != NULL + && Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer != NULL) { + Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer(bw->obj, view); + } +} + +static PyBufferProcs bufferwrapper_as_buffer = { + .bf_releasebuffer = bufferwrapper_releasebuf, +}; + + +PyTypeObject _PyBufferWrapper_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "_buffer_wrapper", + .tp_basicsize = sizeof(PyBufferWrapper), + .tp_alloc = PyType_GenericAlloc, + .tp_free = PyObject_GC_Del, + .tp_traverse = (traverseproc)bufferwrapper_traverse, + .tp_dealloc = bufferwrapper_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_as_buffer = &bufferwrapper_as_buffer, +}; + +static int +slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags) +{ + PyObject *flags_obj = PyLong_FromLong(flags); + if (flags_obj == NULL) { + return -1; + } + PyBufferWrapper *wrapper = NULL; + PyObject *stack[2] = {self, flags_obj}; + PyObject *ret = vectorcall_method(&_Py_ID(__buffer__), stack, 2); + if (ret == NULL) { + goto fail; + } + if (!PyMemoryView_Check(ret)) { + PyErr_Format(PyExc_TypeError, + "__buffer__ returned non-memoryview object"); + goto fail; + } + + if (PyObject_GetBuffer(ret, buffer, flags) < 0) { + goto fail; + } + assert(buffer->obj == ret); + + wrapper = PyObject_GC_New(PyBufferWrapper, &_PyBufferWrapper_Type); + if (wrapper == NULL) { + goto fail; + } + wrapper->mv = ret; + wrapper->obj = Py_NewRef(self); + _PyObject_GC_TRACK(wrapper); + + buffer->obj = (PyObject *)wrapper; + Py_DECREF(ret); + Py_DECREF(flags_obj); + return 0; + +fail: + Py_XDECREF(wrapper); + Py_XDECREF(ret); + Py_DECREF(flags_obj); + return -1; +} + +static void +slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer) +{ + PyObject *mv; + if (Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type) { + // Make sure we pass the same memoryview to + // __release_buffer__() that __buffer__() returned. + mv = Py_NewRef(((PyBufferWrapper *)buffer->obj)->mv); + } + else { + mv = PyMemoryView_FromBuffer(buffer); + if (mv == NULL) { + PyErr_WriteUnraisable(self); + return; + } + } + PyObject *stack[2] = {self, mv}; + PyObject *ret = vectorcall_method(&_Py_ID(__release_buffer__), stack, 2); + Py_DECREF(mv); + if (ret == NULL) { + PyErr_WriteUnraisable(self); + } + else { + Py_DECREF(ret); + } +} + static PyObject * slot_am_await(PyObject *self) { @@ -8962,6 +9141,7 @@ an all-zero entry. #undef TPSLOT #undef FLSLOT +#undef BUFSLOT #undef AMSLOT #undef ETSLOT #undef SQSLOT @@ -8981,6 +9161,8 @@ an all-zero entry. #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ {#NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ PyDoc_STR(DOC), .name_strobj = &_Py_ID(NAME) } +#define BUFSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_buffer.SLOT, FUNCTION, WRAPPER, DOC) #define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_async.SLOT, FUNCTION, WRAPPER, DOC) #define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ @@ -9062,6 +9244,13 @@ static pytype_slotdef slotdefs[] = { "Create and return new object. See help(type) for accurate signature."), TPSLOT(__del__, tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), + BUFSLOT(__buffer__, bf_getbuffer, slot_bf_getbuffer, wrap_buffer, + "__buffer__($self, flags, /)\n--\n\n" + "Return a buffer object that exposes the underlying memory of the object."), + BUFSLOT(__release_buffer__, bf_releasebuffer, slot_bf_releasebuffer, wrap_releasebuffer, + "__release_buffer__($self, /)\n--\n\n" + "Release the buffer object that exposes the underlying memory of the object."), + AMSLOT(__await__, am_await, slot_am_await, wrap_unaryfunc, "__await__($self, /)\n--\n\nReturn an iterator to be used in await expression."), AMSLOT(__aiter__, am_aiter, slot_am_aiter, wrap_unaryfunc, @@ -9208,8 +9397,12 @@ slotptr(PyTypeObject *type, int ioffset) /* Note: this depends on the order of the members of PyHeapTypeObject! */ assert(offset >= 0); - assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer)); - if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) { + assert((size_t)offset < offsetof(PyHeapTypeObject, ht_name)); + if ((size_t)offset >= offsetof(PyHeapTypeObject, as_buffer)) { + ptr = (char *)type->tp_as_buffer; + offset -= offsetof(PyHeapTypeObject, as_buffer); + } + else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) { ptr = (char *)type->tp_as_sequence; offset -= offsetof(PyHeapTypeObject, as_sequence); } diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 56448b6ee7d4..350f97f8ff41 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -110,6 +110,7 @@ <ClCompile Include="..\Modules\_testcapi\structmember.c" /> <ClCompile Include="..\Modules\_testcapi\exceptions.c" /> <ClCompile Include="..\Modules\_testcapi\code.c" /> + <ClCompile Include="..\Modules\_testcapi\buffer.c" /> <ClCompile Include="..\Modules\_testcapi\pyos.c" /> <ClCompile Include="..\Modules\_testcapi\immortal.c" /> </ItemGroup> diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 297c9ce799be..af80f1eebb3c 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -60,6 +60,9 @@ <ClCompile Include="..\Modules\_testcapi\code.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Modules\_testcapi\buffer.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Modules\_testcapi\pyos.c"> <Filter>Source Files</Filter> </ClCompile> diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index c27817702bf9..ded19ee489e7 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -121,6 +121,8 @@ '__xor__', '__divmod__', '__rdivmod__', + '__buffer__', + '__release_buffer__', ] NON_GENERATED_IMMORTAL_OBJECTS = [ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 4dfbbe72df56..165bd74587d7 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -86,6 +86,7 @@ Objects/sliceobject.c - PyEllipsis_Type - Objects/sliceobject.c - PySlice_Type - Objects/tupleobject.c - PyTupleIter_Type - Objects/tupleobject.c - PyTuple_Type - +Objects/typeobject.c - _PyBufferWrapper_Type - Objects/typeobject.c - PyBaseObject_Type - Objects/typeobject.c - PySuper_Type - Objects/typeobject.c - PyType_Type - diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 7a5d7d45f518..fee493ff7f16 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -404,6 +404,7 @@ Modules/_testbuffer.c ndarray_memoryview_from_buffer strides - Modules/_testbuffer.c ndarray_memoryview_from_buffer suboffsets - Modules/_testbuffer.c ndarray_push kwlist - Modules/_testbuffer.c staticarray_init kwlist - +Modules/_testcapi/buffer.c - testBufType - Modules/_testcapi/code.c get_code_extra_index key - Modules/_testcapi/datetime.c - test_run_counter - Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type - From webhook-mailer at python.org Thu May 4 11:23:49 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 04 May 2023 15:23:49 -0000 Subject: [Python-checkins] gh-102500: Document PEP 688 (#102571) Message-ID: <mailman.163.1683213829.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b7a0a521960a6e9ea46b79b51cbcc3c4ffcc7057 commit: b7a0a521960a6e9ea46b79b51cbcc3c4ffcc7057 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-04T08:23:40-07:00 summary: gh-102500: Document PEP 688 (#102571) Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/collections.abc.rst M Doc/library/inspect.rst M Doc/reference/datamodel.rst M Doc/whatsnew/3.12.rst diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 1ada0d352a0c..669b7345499a 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -177,6 +177,7 @@ ABC Inherits from Abstract Methods Mi :class:`AsyncIterable` [1]_ ``__aiter__`` :class:`AsyncIterator` [1]_ :class:`AsyncIterable` ``__anext__`` ``__aiter__`` :class:`AsyncGenerator` [1]_ :class:`AsyncIterator` ``asend``, ``athrow`` ``aclose``, ``__aiter__``, ``__anext__`` +:class:`Buffer` [1]_ ``__buffer__`` ============================== ====================== ======================= ==================================================== @@ -346,6 +347,13 @@ Collections Abstract Base Classes -- Detailed Descriptions .. versionadded:: 3.6 +.. class:: Buffer + + ABC for classes that provide the :meth:`~object.__buffer__` method, + implementing the :ref:`buffer protocol <bufferobjects>`. See :pep:`688`. + + .. versionadded:: 3.12 + Examples and Recipes -------------------- diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 88f843c03b1d..7884308a3330 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1603,6 +1603,39 @@ the following flags: for any introspection needs. +Buffer flags +------------ + +.. class:: BufferFlags + + This is an :class:`enum.IntFlag` that represents the flags that + can be passed to the :meth:`~object.__buffer__` method of objects + implementing the :ref:`buffer protocol <bufferobjects>`. + + The meaning of the flags is explained at :ref:`buffer-request-types`. + + .. attribute:: BufferFlags.SIMPLE + .. attribute:: BufferFlags.WRITABLE + .. attribute:: BufferFlags.FORMAT + .. attribute:: BufferFlags.ND + .. attribute:: BufferFlags.STRIDES + .. attribute:: BufferFlags.C_CONTIGUOUS + .. attribute:: BufferFlags.F_CONTIGUOUS + .. attribute:: BufferFlags.ANY_CONTIGUOUS + .. attribute:: BufferFlags.INDIRECT + .. attribute:: BufferFlags.CONTIG + .. attribute:: BufferFlags.CONTIG_RO + .. attribute:: BufferFlags.STRIDED + .. attribute:: BufferFlags.STRIDED_RO + .. attribute:: BufferFlags.RECORDS + .. attribute:: BufferFlags.RECORDS_RO + .. attribute:: BufferFlags.FULL + .. attribute:: BufferFlags.FULL_RO + .. attribute:: BufferFlags.READ + .. attribute:: BufferFlags.WRITE + + .. versionadded:: 3.12 + .. _inspect-module-cli: Command Line Interface diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 1294d683e268..0a9cabc158b9 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -2865,6 +2865,47 @@ a :exc:`TypeError`. The specification for the Python ``match`` statement. +.. _python-buffer-protocol: + +Emulating buffer types +---------------------- + +The :ref:`buffer protocol <bufferobjects>` provides a way for Python +objects to expose efficient access to a low-level memory array. This protocol +is implemented by builtin types such as :class:`bytes` and :class:`memoryview`, +and third-party libraries may define additional buffer types. + +While buffer types are usually implemented in C, it is also possible to +implement the protocol in Python. + +.. method:: object.__buffer__(self, flags) + + Called when a buffer is requested from *self* (for example, by the + :class:`memoryview` constructor). The *flags* argument is an integer + representing the kind of buffer requested, affecting for example whether + the returned buffer is read-only or writable. :class:`inspect.BufferFlags` + provides a convenient way to interpret the flags. The method must return + a :class:`memoryview` object. + +.. method:: object.__release_buffer__(self, buffer) + + Called when a buffer is no longer needed. The *buffer* argument is a + :class:`memoryview` object that was previously returned by + :meth:`~object.__buffer__`. The method must release any resources associated + with the buffer. This method should return ``None``. + Buffer objects that do not need to perform any cleanup are not required + to implement this method. + +.. versionadded:: 3.12 + +.. seealso:: + + :pep:`688` - Making the buffer protocol accessible in Python + Introduces the Python ``__buffer__`` and ``__release_buffer__`` methods. + + :class:`collections.abc.Buffer` + ABC for buffer types. + .. _special-lookup: Special method lookup diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index edbf92146755..3fe3310a26e5 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -149,6 +149,19 @@ New Features In Python 3.14, the default will switch to ``'data'``. (Contributed by Petr Viktorin in :pep:`706`.) +PEP 688: Making the buffer protocol accessible in Python +-------------------------------------------------------- + +:pep:`688` introduces a way to use the :ref:`buffer protocol <bufferobjects>` +from Python code. Classes that implement the :meth:`~object.__buffer__` method +are now usable as buffer types. + +The new :class:`collections.abc.Buffer` ABC provides a standard +way to represent buffer objects, for example in type annotations. +The new :class:`inspect.BufferFlags` enum represents the flags that +can be used to customize buffer creation. +(Contributed by Jelle Zijlstra in :gh:`102500`.) + New Features Related to Type Hints ================================== @@ -179,7 +192,6 @@ See :pep:`692` for more details. (PEP written by Franek Magiera) - Other Language Changes ====================== From webhook-mailer at python.org Thu May 4 11:25:17 2023 From: webhook-mailer at python.org (vstinner) Date: Thu, 04 May 2023 15:25:17 -0000 Subject: [Python-checkins] gh-99593: Add tests for Unicode C API (part 2) (#99868) Message-ID: <mailman.164.1683213918.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2ba931ff727395cf89b290ed313a8e15db0bfcf1 commit: 2ba931ff727395cf89b290ed313a8e15db0bfcf1 branch: main author: Serhiy Storchaka <storchaka at gmail.com> committer: vstinner <vstinner at python.org> date: 2023-05-04T15:25:09Z summary: gh-99593: Add tests for Unicode C API (part 2) (#99868) Add tests for lower-level functions. Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: M Lib/test/test_capi/test_unicode.py M Modules/_testcapi/unicode.c M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 857579f75838..00807d968a7c 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -17,6 +17,287 @@ class Str(str): class CAPITest(unittest.TestCase): + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_new(self): + """Test PyUnicode_New()""" + from _testcapi import unicode_new as new + + for maxchar in 0, 0x61, 0xa1, 0x4f60, 0x1f600, 0x10ffff: + self.assertEqual(new(0, maxchar), '') + self.assertEqual(new(5, maxchar), chr(maxchar)*5) + self.assertEqual(new(0, 0x110000), '') + self.assertRaises(SystemError, new, 5, 0x110000) + self.assertRaises(SystemError, new, -1, 0) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_fill(self): + """Test PyUnicode_Fill()""" + from _testcapi import unicode_fill as fill + + strings = [ + # all strings have exactly 5 characters + 'abcde', '\xa1\xa2\xa3\xa4\xa5', + '\u4f60\u597d\u4e16\u754c\uff01', + '\U0001f600\U0001f601\U0001f602\U0001f603\U0001f604' + ] + chars = [0x78, 0xa9, 0x20ac, 0x1f638] + + for idx, fill_char in enumerate(chars): + # wide -> narrow: exceed maxchar limitation + for to in strings[:idx]: + self.assertRaises(ValueError, fill, to, 0, 0, fill_char) + for to in strings[idx:]: + for start in range(7): + for length in range(-1, 7 - start): + filled = max(min(length, 5 - start), 0) + if filled == 5 and to != strings[idx]: + # narrow -> wide + # Tests omitted since this creates invalid strings. + continue + expected = to[:start] + chr(fill_char) * filled + to[start + filled:] + self.assertEqual(fill(to, start, length, fill_char), + (expected, filled)) + + s = strings[0] + self.assertRaises(IndexError, fill, s, -1, 0, 0x78) + self.assertRaises(ValueError, fill, s, 0, 0, 0x110000) + self.assertRaises(SystemError, fill, b'abc', 0, 0, 0x78) + self.assertRaises(SystemError, fill, [], 0, 0, 0x78) + # CRASHES fill(s, 0, NULL, 0, 0) + # CRASHES fill(NULL, 0, 0, 0x78) + # TODO: Test PyUnicode_Fill() with non-modifiable unicode. + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_writechar(self): + """Test PyUnicode_ReadChar()""" + from _testcapi import unicode_writechar as writechar + + strings = [ + # one string for every kind + 'abc', '\xa1\xa2\xa3', '\u4f60\u597d\u4e16', + '\U0001f600\U0001f601\U0001f602' + ] + # one character for every kind + out of range code + chars = [0x78, 0xa9, 0x20ac, 0x1f638, 0x110000] + for i, s in enumerate(strings): + for j, c in enumerate(chars): + if j <= i: + self.assertEqual(writechar(s, 1, c), + (s[:1] + chr(c) + s[2:], 0)) + else: + self.assertRaises(ValueError, writechar, s, 1, c) + + self.assertRaises(IndexError, writechar, 'abc', 3, 0x78) + self.assertRaises(IndexError, writechar, 'abc', -1, 0x78) + self.assertRaises(TypeError, writechar, b'abc', 0, 0x78) + self.assertRaises(TypeError, writechar, [], 0, 0x78) + # CRASHES writechar(NULL, 0, 0x78) + # TODO: Test PyUnicode_CopyCharacters() with non-modifiable and legacy + # unicode. + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_resize(self): + """Test PyUnicode_Resize()""" + from _testcapi import unicode_resize as resize + + strings = [ + # all strings have exactly 3 characters + 'abc', '\xa1\xa2\xa3', '\u4f60\u597d\u4e16', + '\U0001f600\U0001f601\U0001f602' + ] + for s in strings: + self.assertEqual(resize(s, 3), (s, 0)) + self.assertEqual(resize(s, 2), (s[:2], 0)) + self.assertEqual(resize(s, 4), (s + '\0', 0)) + self.assertEqual(resize(s, 0), ('', 0)) + self.assertRaises(SystemError, resize, b'abc', 0) + self.assertRaises(SystemError, resize, [], 0) + self.assertRaises(SystemError, resize, NULL, 0) + # TODO: Test PyUnicode_Resize() with non-modifiable and legacy unicode + # and with NULL as the address. + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_append(self): + """Test PyUnicode_Append()""" + from _testcapi import unicode_append as append + + strings = [ + 'abc', '\xa1\xa2\xa3', '\u4f60\u597d\u4e16', + '\U0001f600\U0001f601\U0001f602' + ] + for left in strings: + left = left[::-1] + for right in strings: + expected = left + right + self.assertEqual(append(left, right), expected) + + self.assertRaises(SystemError, append, 'abc', b'abc') + self.assertRaises(SystemError, append, b'abc', 'abc') + self.assertRaises(SystemError, append, b'abc', b'abc') + self.assertRaises(SystemError, append, 'abc', []) + self.assertRaises(SystemError, append, [], 'abc') + self.assertRaises(SystemError, append, [], []) + self.assertRaises(SystemError, append, NULL, 'abc') + self.assertRaises(SystemError, append, 'abc', NULL) + # TODO: Test PyUnicode_Append() with modifiable unicode + # and with NULL as the address. + # TODO: Check reference counts. + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_appendanddel(self): + """Test PyUnicode_AppendAndDel()""" + from _testcapi import unicode_appendanddel as appendanddel + + strings = [ + 'abc', '\xa1\xa2\xa3', '\u4f60\u597d\u4e16', + '\U0001f600\U0001f601\U0001f602' + ] + for left in strings: + left = left[::-1] + for right in strings: + self.assertEqual(appendanddel(left, right), left + right) + + self.assertRaises(SystemError, appendanddel, 'abc', b'abc') + self.assertRaises(SystemError, appendanddel, b'abc', 'abc') + self.assertRaises(SystemError, appendanddel, b'abc', b'abc') + self.assertRaises(SystemError, appendanddel, 'abc', []) + self.assertRaises(SystemError, appendanddel, [], 'abc') + self.assertRaises(SystemError, appendanddel, [], []) + self.assertRaises(SystemError, appendanddel, NULL, 'abc') + self.assertRaises(SystemError, appendanddel, 'abc', NULL) + # TODO: Test PyUnicode_AppendAndDel() with modifiable unicode + # and with NULL as the address. + # TODO: Check reference counts. + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_fromstringandsize(self): + """Test PyUnicode_FromStringAndSize()""" + from _testcapi import unicode_fromstringandsize as fromstringandsize + + self.assertEqual(fromstringandsize(b'abc'), 'abc') + self.assertEqual(fromstringandsize(b'abc', 2), 'ab') + self.assertEqual(fromstringandsize(b'abc\0def'), 'abc\0def') + self.assertEqual(fromstringandsize(b'\xc2\xa1\xc2\xa2'), '\xa1\xa2') + self.assertEqual(fromstringandsize(b'\xe4\xbd\xa0'), '\u4f60') + self.assertEqual(fromstringandsize(b'\xf0\x9f\x98\x80'), '\U0001f600') + self.assertRaises(UnicodeDecodeError, fromstringandsize, b'\xc2\xa1', 1) + self.assertRaises(UnicodeDecodeError, fromstringandsize, b'\xa1', 1) + self.assertEqual(fromstringandsize(b'', 0), '') + self.assertEqual(fromstringandsize(NULL, 0), '') + + self.assertRaises(SystemError, fromstringandsize, b'abc', -1) + # TODO: Test PyUnicode_FromStringAndSize(NULL, size) for size != 0 + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_fromstring(self): + """Test PyUnicode_FromString()""" + from _testcapi import unicode_fromstring as fromstring + + self.assertEqual(fromstring(b'abc'), 'abc') + self.assertEqual(fromstring(b'\xc2\xa1\xc2\xa2'), '\xa1\xa2') + self.assertEqual(fromstring(b'\xe4\xbd\xa0'), '\u4f60') + self.assertEqual(fromstring(b'\xf0\x9f\x98\x80'), '\U0001f600') + self.assertRaises(UnicodeDecodeError, fromstring, b'\xc2') + self.assertRaises(UnicodeDecodeError, fromstring, b'\xa1') + self.assertEqual(fromstring(b''), '') + + # CRASHES fromstring(NULL) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_fromkindanddata(self): + """Test PyUnicode_FromKindAndData()""" + from _testcapi import unicode_fromkindanddata as fromkindanddata + + strings = [ + 'abcde', '\xa1\xa2\xa3\xa4\xa5', + '\u4f60\u597d\u4e16\u754c\uff01', + '\U0001f600\U0001f601\U0001f602\U0001f603\U0001f604' + ] + enc1 = 'latin1' + for s in strings[:2]: + self.assertEqual(fromkindanddata(1, s.encode(enc1)), s) + enc2 = 'utf-16le' if sys.byteorder == 'little' else 'utf-16be' + for s in strings[:3]: + self.assertEqual(fromkindanddata(2, s.encode(enc2)), s) + enc4 = 'utf-32le' if sys.byteorder == 'little' else 'utf-32be' + for s in strings: + self.assertEqual(fromkindanddata(4, s.encode(enc4)), s) + self.assertEqual(fromkindanddata(2, '\U0001f600'.encode(enc2)), + '\ud83d\ude00') + for kind in 1, 2, 4: + self.assertEqual(fromkindanddata(kind, b''), '') + self.assertEqual(fromkindanddata(kind, b'\0'*kind), '\0') + self.assertEqual(fromkindanddata(kind, NULL, 0), '') + + for kind in -1, 0, 3, 5, 8: + self.assertRaises(SystemError, fromkindanddata, kind, b'') + self.assertRaises(ValueError, fromkindanddata, 1, b'abc', -1) + self.assertRaises(ValueError, fromkindanddata, 1, NULL, -1) + # CRASHES fromkindanddata(1, NULL, 1) + # CRASHES fromkindanddata(4, b'\xff\xff\xff\xff') + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_substring(self): + """Test PyUnicode_Substring()""" + from _testcapi import unicode_substring as substring + + strings = [ + 'ab', 'ab\xa1\xa2', + 'ab\xa1\xa2\u4f60\u597d', + 'ab\xa1\xa2\u4f60\u597d\U0001f600\U0001f601' + ] + for s in strings: + for start in range(0, len(s) + 2): + for end in range(max(start-1, 0), len(s) + 2): + self.assertEqual(substring(s, start, end), s[start:end]) + + self.assertRaises(IndexError, substring, 'abc', -1, 0) + self.assertRaises(IndexError, substring, 'abc', 0, -1) + # CRASHES substring(b'abc', 0, 0) + # CRASHES substring([], 0, 0) + # CRASHES substring(NULL, 0, 0) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_getlength(self): + """Test PyUnicode_GetLength()""" + from _testcapi import unicode_getlength as getlength + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', + 'a\ud800b\udfffc', '\ud834\udd1e']: + self.assertEqual(getlength(s), len(s)) + + self.assertRaises(TypeError, getlength, b'abc') + self.assertRaises(TypeError, getlength, []) + # CRASHES getlength(NULL) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_readchar(self): + """Test PyUnicode_ReadChar()""" + from _testcapi import unicode_readchar as readchar + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', + 'a\ud800b\udfffc', '\ud834\udd1e']: + for i, c in enumerate(s): + self.assertEqual(readchar(s, i), ord(c)) + self.assertRaises(IndexError, readchar, s, len(s)) + self.assertRaises(IndexError, readchar, s, -1) + + self.assertRaises(TypeError, readchar, b'abc', 0) + self.assertRaises(TypeError, readchar, [], 0) + # CRASHES readchar(NULL, 0) + @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_fromobject(self): @@ -293,13 +574,70 @@ def check_format(expected, format, *args): self.assertRaisesRegex(SystemError, 'invalid format string', PyUnicode_FromFormat, b'%+i', c_int(10)) + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_interninplace(self): + """Test PyUnicode_InternInPlace()""" + from _testcapi import unicode_interninplace as interninplace + + s = b'abc'.decode() + r = interninplace(s) + self.assertEqual(r, 'abc') + + # CRASHES interninplace(b'abc') + # CRASHES interninplace(NULL) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_internfromstring(self): + """Test PyUnicode_InternFromString()""" + from _testcapi import unicode_internfromstring as internfromstring + + self.assertEqual(internfromstring(b'abc'), 'abc') + self.assertEqual(internfromstring(b'\xf0\x9f\x98\x80'), '\U0001f600') + self.assertRaises(UnicodeDecodeError, internfromstring, b'\xc2') + self.assertRaises(UnicodeDecodeError, internfromstring, b'\xa1') + self.assertEqual(internfromstring(b''), '') + + # CRASHES internfromstring(NULL) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_fromwidechar(self): + """Test PyUnicode_FromWideChar()""" + from _testcapi import unicode_fromwidechar as fromwidechar + from _testcapi import SIZEOF_WCHAR_T + + if SIZEOF_WCHAR_T == 2: + encoding = 'utf-16le' if sys.byteorder == 'little' else 'utf-16be' + elif SIZEOF_WCHAR_T == 4: + encoding = 'utf-32le' if sys.byteorder == 'little' else 'utf-32be' + + for s in '', 'abc', '\xa1\xa2', '\u4f60', '\U0001f600': + b = s.encode(encoding) + self.assertEqual(fromwidechar(b), s) + self.assertEqual(fromwidechar(b + b'\0'*SIZEOF_WCHAR_T, -1), s) + for s in '\ud83d', '\ude00': + b = s.encode(encoding, 'surrogatepass') + self.assertEqual(fromwidechar(b), s) + self.assertEqual(fromwidechar(b + b'\0'*SIZEOF_WCHAR_T, -1), s) + + self.assertEqual(fromwidechar('abc'.encode(encoding), 2), 'ab') + if SIZEOF_WCHAR_T == 2: + self.assertEqual(fromwidechar('a\U0001f600'.encode(encoding), 2), 'a\ud83d') + + self.assertRaises(SystemError, fromwidechar, b'\0'*SIZEOF_WCHAR_T, -2) + self.assertEqual(fromwidechar(NULL, 0), '') + self.assertRaises(SystemError, fromwidechar, NULL, 1) + self.assertRaises(SystemError, fromwidechar, NULL, -1) + @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_aswidechar(self): """Test PyUnicode_AsWideChar()""" from _testcapi import unicode_aswidechar - import_helper.import_module('ctypes') - from ctypes import c_wchar, sizeof + from _testcapi import unicode_aswidechar_null + from _testcapi import SIZEOF_WCHAR_T wchar, size = unicode_aswidechar('abcdef', 2) self.assertEqual(size, 2) @@ -308,6 +646,8 @@ def test_aswidechar(self): wchar, size = unicode_aswidechar('abc', 3) self.assertEqual(size, 3) self.assertEqual(wchar, 'abc') + self.assertEqual(unicode_aswidechar_null('abc', 10), 4) + self.assertEqual(unicode_aswidechar_null('abc', 0), 4) wchar, size = unicode_aswidechar('abc', 4) self.assertEqual(size, 3) @@ -320,60 +660,113 @@ def test_aswidechar(self): wchar, size = unicode_aswidechar('abc\0def', 20) self.assertEqual(size, 7) self.assertEqual(wchar, 'abc\0def\0') + self.assertEqual(unicode_aswidechar_null('abc\0def', 20), 8) nonbmp = chr(0x10ffff) - if sizeof(c_wchar) == 2: - buflen = 3 + if SIZEOF_WCHAR_T == 2: nchar = 2 - else: # sizeof(c_wchar) == 4 - buflen = 2 + else: # SIZEOF_WCHAR_T == 4 nchar = 1 - wchar, size = unicode_aswidechar(nonbmp, buflen) + wchar, size = unicode_aswidechar(nonbmp, 10) self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') + self.assertEqual(unicode_aswidechar_null(nonbmp, 10), nchar + 1) + + self.assertRaises(TypeError, unicode_aswidechar, b'abc', 10) + self.assertRaises(TypeError, unicode_aswidechar, [], 10) + self.assertRaises(SystemError, unicode_aswidechar, NULL, 10) + self.assertRaises(TypeError, unicode_aswidechar_null, b'abc', 10) + self.assertRaises(TypeError, unicode_aswidechar_null, [], 10) + self.assertRaises(SystemError, unicode_aswidechar_null, NULL, 10) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_aswidecharstring(self): """Test PyUnicode_AsWideCharString()""" from _testcapi import unicode_aswidecharstring - import_helper.import_module('ctypes') - from ctypes import c_wchar, sizeof + from _testcapi import unicode_aswidecharstring_null + from _testcapi import SIZEOF_WCHAR_T wchar, size = unicode_aswidecharstring('abc') self.assertEqual(size, 3) self.assertEqual(wchar, 'abc\0') + self.assertEqual(unicode_aswidecharstring_null('abc'), 'abc') wchar, size = unicode_aswidecharstring('abc\0def') self.assertEqual(size, 7) self.assertEqual(wchar, 'abc\0def\0') + self.assertRaises(ValueError, unicode_aswidecharstring_null, 'abc\0def') nonbmp = chr(0x10ffff) - if sizeof(c_wchar) == 2: + if SIZEOF_WCHAR_T == 2: nchar = 2 - else: # sizeof(c_wchar) == 4 + else: # SIZEOF_WCHAR_T == 4 nchar = 1 wchar, size = unicode_aswidecharstring(nonbmp) self.assertEqual(size, nchar) self.assertEqual(wchar, nonbmp + '\0') + self.assertEqual(unicode_aswidecharstring_null(nonbmp), nonbmp) + + self.assertRaises(TypeError, unicode_aswidecharstring, b'abc') + self.assertRaises(TypeError, unicode_aswidecharstring, []) + self.assertRaises(SystemError, unicode_aswidecharstring, NULL) + self.assertRaises(TypeError, unicode_aswidecharstring_null, b'abc') + self.assertRaises(TypeError, unicode_aswidecharstring_null, []) + self.assertRaises(SystemError, unicode_aswidecharstring_null, NULL) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_asucs4(self): """Test PyUnicode_AsUCS4()""" from _testcapi import unicode_asucs4 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', 'a\ud800b\udfffc', '\ud834\udd1e']: l = len(s) - self.assertEqual(unicode_asucs4(s, l, True), s+'\0') - self.assertEqual(unicode_asucs4(s, l, False), s+'\uffff') - self.assertEqual(unicode_asucs4(s, l+1, True), s+'\0\uffff') - self.assertEqual(unicode_asucs4(s, l+1, False), s+'\0\uffff') - self.assertRaises(SystemError, unicode_asucs4, s, l-1, True) - self.assertRaises(SystemError, unicode_asucs4, s, l-2, False) + self.assertEqual(unicode_asucs4(s, l, 1), s+'\0') + self.assertEqual(unicode_asucs4(s, l, 0), s+'\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 1), s+'\0\uffff') + self.assertEqual(unicode_asucs4(s, l+1, 0), s+'\0\uffff') + self.assertRaises(SystemError, unicode_asucs4, s, l-1, 1) + self.assertRaises(SystemError, unicode_asucs4, s, l-2, 0) + s = '\0'.join([s, s]) + self.assertEqual(unicode_asucs4(s, len(s), 1), s+'\0') + self.assertEqual(unicode_asucs4(s, len(s), 0), s+'\uffff') + + # CRASHES unicode_asucs4(b'abc', 1, 0) + # CRASHES unicode_asucs4(b'abc', 1, 1) + # CRASHES unicode_asucs4([], 1, 1) + # CRASHES unicode_asucs4(NULL, 1, 0) + # CRASHES unicode_asucs4(NULL, 1, 1) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_asucs4copy(self): + """Test PyUnicode_AsUCS4Copy()""" + from _testcapi import unicode_asucs4copy as asucs4copy + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600', + 'a\ud800b\udfffc', '\ud834\udd1e']: + self.assertEqual(asucs4copy(s), s+'\0') s = '\0'.join([s, s]) - self.assertEqual(unicode_asucs4(s, len(s), True), s+'\0') - self.assertEqual(unicode_asucs4(s, len(s), False), s+'\uffff') + self.assertEqual(asucs4copy(s), s+'\0') + + # CRASHES asucs4copy(b'abc') + # CRASHES asucs4copy([]) + # CRASHES asucs4copy(NULL) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_fromordinal(self): + """Test PyUnicode_FromOrdinal()""" + from _testcapi import unicode_fromordinal as fromordinal + + self.assertEqual(fromordinal(0x61), 'a') + self.assertEqual(fromordinal(0x20ac), '\u20ac') + self.assertEqual(fromordinal(0x1f600), '\U0001f600') + + self.assertRaises(ValueError, fromordinal, 0x110000) + self.assertRaises(ValueError, fromordinal, -1) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -381,29 +774,62 @@ def test_asutf8(self): """Test PyUnicode_AsUTF8()""" from _testcapi import unicode_asutf8 - bmp = '\u0100' - bmp2 = '\uffff' - nonbmp = chr(0x10ffff) + self.assertEqual(unicode_asutf8('abc', 4), b'abc\0') + self.assertEqual(unicode_asutf8('???', 7), b'\xd0\xb0\xd0\xb1\xd0\xb2\0') + self.assertEqual(unicode_asutf8('\U0001f600', 5), b'\xf0\x9f\x98\x80\0') + self.assertEqual(unicode_asutf8('abc\0def', 8), b'abc\0def\0') - self.assertEqual(unicode_asutf8(bmp), b'\xc4\x80') - self.assertEqual(unicode_asutf8(bmp2), b'\xef\xbf\xbf') - self.assertEqual(unicode_asutf8(nonbmp), b'\xf4\x8f\xbf\xbf') - self.assertRaises(UnicodeEncodeError, unicode_asutf8, 'a\ud800b\udfffc') + self.assertRaises(UnicodeEncodeError, unicode_asutf8, '\ud8ff', 0) + self.assertRaises(TypeError, unicode_asutf8, b'abc', 0) + self.assertRaises(TypeError, unicode_asutf8, [], 0) + # CRASHES unicode_asutf8(NULL, 0) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') def test_asutf8andsize(self): """Test PyUnicode_AsUTF8AndSize()""" from _testcapi import unicode_asutf8andsize + from _testcapi import unicode_asutf8andsize_null - bmp = '\u0100' - bmp2 = '\uffff' - nonbmp = chr(0x10ffff) + self.assertEqual(unicode_asutf8andsize('abc', 4), (b'abc\0', 3)) + self.assertEqual(unicode_asutf8andsize('???', 7), (b'\xd0\xb0\xd0\xb1\xd0\xb2\0', 6)) + self.assertEqual(unicode_asutf8andsize('\U0001f600', 5), (b'\xf0\x9f\x98\x80\0', 4)) + self.assertEqual(unicode_asutf8andsize('abc\0def', 8), (b'abc\0def\0', 7)) + self.assertEqual(unicode_asutf8andsize_null('abc', 4), b'abc\0') + self.assertEqual(unicode_asutf8andsize_null('abc\0def', 8), b'abc\0def\0') - self.assertEqual(unicode_asutf8andsize(bmp), (b'\xc4\x80', 2)) - self.assertEqual(unicode_asutf8andsize(bmp2), (b'\xef\xbf\xbf', 3)) - self.assertEqual(unicode_asutf8andsize(nonbmp), (b'\xf4\x8f\xbf\xbf', 4)) - self.assertRaises(UnicodeEncodeError, unicode_asutf8andsize, 'a\ud800b\udfffc') + self.assertRaises(UnicodeEncodeError, unicode_asutf8andsize, '\ud8ff', 0) + self.assertRaises(TypeError, unicode_asutf8andsize, b'abc', 0) + self.assertRaises(TypeError, unicode_asutf8andsize, [], 0) + # CRASHES unicode_asutf8andsize(NULL, 0) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_getdefaultencoding(self): + """Test PyUnicode_GetDefaultEncoding()""" + from _testcapi import unicode_getdefaultencoding as getdefaultencoding + + self.assertEqual(getdefaultencoding(), b'utf-8') + + @support.cpython_only + @unittest.skipIf(_testcapi is None, 'need _testcapi module') + def test_transform_decimal_and_space(self): + """Test _PyUnicode_TransformDecimalAndSpaceToASCII()""" + from _testcapi import unicode_transformdecimalandspacetoascii as transform_decimal + + self.assertEqual(transform_decimal('123'), + '123') + self.assertEqual(transform_decimal('\u0663.\u0661\u0664'), + '3.14') + self.assertEqual(transform_decimal("\N{EM SPACE}3.14\N{EN SPACE}"), + " 3.14 ") + self.assertEqual(transform_decimal('12\u20ac3'), + '12?') + self.assertEqual(transform_decimal(''), '') + + self.assertRaises(SystemError, transform_decimal, b'123') + self.assertRaises(SystemError, transform_decimal, []) + # CRASHES transform_decimal(NULL) @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') @@ -858,6 +1284,7 @@ def test_copycharacters(self): from _testcapi import unicode_copycharacters strings = [ + # all strings have exactly 5 characters 'abcde', '\xa1\xa2\xa3\xa4\xa5', '\u4f60\u597d\u4e16\u754c\uff01', '\U0001f600\U0001f601\U0001f602\U0001f603\U0001f604' @@ -894,6 +1321,10 @@ def test_copycharacters(self): self.assertRaises(SystemError, unicode_copycharacters, s, 1, s, 0, 5) self.assertRaises(SystemError, unicode_copycharacters, s, 0, s, 0, -1) self.assertRaises(SystemError, unicode_copycharacters, s, 0, b'', 0, 0) + self.assertRaises(SystemError, unicode_copycharacters, s, 0, [], 0, 0) + # CRASHES unicode_copycharacters(s, 0, NULL, 0, 0) + # TODO: Test PyUnicode_CopyCharacters() with non-unicode and + # non-modifiable unicode as "to". @support.cpython_only @unittest.skipIf(_testcapi is None, 'need _testcapi module') diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 2d23993ce420..7dd3b9c0c03e 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -102,6 +102,278 @@ test_widechar(PyObject *self, PyObject *Py_UNUSED(ignored)) #define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0); +static PyObject * +unicode_copy(PyObject *unicode) +{ + PyObject *copy; + + if (!unicode) { + return NULL; + } + if (!PyUnicode_Check(unicode)) { + Py_INCREF(unicode); + return unicode; + } + + copy = PyUnicode_New(PyUnicode_GET_LENGTH(unicode), + PyUnicode_MAX_CHAR_VALUE(unicode)); + if (!copy) { + return NULL; + } + if (PyUnicode_CopyCharacters(copy, 0, unicode, + 0, PyUnicode_GET_LENGTH(unicode)) < 0) + { + Py_DECREF(copy); + return NULL; + } + return copy; +} + +/* Test PyUnicode_New() */ +static PyObject * +unicode_new(PyObject *self, PyObject *args) +{ + Py_ssize_t size; + unsigned int maxchar; + PyObject *result; + + if (!PyArg_ParseTuple(args, "nI", &size, &maxchar)) { + return NULL; + } + + result = PyUnicode_New(size, (Py_UCS4)maxchar); + if (!result) { + return NULL; + } + if (size > 0 && maxchar <= 0x10ffff && + PyUnicode_Fill(result, 0, size, (Py_UCS4)maxchar) < 0) + { + Py_DECREF(result); + return NULL; + } + return result; +} + +/* Test PyUnicode_Fill() */ +static PyObject * +unicode_fill(PyObject *self, PyObject *args) +{ + PyObject *to, *to_copy; + Py_ssize_t start, length, filled; + unsigned int fill_char; + + if (!PyArg_ParseTuple(args, "OnnI", &to, &start, &length, &fill_char)) { + return NULL; + } + + NULLABLE(to); + if (!(to_copy = unicode_copy(to)) && to) { + return NULL; + } + + filled = PyUnicode_Fill(to_copy, start, length, (Py_UCS4)fill_char); + if (filled == -1 && PyErr_Occurred()) { + Py_DECREF(to_copy); + return NULL; + } + return Py_BuildValue("(Nn)", to_copy, filled); +} + +/* Test PyUnicode_WriteChar() */ +static PyObject * +unicode_writechar(PyObject *self, PyObject *args) +{ + PyObject *to, *to_copy; + Py_ssize_t index; + unsigned int character; + int result; + + if (!PyArg_ParseTuple(args, "OnI", &to, &index, &character)) { + return NULL; + } + + NULLABLE(to); + if (!(to_copy = unicode_copy(to)) && to) { + return NULL; + } + + result = PyUnicode_WriteChar(to_copy, index, (Py_UCS4)character); + if (result == -1 && PyErr_Occurred()) { + Py_DECREF(to_copy); + return NULL; + } + return Py_BuildValue("(Ni)", to_copy, result); +} + +/* Test PyUnicode_Resize() */ +static PyObject * +unicode_resize(PyObject *self, PyObject *args) +{ + PyObject *obj, *copy; + Py_ssize_t length; + int result; + + if (!PyArg_ParseTuple(args, "On", &obj, &length)) { + return NULL; + } + + NULLABLE(obj); + if (!(copy = unicode_copy(obj)) && obj) { + return NULL; + } + result = PyUnicode_Resize(©, length); + if (result == -1 && PyErr_Occurred()) { + Py_XDECREF(copy); + return NULL; + } + if (obj && PyUnicode_Check(obj) && length > PyUnicode_GET_LENGTH(obj)) { + if (PyUnicode_Fill(copy, PyUnicode_GET_LENGTH(obj), length, 0U) < 0) { + Py_DECREF(copy); + return NULL; + } + } + return Py_BuildValue("(Ni)", copy, result); +} + +/* Test PyUnicode_Append() */ +static PyObject * +unicode_append(PyObject *self, PyObject *args) +{ + PyObject *left, *right, *left_copy; + + if (!PyArg_ParseTuple(args, "OO", &left, &right)) + return NULL; + + NULLABLE(left); + NULLABLE(right); + if (!(left_copy = unicode_copy(left)) && left) { + return NULL; + } + PyUnicode_Append(&left_copy, right); + return left_copy; +} + +/* Test PyUnicode_AppendAndDel() */ +static PyObject * +unicode_appendanddel(PyObject *self, PyObject *args) +{ + PyObject *left, *right, *left_copy; + + if (!PyArg_ParseTuple(args, "OO", &left, &right)) + return NULL; + + NULLABLE(left); + NULLABLE(right); + if (!(left_copy = unicode_copy(left)) && left) { + return NULL; + } + Py_XINCREF(right); + PyUnicode_AppendAndDel(&left_copy, right); + return left_copy; +} + +/* Test PyUnicode_FromStringAndSize() */ +static PyObject * +unicode_fromstringandsize(PyObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t bsize; + Py_ssize_t size = -100; + + if (!PyArg_ParseTuple(args, "z#|n", &s, &bsize, &size)) { + return NULL; + } + + if (size == -100) { + size = bsize; + } + return PyUnicode_FromStringAndSize(s, size); +} + +/* Test PyUnicode_FromString() */ +static PyObject * +unicode_fromstring(PyObject *self, PyObject *arg) +{ + const char *s; + Py_ssize_t size; + + if (!PyArg_Parse(arg, "z#", &s, &size)) { + return NULL; + } + return PyUnicode_FromString(s); +} + +/* Test PyUnicode_FromKindAndData() */ +static PyObject * +unicode_fromkindanddata(PyObject *self, PyObject *args) +{ + int kind; + void *buffer; + Py_ssize_t bsize; + Py_ssize_t size = -100; + + if (!PyArg_ParseTuple(args, "iz#|n", &kind, &buffer, &bsize, &size)) { + return NULL; + } + + if (size == -100) { + size = bsize; + } + if (kind && size % kind) { + PyErr_SetString(PyExc_AssertionError, + "invalid size in unicode_fromkindanddata()"); + return NULL; + } + return PyUnicode_FromKindAndData(kind, buffer, kind ? size / kind : 0); +} + +/* Test PyUnicode_Substring() */ +static PyObject * +unicode_substring(PyObject *self, PyObject *args) +{ + PyObject *str; + Py_ssize_t start, end; + + if (!PyArg_ParseTuple(args, "Onn", &str, &start, &end)) { + return NULL; + } + + NULLABLE(str); + return PyUnicode_Substring(str, start, end); +} + +/* Test PyUnicode_GetLength() */ +static PyObject * +unicode_getlength(PyObject *self, PyObject *arg) +{ + Py_ssize_t result; + + NULLABLE(arg); + result = PyUnicode_GetLength(arg); + if (result == -1) + return NULL; + return PyLong_FromSsize_t(result); +} + +/* Test PyUnicode_ReadChar() */ +static PyObject * +unicode_readchar(PyObject *self, PyObject *args) +{ + PyObject *unicode; + Py_ssize_t index; + Py_UCS4 result; + + if (!PyArg_ParseTuple(args, "On", &unicode, &index)) { + return NULL; + } + + NULLABLE(unicode); + result = PyUnicode_ReadChar(unicode, index); + if (result == (Py_UCS4)-1) + return NULL; + return PyLong_FromUnsignedLong(result); +} + /* Test PyUnicode_FromObject() */ static PyObject * unicode_fromobject(PyObject *self, PyObject *arg) @@ -110,6 +382,51 @@ unicode_fromobject(PyObject *self, PyObject *arg) return PyUnicode_FromObject(arg); } +/* Test PyUnicode_InternInPlace() */ +static PyObject * +unicode_interninplace(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + Py_XINCREF(arg); + PyUnicode_InternInPlace(&arg); + return arg; +} + +/* Test PyUnicode_InternFromString() */ +static PyObject * +unicode_internfromstring(PyObject *self, PyObject *arg) +{ + const char *s; + Py_ssize_t size; + + if (!PyArg_Parse(arg, "z#", &s, &size)) { + return NULL; + } + return PyUnicode_InternFromString(s); +} + +/* Test PyUnicode_FromWideChar() */ +static PyObject * +unicode_fromwidechar(PyObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t bsize; + Py_ssize_t size = -100; + + if (!PyArg_ParseTuple(args, "z#|n", &s, &bsize, &size)) { + return NULL; + } + if (size == -100) { + if (bsize % SIZEOF_WCHAR_T) { + PyErr_SetString(PyExc_AssertionError, + "invalid size in unicode_fromwidechar()"); + return NULL; + } + size = bsize / SIZEOF_WCHAR_T; + } + return PyUnicode_FromWideChar((const wchar_t *)s, size); +} + /* Test PyUnicode_AsWideChar() */ static PyObject * unicode_aswidechar(PyObject *self, PyObject *args) @@ -118,8 +435,9 @@ unicode_aswidechar(PyObject *self, PyObject *args) Py_ssize_t buflen, size; wchar_t *buffer; - if (!PyArg_ParseTuple(args, "Un", &unicode, &buflen)) + if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) return NULL; + NULLABLE(unicode); buffer = PyMem_New(wchar_t, buflen); if (buffer == NULL) return PyErr_NoMemory(); @@ -142,17 +460,35 @@ unicode_aswidechar(PyObject *self, PyObject *args) return Py_BuildValue("(Nn)", result, size); } +/* Test PyUnicode_AsWideCharString() with NULL as buffer */ +static PyObject * +unicode_aswidechar_null(PyObject *self, PyObject *args) +{ + PyObject *unicode; + Py_ssize_t buflen, size; + + if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) + return NULL; + NULLABLE(unicode); + size = PyUnicode_AsWideChar(unicode, NULL, buflen); + if (size == -1) { + return NULL; + } + return PyLong_FromSsize_t(size); +} + /* Test PyUnicode_AsWideCharString() */ static PyObject * unicode_aswidecharstring(PyObject *self, PyObject *args) { PyObject *unicode, *result; - Py_ssize_t size; + Py_ssize_t size = 100; wchar_t *buffer; - if (!PyArg_ParseTuple(args, "U", &unicode)) + if (!PyArg_ParseTuple(args, "O", &unicode)) return NULL; + NULLABLE(unicode); buffer = PyUnicode_AsWideCharString(unicode, &size); if (buffer == NULL) return NULL; @@ -164,6 +500,28 @@ unicode_aswidecharstring(PyObject *self, PyObject *args) return Py_BuildValue("(Nn)", result, size); } +/* Test PyUnicode_AsWideCharString() with NULL as the size address */ +static PyObject * +unicode_aswidecharstring_null(PyObject *self, PyObject *args) +{ + PyObject *unicode, *result; + wchar_t *buffer; + + if (!PyArg_ParseTuple(args, "O", &unicode)) + return NULL; + + NULLABLE(unicode); + buffer = PyUnicode_AsWideCharString(unicode, NULL); + if (buffer == NULL) + return NULL; + + result = PyUnicode_FromWideChar(buffer, -1); + PyMem_Free(buffer); + if (result == NULL) + return NULL; + return result; +} + /* Test PyUnicode_AsUCS4() */ static PyObject * unicode_asucs4(PyObject *self, PyObject *args) @@ -173,10 +531,11 @@ unicode_asucs4(PyObject *self, PyObject *args) int copy_null; Py_ssize_t str_len, buf_len; - if (!PyArg_ParseTuple(args, "Unp:unicode_asucs4", &unicode, &str_len, ©_null)) { + if (!PyArg_ParseTuple(args, "Onp:unicode_asucs4", &unicode, &str_len, ©_null)) { return NULL; } + NULLABLE(unicode); buf_len = str_len + 1; buffer = PyMem_NEW(Py_UCS4, buf_len); if (buffer == NULL) { @@ -195,48 +554,117 @@ unicode_asucs4(PyObject *self, PyObject *args) return result; } -/* Test PyUnicode_AsUTF8() */ +/* Test PyUnicode_AsUCS4Copy() */ static PyObject * -unicode_asutf8(PyObject *self, PyObject *args) +unicode_asucs4copy(PyObject *self, PyObject *args) { PyObject *unicode; - const char *buffer; + Py_UCS4 *buffer; + PyObject *result; - if (!PyArg_ParseTuple(args, "U", &unicode)) { + if (!PyArg_ParseTuple(args, "O", &unicode)) { return NULL; } - buffer = PyUnicode_AsUTF8(unicode); + NULLABLE(unicode); + buffer = PyUnicode_AsUCS4Copy(unicode); if (buffer == NULL) { return NULL; } + result = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, + buffer, + PyUnicode_GET_LENGTH(unicode) + 1); + PyMem_FREE(buffer); + return result; +} + +/* Test PyUnicode_FromOrdinal() */ +static PyObject * +unicode_fromordinal(PyObject *self, PyObject *args) +{ + int ordinal; + + if (!PyArg_ParseTuple(args, "i", &ordinal)) + return NULL; - return PyBytes_FromString(buffer); + return PyUnicode_FromOrdinal(ordinal); +} + +/* Test PyUnicode_AsUTF8() */ +static PyObject * +unicode_asutf8(PyObject *self, PyObject *args) +{ + PyObject *unicode; + Py_ssize_t buflen; + const char *s; + + if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) + return NULL; + + NULLABLE(unicode); + s = PyUnicode_AsUTF8(unicode); + if (s == NULL) + return NULL; + + return PyBytes_FromStringAndSize(s, buflen); } /* Test PyUnicode_AsUTF8AndSize() */ static PyObject * unicode_asutf8andsize(PyObject *self, PyObject *args) { - PyObject *unicode, *result; - const char *buffer; - Py_ssize_t utf8_len; + PyObject *unicode; + Py_ssize_t buflen; + const char *s; + Py_ssize_t size = -100; - if(!PyArg_ParseTuple(args, "U", &unicode)) { + if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) return NULL; - } - buffer = PyUnicode_AsUTF8AndSize(unicode, &utf8_len); - if (buffer == NULL) { + NULLABLE(unicode); + s = PyUnicode_AsUTF8AndSize(unicode, &size); + if (s == NULL) return NULL; - } - result = PyBytes_FromString(buffer); - if (result == NULL) { + return Py_BuildValue("(y#n)", s, buflen, size); +} + +/* Test PyUnicode_AsUTF8AndSize() with NULL as the size address */ +static PyObject * +unicode_asutf8andsize_null(PyObject *self, PyObject *args) +{ + PyObject *unicode; + Py_ssize_t buflen; + const char *s; + + if (!PyArg_ParseTuple(args, "On", &unicode, &buflen)) return NULL; - } - return Py_BuildValue("(Nn)", result, utf8_len); + NULLABLE(unicode); + s = PyUnicode_AsUTF8AndSize(unicode, NULL); + if (s == NULL) + return NULL; + + return PyBytes_FromStringAndSize(s, buflen); +} + +/* Test PyUnicode_GetDefaultEncoding() */ +static PyObject * +unicode_getdefaultencoding(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + const char *s = PyUnicode_GetDefaultEncoding(); + if (s == NULL) + return NULL; + + return PyBytes_FromString(s); +} + +/* Test _PyUnicode_TransformDecimalAndSpaceToASCII() */ +static PyObject * +unicode_transformdecimalandspacetoascii(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return _PyUnicode_TransformDecimalAndSpaceToASCII(arg); } /* Test PyUnicode_DecodeUTF8() */ @@ -470,11 +898,11 @@ unicode_findchar(PyObject *self, PyObject *args) Py_ssize_t result; Py_ssize_t start, end; - if (!PyArg_ParseTuple(args, "UInni:unicode_findchar", &str, &ch, + if (!PyArg_ParseTuple(args, "OInni:unicode_findchar", &str, &ch, &start, &end, &direction)) { return NULL; } - + NULLABLE(str); result = PyUnicode_FindChar(str, (Py_UCS4)ch, start, end, direction); if (result == -2) return NULL; @@ -612,11 +1040,12 @@ unicode_copycharacters(PyObject *self, PyObject *args) PyObject *from, *to, *to_copy; Py_ssize_t from_start, to_start, how_many, copied; - if (!PyArg_ParseTuple(args, "UnOnn:unicode_copycharacters", &to, &to_start, + if (!PyArg_ParseTuple(args, "UnOnn", &to, &to_start, &from, &from_start, &how_many)) { return NULL; } + NULLABLE(from); if (!(to_copy = PyUnicode_New(PyUnicode_GET_LENGTH(to), PyUnicode_MAX_CHAR_VALUE(to)))) { return NULL; @@ -626,8 +1055,9 @@ unicode_copycharacters(PyObject *self, PyObject *args) return NULL; } - if ((copied = PyUnicode_CopyCharacters(to_copy, to_start, from, - from_start, how_many)) < 0) { + copied = PyUnicode_CopyCharacters(to_copy, to_start, from, + from_start, how_many); + if (copied == -1 && PyErr_Occurred()) { Py_DECREF(to_copy); return NULL; } @@ -1053,14 +1483,36 @@ static PyMethodDef TestMethods[] = { test_unicode_compare_with_ascii, METH_NOARGS}, {"test_string_from_format", test_string_from_format, METH_NOARGS}, {"test_widechar", test_widechar, METH_NOARGS}, + {"unicode_new", unicode_new, METH_VARARGS}, + {"unicode_fill", unicode_fill, METH_VARARGS}, + {"unicode_writechar", unicode_writechar, METH_VARARGS}, + {"unicode_resize", unicode_resize, METH_VARARGS}, + {"unicode_append", unicode_append, METH_VARARGS}, + {"unicode_appendanddel", unicode_appendanddel, METH_VARARGS}, + {"unicode_fromstringandsize",unicode_fromstringandsize, METH_VARARGS}, + {"unicode_fromstring", unicode_fromstring, METH_O}, + {"unicode_fromkindanddata", unicode_fromkindanddata, METH_VARARGS}, + {"unicode_substring", unicode_substring, METH_VARARGS}, + {"unicode_getlength", unicode_getlength, METH_O}, + {"unicode_readchar", unicode_readchar, METH_VARARGS}, {"unicode_fromobject", unicode_fromobject, METH_O}, + {"unicode_interninplace", unicode_interninplace, METH_O}, + {"unicode_internfromstring", unicode_internfromstring, METH_O}, + {"unicode_fromwidechar", unicode_fromwidechar, METH_VARARGS}, {"unicode_aswidechar", unicode_aswidechar, METH_VARARGS}, + {"unicode_aswidechar_null", unicode_aswidechar_null, METH_VARARGS}, {"unicode_aswidecharstring", unicode_aswidecharstring, METH_VARARGS}, + {"unicode_aswidecharstring_null",unicode_aswidecharstring_null,METH_VARARGS}, {"unicode_asucs4", unicode_asucs4, METH_VARARGS}, + {"unicode_asucs4copy", unicode_asucs4copy, METH_VARARGS}, + {"unicode_fromordinal", unicode_fromordinal, METH_VARARGS}, {"unicode_asutf8", unicode_asutf8, METH_VARARGS}, {"unicode_asutf8andsize", unicode_asutf8andsize, METH_VARARGS}, + {"unicode_asutf8andsize_null",unicode_asutf8andsize_null, METH_VARARGS}, {"unicode_decodeutf8", unicode_decodeutf8, METH_VARARGS}, {"unicode_decodeutf8stateful",unicode_decodeutf8stateful, METH_VARARGS}, + {"unicode_getdefaultencoding",unicode_getdefaultencoding, METH_NOARGS}, + {"unicode_transformdecimalandspacetoascii", unicode_transformdecimalandspacetoascii, METH_O}, {"unicode_concat", unicode_concat, METH_VARARGS}, {"unicode_splitlines", unicode_splitlines, METH_VARARGS}, {"unicode_split", unicode_split, METH_VARARGS}, diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 38f4758e6575..ae70a33eb4d1 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4247,6 +4247,7 @@ PyInit__testcapi(void) PyModule_AddObject(m, "ULLONG_MAX", PyLong_FromUnsignedLongLong(ULLONG_MAX)); PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyLong_FromSsize_t(PY_SSIZE_T_MAX)); PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyLong_FromSsize_t(PY_SSIZE_T_MIN)); + PyModule_AddObject(m, "SIZEOF_WCHAR_T", PyLong_FromSsize_t(sizeof(wchar_t))); PyModule_AddObject(m, "SIZEOF_TIME_T", PyLong_FromSsize_t(sizeof(time_t))); PyModule_AddObject(m, "Py_Version", PyLong_FromUnsignedLong(Py_Version)); Py_INCREF(&PyInstanceMethod_Type); From webhook-mailer at python.org Thu May 4 12:40:13 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 04 May 2023 16:40:13 -0000 Subject: [Python-checkins] gh-91896: Deprecate collections.abc.ByteString (#102096) Message-ID: <mailman.165.1683218413.13550.python-checkins@python.org> https://github.com/python/cpython/commit/09b7695f12f2b44d2df6898407d7e68dd9493ed4 commit: 09b7695f12f2b44d2df6898407d7e68dd9493ed4 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-04T09:39:33-07:00 summary: gh-91896: Deprecate collections.abc.ByteString (#102096) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst M Doc/library/collections.abc.rst M Doc/library/typing.rst M Doc/whatsnew/3.12.rst M Lib/_collections_abc.py M Lib/test/test_collections.py diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 669b7345499a..43a3286ba832 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -273,6 +273,12 @@ Collections Abstract Base Classes -- Detailed Descriptions The index() method added support for *stop* and *start* arguments. + .. deprecated-removed:: 3.12 3.14 + The :class:`ByteString` ABC has been deprecated. + For use in typing, prefer a union, like ``bytes | bytearray``, or + :class:`collections.abc.Buffer`. + For use as an ABC, prefer :class:`Sequence` or :class:`collections.abc.Buffer`. + .. class:: Set MutableSet diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c22fc0b28a50..162041fc7a84 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2139,8 +2139,7 @@ Corresponding to collections in :mod:`collections.abc` annotate arguments of any of the types mentioned above. .. deprecated:: 3.9 - :class:`collections.abc.ByteString` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3fe3310a26e5..4a988bf4b993 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -792,6 +792,11 @@ Pending Removal in Python 3.14 (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) +* Deprecated :class:`collections.abc.ByteString`. + Prefer :class:`Sequence` or :class:`collections.abc.Buffer`. + For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. + (Contributed by Shantanu Jain in :gh:`91896`.) + * Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases using the C API. diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index 2117190cf8b6..601107d2d867 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -1071,8 +1071,27 @@ def count(self, value): Sequence.register(range) Sequence.register(memoryview) - -class ByteString(Sequence): +class _DeprecateByteStringMeta(ABCMeta): + def __new__(cls, name, bases, namespace, **kwargs): + if name != "ByteString": + import warnings + + warnings._deprecated( + "collections.abc.ByteString", + remove=(3, 14), + ) + return super().__new__(cls, name, bases, namespace, **kwargs) + + def __instancecheck__(cls, instance): + import warnings + + warnings._deprecated( + "collections.abc.ByteString", + remove=(3, 14), + ) + return super().__instancecheck__(instance) + +class ByteString(Sequence, metaclass=_DeprecateByteStringMeta): """This unifies bytes and bytearray. XXX Should add all their methods. diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 8fc28a6bf98e..bb8b352518ef 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1940,14 +1940,25 @@ def assert_index_same(seq1, seq2, index_args): def test_ByteString(self): for sample in [bytes, bytearray]: - self.assertIsInstance(sample(), ByteString) + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(sample(), ByteString) self.assertTrue(issubclass(sample, ByteString)) for sample in [str, list, tuple]: - self.assertNotIsInstance(sample(), ByteString) + with self.assertWarns(DeprecationWarning): + self.assertNotIsInstance(sample(), ByteString) self.assertFalse(issubclass(sample, ByteString)) - self.assertNotIsInstance(memoryview(b""), ByteString) + with self.assertWarns(DeprecationWarning): + self.assertNotIsInstance(memoryview(b""), ByteString) self.assertFalse(issubclass(memoryview, ByteString)) - self.validate_abstract_methods(ByteString, '__getitem__', '__len__') + with self.assertWarns(DeprecationWarning): + self.validate_abstract_methods(ByteString, '__getitem__', '__len__') + + with self.assertWarns(DeprecationWarning): + class X(ByteString): pass + + with self.assertWarns(DeprecationWarning): + # No metaclass conflict + class Z(ByteString, Awaitable): pass def test_Buffer(self): for sample in [bytes, bytearray, memoryview]: diff --git a/Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst b/Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst new file mode 100644 index 000000000000..b5282d3d6129 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst @@ -0,0 +1 @@ +Deprecate :class:`collections.abc.ByteString` From webhook-mailer at python.org Thu May 4 12:44:43 2023 From: webhook-mailer at python.org (barneygale) Date: Thu, 04 May 2023 16:44:43 -0000 Subject: [Python-checkins] GH-81079: Add case_sensitive argument to `pathlib.Path.glob()` (GH-102710) Message-ID: <mailman.166.1683218684.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8100be5535073a5442c2b8c68dcb2093ee69433d commit: 8100be5535073a5442c2b8c68dcb2093ee69433d branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-04T16:44:36Z summary: GH-81079: Add case_sensitive argument to `pathlib.Path.glob()` (GH-102710) This argument allows case-sensitive matching to be enabled on Windows, and case-insensitive matching to be enabled on Posix. Co-authored-by: Steve Dower <steve.dower at microsoft.com> files: A Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst M Doc/library/pathlib.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 4847ac24c775..14118127835b 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -855,7 +855,7 @@ call fails (for example because the path doesn't exist). .. versionadded:: 3.5 -.. method:: Path.glob(pattern) +.. method:: Path.glob(pattern, *, case_sensitive=None) Glob the given relative *pattern* in the directory represented by this path, yielding all matching files (of any kind):: @@ -876,6 +876,11 @@ call fails (for example because the path doesn't exist). PosixPath('setup.py'), PosixPath('test_pathlib.py')] + By default, or when the *case_sensitive* keyword-only argument is set to + ``None``, this method matches paths using platform-specific casing rules: + typically, case-sensitive on POSIX, and case-insensitive on Windows. + Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. + .. note:: Using the "``**``" pattern in large directory trees may consume an inordinate amount of time. @@ -886,6 +891,9 @@ call fails (for example because the path doesn't exist). Return only directories if *pattern* ends with a pathname components separator (:data:`~os.sep` or :data:`~os.altsep`). + .. versionadded:: 3.12 + The *case_sensitive* argument. + .. method:: Path.group() Return the name of the group owning the file. :exc:`KeyError` is raised @@ -1271,7 +1279,7 @@ call fails (for example because the path doesn't exist). .. versionadded:: 3.6 The *strict* argument (pre-3.6 behavior is strict). -.. method:: Path.rglob(pattern) +.. method:: Path.rglob(pattern, *, case_sensitive=None) Glob the given relative *pattern* recursively. This is like calling :func:`Path.glob` with "``**/``" added in front of the *pattern*, where @@ -1284,12 +1292,20 @@ call fails (for example because the path doesn't exist). PosixPath('setup.py'), PosixPath('test_pathlib.py')] + By default, or when the *case_sensitive* keyword-only argument is set to + ``None``, this method matches paths using platform-specific casing rules: + typically, case-sensitive on POSIX, and case-insensitive on Windows. + Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. + .. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob .. versionchanged:: 3.11 Return only directories if *pattern* ends with a pathname components separator (:data:`~os.sep` or :data:`~os.altsep`). + .. versionadded:: 3.12 + The *case_sensitive* argument. + .. method:: Path.rmdir() Remove this directory. The directory must be empty. diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 8a1651c23d7f..f32e1e2d8228 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -62,7 +62,7 @@ def _is_case_sensitive(flavour): # @functools.lru_cache() -def _make_selector(pattern_parts, flavour): +def _make_selector(pattern_parts, flavour, case_sensitive): pat = pattern_parts[0] child_parts = pattern_parts[1:] if not pat: @@ -75,17 +75,17 @@ def _make_selector(pattern_parts, flavour): raise ValueError("Invalid pattern: '**' can only be an entire path component") else: cls = _WildcardSelector - return cls(pat, child_parts, flavour) + return cls(pat, child_parts, flavour, case_sensitive) class _Selector: """A selector matches a specific glob pattern part against the children of a given path.""" - def __init__(self, child_parts, flavour): + def __init__(self, child_parts, flavour, case_sensitive): self.child_parts = child_parts if child_parts: - self.successor = _make_selector(child_parts, flavour) + self.successor = _make_selector(child_parts, flavour, case_sensitive) self.dironly = True else: self.successor = _TerminatingSelector() @@ -108,8 +108,9 @@ def _select_from(self, parent_path, scandir): class _ParentSelector(_Selector): - def __init__(self, name, child_parts, flavour): - _Selector.__init__(self, child_parts, flavour) + + def __init__(self, name, child_parts, flavour, case_sensitive): + _Selector.__init__(self, child_parts, flavour, case_sensitive) def _select_from(self, parent_path, scandir): path = parent_path._make_child_relpath('..') @@ -119,10 +120,13 @@ def _select_from(self, parent_path, scandir): class _WildcardSelector(_Selector): - def __init__(self, pat, child_parts, flavour): - flags = re.NOFLAG if _is_case_sensitive(flavour) else re.IGNORECASE + def __init__(self, pat, child_parts, flavour, case_sensitive): + _Selector.__init__(self, child_parts, flavour, case_sensitive) + if case_sensitive is None: + # TODO: evaluate case-sensitivity of each directory in _select_from() + case_sensitive = _is_case_sensitive(flavour) + flags = re.NOFLAG if case_sensitive else re.IGNORECASE self.match = re.compile(fnmatch.translate(pat), flags=flags).fullmatch - _Selector.__init__(self, child_parts, flavour) def _select_from(self, parent_path, scandir): try: @@ -153,8 +157,8 @@ def _select_from(self, parent_path, scandir): class _RecursiveWildcardSelector(_Selector): - def __init__(self, pat, child_parts, flavour): - _Selector.__init__(self, child_parts, flavour) + def __init__(self, pat, child_parts, flavour, case_sensitive): + _Selector.__init__(self, child_parts, flavour, case_sensitive) def _iterate_directories(self, parent_path, scandir): yield parent_path @@ -819,7 +823,7 @@ def _scandir(self): # includes scandir(), which is used to implement glob(). return os.scandir(self) - def glob(self, pattern): + def glob(self, pattern, *, case_sensitive=None): """Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern. """ @@ -831,11 +835,11 @@ def glob(self, pattern): raise NotImplementedError("Non-relative patterns are unsupported") if pattern[-1] in (self._flavour.sep, self._flavour.altsep): pattern_parts.append('') - selector = _make_selector(tuple(pattern_parts), self._flavour) + selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive) for p in selector.select_from(self): yield p - def rglob(self, pattern): + def rglob(self, pattern, *, case_sensitive=None): """Recursively yield all existing files (of any kind, including directories) matching the given relative pattern, anywhere in this subtree. @@ -846,7 +850,7 @@ def rglob(self, pattern): raise NotImplementedError("Non-relative patterns are unsupported") if pattern and pattern[-1] in (self._flavour.sep, self._flavour.altsep): pattern_parts.append('') - selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour) + selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour, case_sensitive) for p in selector.select_from(self): yield p diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 424bb92a87d1..a932e03df423 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1816,6 +1816,18 @@ def _check(glob, expected): else: _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"]) + def test_glob_case_sensitive(self): + P = self.cls + def _check(path, pattern, case_sensitive, expected): + actual = {str(q) for q in path.glob(pattern, case_sensitive=case_sensitive)} + expected = {str(P(BASE, q)) for q in expected} + self.assertEqual(actual, expected) + path = P(BASE) + _check(path, "DIRB/FILE*", True, []) + _check(path, "DIRB/FILE*", False, ["dirB/fileB"]) + _check(path, "dirb/file*", True, []) + _check(path, "dirb/file*", False, ["dirB/fileB"]) + def test_rglob_common(self): def _check(glob, expected): self.assertEqual(set(glob), { P(BASE, q) for q in expected }) diff --git a/Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst b/Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst new file mode 100644 index 000000000000..ef5690533985 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst @@ -0,0 +1,2 @@ +Add *case_sensitive* keyword-only argument to :meth:`pathlib.Path.glob` and +:meth:`~pathlib.Path.rglob`. From webhook-mailer at python.org Thu May 4 12:55:56 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 04 May 2023 16:55:56 -0000 Subject: [Python-checkins] gh-102500: Add PEP 688 and 698 to the 3.12 release highlights (#104174) Message-ID: <mailman.167.1683219357.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d47cddfa27cbcbeb4dddb9263976d85c41241672 commit: d47cddfa27cbcbeb4dddb9263976d85c41241672 branch: main author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-04T19:55:48+03:00 summary: gh-102500: Add PEP 688 and 698 to the 3.12 release highlights (#104174) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4a988bf4b993..4f952e2a37ef 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -68,13 +68,17 @@ Summary -- Release highlights New typing features: +* :pep:`688`: Making the buffer protocol accessible in Python + * :ref:`whatsnew312-pep692` +* :pep:`698`: Override Decorator for Static Typing + Important deprecations, removals or restrictions: -* :pep:`623`, Remove wstr from Unicode +* :pep:`623`: Remove wstr from Unicode -* :pep:`632`, Remove the ``distutils`` package. +* :pep:`632`: Remove the ``distutils`` package Improved Error Messages ======================= From webhook-mailer at python.org Thu May 4 13:46:03 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 04 May 2023 17:46:03 -0000 Subject: [Python-checkins] gh-103963: fix 'make regen-opcode' in out-of-tree builds (#104177) Message-ID: <mailman.168.1683222364.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f5c38382f9c40f0017cef086896a8160e313ac9e commit: f5c38382f9c40f0017cef086896a8160e313ac9e branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-04T17:45:56Z summary: gh-103963: fix 'make regen-opcode' in out-of-tree builds (#104177) files: M Makefile.pre.in M PCbuild/regen.targets M Tools/build/generate_opcode_h.py diff --git a/Makefile.pre.in b/Makefile.pre.in index b285ef9e832d..736a520d0e8f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1376,9 +1376,11 @@ regen-opcode: $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_opcode_h.py \ $(srcdir)/Lib/opcode.py \ $(srcdir)/Include/opcode.h.new \ - $(srcdir)/Include/internal/pycore_opcode.h.new + $(srcdir)/Include/internal/pycore_opcode.h.new \ + $(srcdir)/Include/internal/pycore_intrinsics.h.new $(UPDATE_FILE) $(srcdir)/Include/opcode.h $(srcdir)/Include/opcode.h.new $(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode.h $(srcdir)/Include/internal/pycore_opcode.h.new + $(UPDATE_FILE) $(srcdir)/Include/internal/pycore_intrinsics.h $(srcdir)/Include/internal/pycore_intrinsics.h.new .PHONY: regen-token regen-token: diff --git a/PCbuild/regen.targets b/PCbuild/regen.targets index aeb7e2e185d9..107066817ba6 100644 --- a/PCbuild/regen.targets +++ b/PCbuild/regen.targets @@ -59,7 +59,7 @@ Inputs="@(_OpcodeSources)" Outputs="@(_OpcodeOutputs)" DependsOnTargets="FindPythonForBuild"> <Message Text="Regenerate @(_OpcodeOutputs->'%(Filename)%(Extension)',' ')" Importance="high" /> - <Exec Command="$(PythonForBuild) Tools\build\generate_opcode_h.py Lib\opcode.py Include\opcode.h Include\internal\pycore_opcode.h" + <Exec Command="$(PythonForBuild) Tools\build\generate_opcode_h.py Lib\opcode.py Include\opcode.h Include\internal\pycore_opcode.h Include\internal\pycore_intrinsics.h" WorkingDirectory="$(PySourcePath)" /> <Exec Command="$(PythonForBuild) Python\makeopcodetargets.py Python\opcode_targets.h" WorkingDirectory="$(PySourcePath)" /> diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index adcbaf2b8e08..5be981005725 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -233,4 +233,4 @@ def main(opcode_py, outfile='Include/opcode.h', if __name__ == '__main__': - main(sys.argv[1], sys.argv[2], sys.argv[3]) + main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]) From webhook-mailer at python.org Thu May 4 18:07:54 2023 From: webhook-mailer at python.org (brandtbucher) Date: Thu, 04 May 2023 22:07:54 -0000 Subject: [Python-checkins] GH-103899: Provide a hint when accidentally calling a module (GH-103900) Message-ID: <mailman.169.1683238074.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7d35c3121ade679dd6e8b4a0bac7b3702aee6921 commit: 7d35c3121ade679dd6e8b4a0bac7b3702aee6921 branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-04T15:07:42-07:00 summary: GH-103899: Provide a hint when accidentally calling a module (GH-103900) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst M Lib/test/test_call.py M Objects/call.c diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index aab7b1580eaf..12759c53bb66 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -10,6 +10,7 @@ import gc import contextlib import sys +import types class BadStr(str): @@ -202,6 +203,37 @@ def test_oldargs1_2_kw(self): msg = r"count\(\) takes no keyword arguments" self.assertRaisesRegex(TypeError, msg, [].count, x=2, y=2) + def test_object_not_callable(self): + msg = r"^'object' object is not callable$" + self.assertRaisesRegex(TypeError, msg, object()) + + def test_module_not_callable_no_suggestion_0(self): + msg = r"^'module' object is not callable$" + self.assertRaisesRegex(TypeError, msg, types.ModuleType("mod")) + + def test_module_not_callable_no_suggestion_1(self): + msg = r"^'module' object is not callable$" + mod = types.ModuleType("mod") + mod.mod = 42 + self.assertRaisesRegex(TypeError, msg, mod) + + def test_module_not_callable_no_suggestion_2(self): + msg = r"^'module' object is not callable$" + mod = types.ModuleType("mod") + del mod.__name__ + self.assertRaisesRegex(TypeError, msg, mod) + + def test_module_not_callable_no_suggestion_3(self): + msg = r"^'module' object is not callable$" + mod = types.ModuleType("mod") + mod.__name__ = 42 + self.assertRaisesRegex(TypeError, msg, mod) + + def test_module_not_callable_suggestion(self): + msg = r"^'module' object is not callable\. Did you mean: 'mod\.mod\(\.\.\.\)'\?$" + mod = types.ModuleType("mod") + mod.mod = lambda: ... + self.assertRaisesRegex(TypeError, msg, mod) class TestCallingConventions(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst new file mode 100644 index 000000000000..c12a6b9cb841 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst @@ -0,0 +1,3 @@ +Provide a helpful hint in the :exc:`TypeError` message when accidentally +calling a :term:`module` object that has a callable attribute of the same +name (such as :func:`dis.dis` or :class:`datetime.datetime`). diff --git a/Objects/call.c b/Objects/call.c index cf6e357a9904..0d548dcd5e1a 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -157,6 +157,42 @@ PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, return _PyObject_FastCallDictTstate(tstate, callable, args, nargsf, kwargs); } +static void +object_is_not_callable(PyThreadState *tstate, PyObject *callable) +{ + if (Py_IS_TYPE(callable, &PyModule_Type)) { + // >>> import pprint + // >>> pprint(thing) + // Traceback (most recent call last): + // File "<stdin>", line 1, in <module> + // TypeError: 'module' object is not callable. Did you mean: 'pprint.pprint(...)'? + PyObject *name = PyModule_GetNameObject(callable); + if (name == NULL) { + _PyErr_Clear(tstate); + goto basic_type_error; + } + PyObject *attr; + int res = _PyObject_LookupAttr(callable, name, &attr); + if (res < 0) { + _PyErr_Clear(tstate); + } + else if (res > 0 && PyCallable_Check(attr)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object is not callable. " + "Did you mean: '%U.%U(...)'?", + Py_TYPE(callable)->tp_name, name, name); + Py_DECREF(attr); + Py_DECREF(name); + return; + } + Py_XDECREF(attr); + Py_DECREF(name); + } +basic_type_error: + _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object is not callable", + Py_TYPE(callable)->tp_name); +} + PyObject * _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, @@ -171,9 +207,7 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, * temporary dictionary for keyword arguments (if any) */ ternaryfunc call = Py_TYPE(callable)->tp_call; if (call == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not callable", - Py_TYPE(callable)->tp_name); + object_is_not_callable(tstate, callable); return NULL; } @@ -322,9 +356,7 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable, else { call = Py_TYPE(callable)->tp_call; if (call == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not callable", - Py_TYPE(callable)->tp_name); + object_is_not_callable(tstate, callable); return NULL; } From webhook-mailer at python.org Thu May 4 18:37:45 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 04 May 2023 22:37:45 -0000 Subject: [Python-checkins] gh-68968: Correcting message display issue with assertEqual (#103937) Message-ID: <mailman.170.1683239866.13550.python-checkins@python.org> https://github.com/python/cpython/commit/46361bb84332800bc3632688e6ef3b4dd4a48723 commit: 46361bb84332800bc3632688e6ef3b4dd4a48723 branch: main author: Michael Blahay <mblahay at users.noreply.github.com> committer: carljm <carl at oddbird.net> date: 2023-05-04T16:37:17-06:00 summary: gh-68968: Correcting message display issue with assertEqual (#103937) files: A Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst M Lib/test/test_unittest/test_assertions.py M Lib/test/test_unittest/test_case.py M Lib/unittest/case.py diff --git a/Lib/test/test_unittest/test_assertions.py b/Lib/test/test_unittest/test_assertions.py index 6557104b81fc..5c1a28ecda5b 100644 --- a/Lib/test/test_unittest/test_assertions.py +++ b/Lib/test/test_unittest/test_assertions.py @@ -273,9 +273,9 @@ def testAssertDictEqual(self): def testAssertMultiLineEqual(self): self.assertMessages('assertMultiLineEqual', ("", "foo"), - [r"\+ foo$", "^oops$", - r"\+ foo$", - r"\+ foo : oops$"]) + [r"\+ foo\n$", "^oops$", + r"\+ foo\n$", + r"\+ foo\n : oops$"]) def testAssertLess(self): self.assertMessages('assertLess', (2, 1), diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py index dd5ff6d553e6..ed5eb5609a5d 100644 --- a/Lib/test/test_unittest/test_case.py +++ b/Lib/test/test_unittest/test_case.py @@ -1149,6 +1149,66 @@ def testAssertEqualSingleLine(self): error = str(e).split('\n', 1)[1] self.assertEqual(sample_text_error, error) + def testAssertEqualwithEmptyString(self): + '''Verify when there is an empty string involved, the diff output + does not treat the empty string as a single empty line. It should + instead be handled as a non-line. + ''' + sample_text = '' + revised_sample_text = 'unladen swallows fly quickly' + sample_text_error = '''\ ++ unladen swallows fly quickly +''' + try: + self.assertEqual(sample_text, revised_sample_text) + except self.failureException as e: + # need to remove the first line of the error message + error = str(e).split('\n', 1)[1] + self.assertEqual(sample_text_error, error) + + def testAssertEqualMultipleLinesMissingNewlineTerminator(self): + '''Verifying format of diff output from assertEqual involving strings + with multiple lines, but missing the terminating newline on both. + ''' + sample_text = 'laden swallows\nfly sloely' + revised_sample_text = 'laden swallows\nfly slowly' + sample_text_error = '''\ + laden swallows +- fly sloely +? ^ ++ fly slowly +? ^ +''' + try: + self.assertEqual(sample_text, revised_sample_text) + except self.failureException as e: + # need to remove the first line of the error message + error = str(e).split('\n', 1)[1] + self.assertEqual(sample_text_error, error) + + def testAssertEqualMultipleLinesMismatchedNewlinesTerminators(self): + '''Verifying format of diff output from assertEqual involving strings + with multiple lines and mismatched newlines. The output should + include a - on it's own line to indicate the newline difference + between the two strings + ''' + sample_text = 'laden swallows\nfly sloely\n' + revised_sample_text = 'laden swallows\nfly slowly' + sample_text_error = '''\ + laden swallows +- fly sloely +? ^ ++ fly slowly +? ^ +-\x20 +''' + try: + self.assertEqual(sample_text, revised_sample_text) + except self.failureException as e: + # need to remove the first line of the error message + error = str(e).split('\n', 1)[1] + self.assertEqual(sample_text_error, error) + def testEqualityBytesWarning(self): if sys.flags.bytes_warning: def bytes_warning(): diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index 018f22e7ce0c..001b640dc43a 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -1217,19 +1217,34 @@ def assertCountEqual(self, first, second, msg=None): def assertMultiLineEqual(self, first, second, msg=None): """Assert that two multi-line strings are equal.""" - self.assertIsInstance(first, str, 'First argument is not a string') - self.assertIsInstance(second, str, 'Second argument is not a string') + self.assertIsInstance(first, str, "First argument is not a string") + self.assertIsInstance(second, str, "Second argument is not a string") if first != second: - # don't use difflib if the strings are too long + # Don't use difflib if the strings are too long if (len(first) > self._diffThreshold or len(second) > self._diffThreshold): self._baseAssertEqual(first, second, msg) - firstlines = first.splitlines(keepends=True) - secondlines = second.splitlines(keepends=True) - if len(firstlines) == 1 and first.strip('\r\n') == first: - firstlines = [first + '\n'] - secondlines = [second + '\n'] + + # Append \n to both strings if either is missing the \n. + # This allows the final ndiff to show the \n difference. The + # exception here is if the string is empty, in which case no + # \n should be added + first_presplit = first + second_presplit = second + if first and second: + if first[-1] != '\n' or second[-1] != '\n': + first_presplit += '\n' + second_presplit += '\n' + elif second and second[-1] != '\n': + second_presplit += '\n' + elif first and first[-1] != '\n': + first_presplit += '\n' + + firstlines = first_presplit.splitlines(keepends=True) + secondlines = second_presplit.splitlines(keepends=True) + + # Generate the message and diff, then raise the exception standardMsg = '%s != %s' % _common_shorten_repr(first, second) diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines)) standardMsg = self._truncateMessage(standardMsg, diff) diff --git a/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst b/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst new file mode 100644 index 000000000000..bf29b64793b9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst @@ -0,0 +1 @@ +Fixed garbled output of :meth:`~unittest.TestCase.assertEqual` when an input lacks final newline. From webhook-mailer at python.org Thu May 4 18:38:59 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 04 May 2023 22:38:59 -0000 Subject: [Python-checkins] gh-104112: link from cached_property docs to method-caching FAQ (#104113) Message-ID: <mailman.171.1683239940.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fa86a77589a06661fcebb806d36f3a7450e2aecf commit: fa86a77589a06661fcebb806d36f3a7450e2aecf branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-04T16:38:53-06:00 summary: gh-104112: link from cached_property docs to method-caching FAQ (#104113) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/functools.rst diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 29cbc87bf66d..40f43f8b3519 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -110,18 +110,10 @@ The :mod:`functools` module defines the following functions: ``__slots__`` without including ``__dict__`` as one of the defined slots (as such classes don't provide a ``__dict__`` attribute at all). - If a mutable mapping is not available or if space-efficient key sharing - is desired, an effect similar to :func:`cached_property` can be achieved - by a stacking :func:`property` on top of :func:`cache`:: - - class DataSet: - def __init__(self, sequence_of_numbers): - self._data = sequence_of_numbers - - @property - @cache - def stdev(self): - return statistics.stdev(self._data) + If a mutable mapping is not available or if space-efficient key sharing is + desired, an effect similar to :func:`cached_property` can also be achieved by + stacking :func:`property` on top of :func:`lru_cache`. See + :ref:`faq-cache-method-calls` for more details on how this differs from :func:`cached_property`. .. versionadded:: 3.8 From webhook-mailer at python.org Thu May 4 19:10:41 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 04 May 2023 23:10:41 -0000 Subject: [Python-checkins] [3.11] gh-104112: link from cached_property docs to method-caching FAQ (GH-104113) (#104182) Message-ID: <mailman.172.1683241842.13550.python-checkins@python.org> https://github.com/python/cpython/commit/bb4369e15f1335c3842001434e4ae650da9c90d0 commit: bb4369e15f1335c3842001434e4ae650da9c90d0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm <carl at oddbird.net> date: 2023-05-04T17:10:34-06:00 summary: [3.11] gh-104112: link from cached_property docs to method-caching FAQ (GH-104113) (#104182) gh-104112: link from cached_property docs to method-caching FAQ (GH-104113) (cherry picked from commit fa86a77589a06661fcebb806d36f3a7450e2aecf) Co-authored-by: Carl Meyer <carl at oddbird.net> Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/functools.rst diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 7438d4cdadc5..62fcddec0904 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -102,18 +102,10 @@ The :mod:`functools` module defines the following functions: ``__slots__`` without including ``__dict__`` as one of the defined slots (as such classes don't provide a ``__dict__`` attribute at all). - If a mutable mapping is not available or if space-efficient key sharing - is desired, an effect similar to :func:`cached_property` can be achieved - by a stacking :func:`property` on top of :func:`cache`:: - - class DataSet: - def __init__(self, sequence_of_numbers): - self._data = sequence_of_numbers - - @property - @cache - def stdev(self): - return statistics.stdev(self._data) + If a mutable mapping is not available or if space-efficient key sharing is + desired, an effect similar to :func:`cached_property` can also be achieved by + stacking :func:`property` on top of :func:`lru_cache`. See + :ref:`faq-cache-method-calls` for more details on how this differs from :func:`cached_property`. .. versionadded:: 3.8 From webhook-mailer at python.org Thu May 4 20:00:14 2023 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 05 May 2023 00:00:14 -0000 Subject: [Python-checkins] GH-104142: Fix _Py_RefcntAdd to respect immortality (GH-104143) Message-ID: <mailman.173.1683244815.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ce871fdc3a02e8441ad73b13f9fced308a9d9ad1 commit: ce871fdc3a02e8441ad73b13f9fced308a9d9ad1 branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-04T17:00:07-07:00 summary: GH-104142: Fix _Py_RefcntAdd to respect immortality (GH-104143) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst M Include/internal/pycore_object.h M Lib/test/test_builtin.py diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index b9e700ea280c..500b3eece680 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -58,6 +58,9 @@ extern void _Py_DecRefTotal(PyInterpreterState *); // Increment reference count by n static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) { + if (_Py_IsImmortal(op)) { + return; + } #ifdef Py_REF_DEBUG _Py_AddRefTotal(_PyInterpreterState_GET(), n); #endif diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 04dd8ff3070c..821710a7fa32 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2372,24 +2372,31 @@ def __del__(self): @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) + + if sys.maxsize < (1 << 32): + IMMORTAL_REFCOUNT = (1 << 30) - 1 + else: + IMMORTAL_REFCOUNT = (1 << 32) - 1 + + IMMORTALS = (None, True, False, Ellipsis, NotImplemented, *range(-5, 257)) + + def assert_immortal(self, immortal): + with self.subTest(immortal): + self.assertEqual(sys.getrefcount(immortal), self.IMMORTAL_REFCOUNT) + + def test_immortals(self): + for immortal in self.IMMORTALS: + self.assert_immortal(immortal) + + def test_list_repeat_respect_immortality(self): + refs = list(self.IMMORTALS) * 42 + for immortal in self.IMMORTALS: + self.assert_immortal(immortal) + + def test_tuple_repeat_respect_immortality(self): + refs = tuple(self.IMMORTALS) * 42 + for immortal in self.IMMORTALS: + self.assert_immortal(immortal) class TestType(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst new file mode 100644 index 000000000000..6a19ae84057f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst @@ -0,0 +1,2 @@ +Fix an issue where :class:`list` or :class:`tuple` repetition could fail to +respect :pep:`683`. From webhook-mailer at python.org Thu May 4 23:28:00 2023 From: webhook-mailer at python.org (corona10) Date: Fri, 05 May 2023 03:28:00 -0000 Subject: [Python-checkins] gh-104106: Add gcc fallback of mkfifoat/mknodat for macOS (gh-104129) Message-ID: <mailman.174.1683257281.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e5b8b19d99861c73ab76ee0175a685acf6082d7e commit: e5b8b19d99861c73ab76ee0175a685acf6082d7e branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-05T12:27:25+09:00 summary: gh-104106: Add gcc fallback of mkfifoat/mknodat for macOS (gh-104129) files: A Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst M Modules/posixmodule.c diff --git a/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst b/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst new file mode 100644 index 000000000000..900e5bd61d60 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst @@ -0,0 +1 @@ +Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Dong-hee Na. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index dcb5e7a0e040..b395c265c72d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -175,6 +175,14 @@ # define HAVE_PWRITEV_RUNTIME (pwritev != NULL) # endif +# ifdef HAVE_MKFIFOAT +# define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL) +# endif + +# ifdef HAVE_MKNODAT +# define HAVE_MKNODAT_RUNTIME (mknodat != NULL) +# endif + #endif #ifdef HAVE_FUTIMESAT @@ -4802,7 +4810,7 @@ os__path_isdir_impl(PyObject *module, PyObject *path) } Py_BEGIN_ALLOW_THREADS - if (_path.wide) { + if (_path.wide) { if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo, &statInfo, sizeof(statInfo))) { if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { @@ -4899,7 +4907,7 @@ os__path_isfile_impl(PyObject *module, PyObject *path) } Py_BEGIN_ALLOW_THREADS - if (_path.wide) { + if (_path.wide) { if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo, &statInfo, sizeof(statInfo))) { if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { @@ -4995,7 +5003,7 @@ os__path_exists_impl(PyObject *module, PyObject *path) } Py_BEGIN_ALLOW_THREADS - if (_path.wide) { + if (_path.wide) { if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo, &statInfo, sizeof(statInfo))) { if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { @@ -5082,7 +5090,7 @@ os__path_islink_impl(PyObject *module, PyObject *path) } Py_BEGIN_ALLOW_THREADS - if (_path.wide) { + if (_path.wide) { if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo, &statInfo, sizeof(statInfo))) { slow_path = FALSE; From webhook-mailer at python.org Fri May 5 00:32:35 2023 From: webhook-mailer at python.org (corona10) Date: Fri, 05 May 2023 04:32:35 -0000 Subject: [Python-checkins] [3.11] gh-104106: Add gcc fallback of mkfifoat/mknodat for macOS (gh-104129) (gh-104187) Message-ID: <mailman.175.1683261156.13550.python-checkins@python.org> https://github.com/python/cpython/commit/81902d3ed3c4119a5c4604547fa941f3e3448114 commit: 81902d3ed3c4119a5c4604547fa941f3e3448114 branch: 3.11 author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-05T04:32:28Z summary: [3.11] gh-104106: Add gcc fallback of mkfifoat/mknodat for macOS (gh-104129) (gh-104187) gh-104106: Add gcc fallback of mkfifoat/mknodat for macOS (gh-104129) files: A Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst M Modules/posixmodule.c diff --git a/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst b/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst new file mode 100644 index 000000000000..900e5bd61d60 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst @@ -0,0 +1 @@ +Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Dong-hee Na. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 613b86f09c9e..c825aeedcf08 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -169,6 +169,14 @@ # define HAVE_PWRITEV_RUNTIME (pwritev != NULL) # endif +# ifdef HAVE_MKFIFOAT +# define HAVE_MKFIFOAT_RUNTIME (mkfifoat != NULL) +# endif + +# ifdef HAVE_MKNODAT +# define HAVE_MKNODAT_RUNTIME (mknodat != NULL) +# endif + #endif #ifdef HAVE_FUTIMESAT From webhook-mailer at python.org Fri May 5 05:54:10 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 05 May 2023 09:54:10 -0000 Subject: [Python-checkins] gh-104190: fix ubsan crash (#104191) Message-ID: <mailman.176.1683280451.13550.python-checkins@python.org> https://github.com/python/cpython/commit/163034515a81f137d1dd7d289dc048eb0f1cd424 commit: 163034515a81f137d1dd7d289dc048eb0f1cd424 branch: main author: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-05T15:24:03+05:30 summary: gh-104190: fix ubsan crash (#104191) files: M Modules/_testcapimodule.c diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ae70a33eb4d1..376f04f23e32 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4221,7 +4221,7 @@ PyInit__testcapi(void) return NULL; } int ret = PyModule_AddType(m, (PyTypeObject*)ObjExtraData_Type); - Py_DECREF(&ObjExtraData_Type); + Py_DECREF(ObjExtraData_Type); if (ret < 0) { return NULL; } From webhook-mailer at python.org Fri May 5 06:34:24 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 05 May 2023 10:34:24 -0000 Subject: [Python-checkins] gh-104051: fix crash in test_xxtestfuzz with -We (#104052) Message-ID: <mailman.177.1683282864.13550.python-checkins@python.org> https://github.com/python/cpython/commit/81fc135f263e9ec5df3d967290b9665d7e100c7f commit: 81fc135f263e9ec5df3d967290b9665d7e100c7f branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-05T11:34:13+01:00 summary: gh-104051: fix crash in test_xxtestfuzz with -We (#104052) files: M Modules/_xxtestfuzz/fuzzer.c diff --git a/Modules/_xxtestfuzz/fuzzer.c b/Modules/_xxtestfuzz/fuzzer.c index fb0c191d2c49..37d402824853 100644 --- a/Modules/_xxtestfuzz/fuzzer.c +++ b/Modules/_xxtestfuzz/fuzzer.c @@ -526,13 +526,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { #if !defined(_Py_FUZZ_ONE) || defined(_Py_FUZZ_fuzz_sre_compile) static int SRE_COMPILE_INITIALIZED = 0; if (!SRE_COMPILE_INITIALIZED && !init_sre_compile()) { - PyErr_Print(); - abort(); + if (!PyErr_ExceptionMatches(PyExc_DeprecationWarning)) { + PyErr_Print(); + abort(); + } + else { + PyErr_Clear(); + } } else { SRE_COMPILE_INITIALIZED = 1; } - rv |= _run_fuzz(data, size, fuzz_sre_compile); + if (SRE_COMPILE_INITIALIZED) { + rv |= _run_fuzz(data, size, fuzz_sre_compile); + } #endif #if !defined(_Py_FUZZ_ONE) || defined(_Py_FUZZ_fuzz_sre_match) static int SRE_MATCH_INITIALIZED = 0; From webhook-mailer at python.org Fri May 5 07:13:05 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 05 May 2023 11:13:05 -0000 Subject: [Python-checkins] GH-103092: port `_asyncio` freelist to module state (#104196) Message-ID: <mailman.178.1683285186.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2318bedb3645d2dfb56944553f01d6c434904c4b commit: 2318bedb3645d2dfb56944553f01d6c434904c4b branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-05T16:42:58+05:30 summary: GH-103092: port `_asyncio` freelist to module state (#104196) files: M Modules/_asynciomodule.c diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 8b1a29b6d33e..fef34d655238 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -18,6 +18,10 @@ module _asyncio /*[clinic end generated code: output=da39a3ee5e6b4b0d input=8fd17862aa989c69]*/ +#define FI_FREELIST_MAXLEN 255 + +typedef struct futureiterobject futureiterobject; + /* State of the _asyncio module */ typedef struct { PyTypeObject *FutureIterType; @@ -67,6 +71,9 @@ typedef struct { /* Counter for autogenerated Task names */ uint64_t task_name_counter; + + futureiterobject *fi_freelist; + Py_ssize_t fi_freelist_len; } asyncio_state; static inline asyncio_state * @@ -1574,28 +1581,24 @@ FutureObj_dealloc(PyObject *self) /*********************** Future Iterator **************************/ -typedef struct { +typedef struct futureiterobject { PyObject_HEAD FutureObj *future; } futureiterobject; -#define FI_FREELIST_MAXLEN 255 -static futureiterobject *fi_freelist = NULL; -static Py_ssize_t fi_freelist_len = 0; - - static void FutureIter_dealloc(futureiterobject *it) { PyTypeObject *tp = Py_TYPE(it); + asyncio_state *state = get_asyncio_state_by_def((PyObject *)it); PyObject_GC_UnTrack(it); tp->tp_clear((PyObject *)it); - if (fi_freelist_len < FI_FREELIST_MAXLEN) { - fi_freelist_len++; - it->future = (FutureObj*) fi_freelist; - fi_freelist = it; + if (state->fi_freelist_len < FI_FREELIST_MAXLEN) { + state->fi_freelist_len++; + it->future = (FutureObj*) state->fi_freelist; + state->fi_freelist = it; } else { PyObject_GC_Del(it); @@ -1799,17 +1802,12 @@ future_new_iter(PyObject *fut) futureiterobject *it; asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); - if (!Future_Check(state, fut)) { - PyErr_BadInternalCall(); - return NULL; - } - ENSURE_FUTURE_ALIVE(state, fut) - if (fi_freelist_len) { - fi_freelist_len--; - it = fi_freelist; - fi_freelist = (futureiterobject*) it->future; + if (state->fi_freelist_len) { + state->fi_freelist_len--; + it = state->fi_freelist; + state->fi_freelist = (futureiterobject*) it->future; it->future = NULL; _Py_NewReference((PyObject*) it); } @@ -3556,22 +3554,22 @@ _asyncio_current_task_impl(PyObject *module, PyObject *loop) static void -module_free_freelists(void) +module_free_freelists(asyncio_state *state) { PyObject *next; PyObject *current; - next = (PyObject*) fi_freelist; + next = (PyObject*) state->fi_freelist; while (next != NULL) { - assert(fi_freelist_len > 0); - fi_freelist_len--; + assert(state->fi_freelist_len > 0); + state->fi_freelist_len--; current = next; next = (PyObject*) ((futureiterobject*) current)->future; PyObject_GC_Del(current); } - assert(fi_freelist_len == 0); - fi_freelist = NULL; + assert(state->fi_freelist_len == 0); + state->fi_freelist = NULL; } static int @@ -3603,7 +3601,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg) Py_VISIT(state->context_kwname); // Visit freelist. - PyObject *next = (PyObject*) fi_freelist; + PyObject *next = (PyObject*) state->fi_freelist; while (next != NULL) { PyObject *current = next; Py_VISIT(current); @@ -3640,7 +3638,7 @@ module_clear(PyObject *mod) Py_CLEAR(state->context_kwname); - module_free_freelists(); + module_free_freelists(state); return 0; } From webhook-mailer at python.org Fri May 5 07:32:08 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 05 May 2023 11:32:08 -0000 Subject: [Python-checkins] gh-64658: Expand Argument Clinic return converter docs (#104175) Message-ID: <mailman.179.1683286329.13550.python-checkins@python.org> https://github.com/python/cpython/commit/721a78395d07c68351625aedb827a47dd4f48525 commit: 721a78395d07c68351625aedb827a47dd4f48525 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-05T13:32:00+02:00 summary: gh-64658: Expand Argument Clinic return converter docs (#104175) files: M Doc/howto/clinic.rst diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 8a10fe327358..6ebc2d9b0a71 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1033,19 +1033,36 @@ you're not permitted to use: Using a return converter ------------------------ -By default the impl function Argument Clinic generates for you returns ``PyObject *``. -But your C function often computes some C type, then converts it into the ``PyObject *`` +By default, the impl function Argument Clinic generates for you returns +:c:type:`PyObject * <PyObject>`. +But your C function often computes some C type, +then converts it into the :c:type:`!PyObject *` at the last moment. Argument Clinic handles converting your inputs from Python types into native C types?why not have it convert your return value from a native C type into a Python type too? That's what a "return converter" does. It changes your impl function to return some C type, then adds code to the generated (non-impl) function to handle converting -that value into the appropriate ``PyObject *``. +that value into the appropriate :c:type:`!PyObject *`. The syntax for return converters is similar to that of parameter converters. You specify the return converter like it was a return annotation on the -function itself. Return converters behave much the same as parameter converters; +function itself, using ``->`` notation. + +For example: + +.. code-block:: c + + /*[clinic input] + add -> int + + a: int + b: int + / + + [clinic start generated code]*/ + +Return converters behave much the same as parameter converters; they take arguments, the arguments are all keyword-only, and if you're not changing any of the default arguments you can omit the parentheses. @@ -1066,19 +1083,17 @@ Currently Argument Clinic supports only a few return converters: .. code-block:: none bool + double + float int - unsigned int long - unsigned int - size_t Py_ssize_t - float - double - DecodeFSDefault + size_t + unsigned int + unsigned long -None of these take parameters. For the first three, return -1 to indicate -error. For ``DecodeFSDefault``, the return type is ``const char *``; return a ``NULL`` -pointer to indicate an error. +None of these take parameters. +For all of these, return ``-1`` to indicate error. To see all the return converters Argument Clinic supports, along with their parameters (if any), From webhook-mailer at python.org Fri May 5 07:40:25 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 05 May 2023 11:40:25 -0000 Subject: [Python-checkins] gh-68395: Avoid naming conflicts by mangling variable names in Argument Clinic (#104065) Message-ID: <mailman.180.1683286826.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5245cb64d9a898804edf683427ef4d4fd20ccaec commit: 5245cb64d9a898804edf683427ef4d4fd20ccaec branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-05T13:40:18+02:00 summary: gh-68395: Avoid naming conflicts by mangling variable names in Argument Clinic (#104065) Add all internally used variable names to CLINIC_PREFIXED_ARGS. files: M Lib/test/clinic.test M Tools/clinic/clinic.py diff --git a/Lib/test/clinic.test b/Lib/test/clinic.test index 53e5df5ba872..564205274edd 100644 --- a/Lib/test/clinic.test +++ b/Lib/test/clinic.test @@ -4102,3 +4102,172 @@ exit: static PyObject * test_paramname_module_impl(PyObject *module, PyObject *mod) /*[clinic end generated code: output=4a2a849ecbcc8b53 input=afefe259667f13ba]*/ + +/*[clinic input] +mangle1 + + args: object + kwnames: object + return_value: object + _keywords: object + _parser: object + argsbuf: object + fastargs: object + nargs: object + noptargs: object + +[clinic start generated code]*/ + +PyDoc_STRVAR(mangle1__doc__, +"mangle1($module, /, args, kwnames, return_value, _keywords, _parser,\n" +" argsbuf, fastargs, nargs, noptargs)\n" +"--\n" +"\n"); + +#define MANGLE1_METHODDEF \ + {"mangle1", _PyCFunction_CAST(mangle1), METH_FASTCALL|METH_KEYWORDS, mangle1__doc__}, + +static PyObject * +mangle1_impl(PyObject *module, PyObject *args, PyObject *kwnames, + PyObject *return_value, PyObject *_keywords, PyObject *_parser, + PyObject *argsbuf, PyObject *fastargs, PyObject *nargs, + PyObject *noptargs); + +static PyObject * +mangle1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 9 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(args), &_Py_ID(kwnames), &_Py_ID(return_value), &_Py_ID(_keywords), &_Py_ID(_parser), &_Py_ID(argsbuf), &_Py_ID(fastargs), &_Py_ID(nargs), &_Py_ID(noptargs), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"args", "kwnames", "return_value", "_keywords", "_parser", "argsbuf", "fastargs", "nargs", "noptargs", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "mangle1", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[9]; + PyObject *__clinic_args; + PyObject *__clinic_kwnames; + PyObject *__clinic_return_value; + PyObject *__clinic__keywords; + PyObject *__clinic__parser; + PyObject *__clinic_argsbuf; + PyObject *__clinic_fastargs; + PyObject *__clinic_nargs; + PyObject *__clinic_noptargs; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 9, 9, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + __clinic_kwnames = args[1]; + __clinic_return_value = args[2]; + __clinic__keywords = args[3]; + __clinic__parser = args[4]; + __clinic_argsbuf = args[5]; + __clinic_fastargs = args[6]; + __clinic_nargs = args[7]; + __clinic_noptargs = args[8]; + return_value = mangle1_impl(module, __clinic_args, __clinic_kwnames, __clinic_return_value, __clinic__keywords, __clinic__parser, __clinic_argsbuf, __clinic_fastargs, __clinic_nargs, __clinic_noptargs); + +exit: + return return_value; +} + +static PyObject * +mangle1_impl(PyObject *module, PyObject *args, PyObject *kwnames, + PyObject *return_value, PyObject *_keywords, PyObject *_parser, + PyObject *argsbuf, PyObject *fastargs, PyObject *nargs, + PyObject *noptargs) +/*[clinic end generated code: output=083e5076be9987c3 input=a3ed51bdedf8a3c7]*/ + +/*[clinic input] +mangle2 + + args: object + kwargs: object + return_value: object + +[clinic start generated code]*/ + +PyDoc_STRVAR(mangle2__doc__, +"mangle2($module, /, args, kwargs, return_value)\n" +"--\n" +"\n"); + +#define MANGLE2_METHODDEF \ + {"mangle2", _PyCFunction_CAST(mangle2), METH_FASTCALL|METH_KEYWORDS, mangle2__doc__}, + +static PyObject * +mangle2_impl(PyObject *module, PyObject *args, PyObject *kwargs, + PyObject *return_value); + +static PyObject * +mangle2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(args), &_Py_ID(kwargs), &_Py_ID(return_value), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"args", "kwargs", "return_value", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "mangle2", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject *__clinic_args; + PyObject *__clinic_kwargs; + PyObject *__clinic_return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + __clinic_kwargs = args[1]; + __clinic_return_value = args[2]; + return_value = mangle2_impl(module, __clinic_args, __clinic_kwargs, __clinic_return_value); + +exit: + return return_value; +} + +static PyObject * +mangle2_impl(PyObject *module, PyObject *args, PyObject *kwargs, + PyObject *return_value) +/*[clinic end generated code: output=2ebb62aaefe7590a input=391766fee51bad7a]*/ diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index d3e120c0e7a8..2746b24c333e 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -43,7 +43,18 @@ NO_VARARG = "PY_SSIZE_T_MAX" CLINIC_PREFIX = "__clinic_" -CLINIC_PREFIXED_ARGS = {"args"} +CLINIC_PREFIXED_ARGS = { + "_keywords", + "_parser", + "args", + "argsbuf", + "fastargs", + "kwargs", + "kwnames", + "nargs", + "noptargs", + "return_value", +} class Unspecified: def __repr__(self): From webhook-mailer at python.org Fri May 5 07:46:29 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 05 May 2023 11:46:29 -0000 Subject: [Python-checkins] [3.11] gh-64658: Expand Argument Clinic return converter docs (#104175) (#104198) Message-ID: <mailman.181.1683287191.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a635d6386041a2971cf1d39837188ffb8139bcc7 commit: a635d6386041a2971cf1d39837188ffb8139bcc7 branch: 3.11 author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-05T13:46:23+02:00 summary: [3.11] gh-64658: Expand Argument Clinic return converter docs (#104175) (#104198) files: M Doc/howto/clinic.rst diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 4e9b3dee0913..c4bf6ef76477 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -1025,19 +1025,36 @@ you're not permitted to use: Using a return converter ------------------------ -By default the impl function Argument Clinic generates for you returns ``PyObject *``. -But your C function often computes some C type, then converts it into the ``PyObject *`` +By default, the impl function Argument Clinic generates for you returns +:c:type:`PyObject * <PyObject>`. +But your C function often computes some C type, +then converts it into the :c:type:`!PyObject *` at the last moment. Argument Clinic handles converting your inputs from Python types into native C types?why not have it convert your return value from a native C type into a Python type too? That's what a "return converter" does. It changes your impl function to return some C type, then adds code to the generated (non-impl) function to handle converting -that value into the appropriate ``PyObject *``. +that value into the appropriate :c:type:`!PyObject *`. The syntax for return converters is similar to that of parameter converters. You specify the return converter like it was a return annotation on the -function itself. Return converters behave much the same as parameter converters; +function itself, using ``->`` notation. + +For example: + +.. code-block:: c + + /*[clinic input] + add -> int + + a: int + b: int + / + + [clinic start generated code]*/ + +Return converters behave much the same as parameter converters; they take arguments, the arguments are all keyword-only, and if you're not changing any of the default arguments you can omit the parentheses. @@ -1058,19 +1075,17 @@ Currently Argument Clinic supports only a few return converters: .. code-block:: none bool + double + float int - unsigned int long - unsigned int - size_t Py_ssize_t - float - double - DecodeFSDefault + size_t + unsigned int + unsigned long -None of these take parameters. For the first three, return -1 to indicate -error. For ``DecodeFSDefault``, the return type is ``const char *``; return a ``NULL`` -pointer to indicate an error. +None of these take parameters. +For all of these, return ``-1`` to indicate error. (There's also an experimental ``NoneType`` converter, which lets you return ``Py_None`` on success or ``NULL`` on failure, without having From webhook-mailer at python.org Fri May 5 08:08:31 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 05 May 2023 12:08:31 -0000 Subject: [Python-checkins] gh-64631: Test exception messages in cloned Argument Clinic funcs (#104167) Message-ID: <mailman.182.1683288512.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d0b4abedfb8b0322df835065f85551d097cfecb8 commit: d0b4abedfb8b0322df835065f85551d097cfecb8 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-05T14:08:24+02:00 summary: gh-64631: Test exception messages in cloned Argument Clinic funcs (#104167) files: M Lib/test/test_clinic.py M Modules/_testclinic.c M Modules/clinic/_testclinic.c.h diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 4abf739cf52c..660f7a1e296d 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1284,6 +1284,19 @@ def test_gh_99240_double_free(self): with self.assertRaisesRegex(TypeError, expected_error): ac_tester.gh_99240_double_free('a', '\0b') + def test_cloned_func_exception_message(self): + incorrect_arg = -1 # f1() and f2() accept a single str + with self.assertRaisesRegex(TypeError, "clone_f1"): + ac_tester.clone_f1(incorrect_arg) + with self.assertRaisesRegex(TypeError, "clone_f2"): + ac_tester.clone_f2(incorrect_arg) + + def test_cloned_func_with_converter_exception_message(self): + for name in "clone_with_conv_f1", "clone_with_conv_f2": + with self.subTest(name=name): + func = getattr(ac_tester, name) + self.assertEqual(func(), name) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index 91fdee24d328..6ff55a2755cf 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -9,6 +9,19 @@ #include "Python.h" + +// Used for clone_with_conv_f1 and clone_with_conv_v2 +typedef struct { + const char *name; +} custom_t; + +static int +custom_converter(PyObject *obj, custom_t *val) +{ + return 1; +} + + #include "clinic/_testclinic.c.h" @@ -1117,6 +1130,70 @@ gh_99240_double_free_impl(PyObject *module, char *a, char *b) } +/*[clinic input] +_testclinic.clone_f1 as clone_f1 + path: str +[clinic start generated code]*/ + +static PyObject * +clone_f1_impl(PyObject *module, const char *path) +/*[clinic end generated code: output=8c30b5620ba86715 input=9c614b7f025ebf70]*/ +{ + Py_RETURN_NONE; +} + + +/*[clinic input] +_testclinic.clone_f2 as clone_f2 = _testclinic.clone_f1 +[clinic start generated code]*/ + +static PyObject * +clone_f2_impl(PyObject *module, const char *path) +/*[clinic end generated code: output=6aa1c39bec3f5d9b input=1aaaf47d6ed2324a]*/ +{ + Py_RETURN_NONE; +} + + +/*[python input] +class custom_t_converter(CConverter): + type = 'custom_t' + converter = 'custom_converter' + + def pre_render(self): + self.c_default = f'''{{ + .name = "{self.function.name}", + }}''' + +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=b2fb801e99a06bf6]*/ + + +/*[clinic input] +_testclinic.clone_with_conv_f1 as clone_with_conv_f1 + path: custom_t = None +[clinic start generated code]*/ + +static PyObject * +clone_with_conv_f1_impl(PyObject *module, custom_t path) +/*[clinic end generated code: output=f7e030ffd5439cb0 input=bc77bc80dec3f46d]*/ +{ + return PyUnicode_FromString(path.name); +} + + +/*[clinic input] +_testclinic.clone_with_conv_f2 as clone_with_conv_f2 = _testclinic.clone_with_conv_f1 +[clinic start generated code]*/ + +static PyObject * +clone_with_conv_f2_impl(PyObject *module, custom_t path) +/*[clinic end generated code: output=9d7fdd6a75eecee4 input=cff459a205fa83bb]*/ +{ + return PyUnicode_FromString(path.name); +} + + static PyMethodDef tester_methods[] = { TEST_EMPTY_FUNCTION_METHODDEF OBJECTS_CONVERTER_METHODDEF @@ -1168,6 +1245,10 @@ static PyMethodDef tester_methods[] = { GH_32092_KW_PASS_METHODDEF GH_99233_REFCOUNT_METHODDEF GH_99240_DOUBLE_FREE_METHODDEF + CLONE_F1_METHODDEF + CLONE_F2_METHODDEF + CLONE_WITH_CONV_F1_METHODDEF + CLONE_WITH_CONV_F2_METHODDEF {NULL, NULL} }; diff --git a/Modules/clinic/_testclinic.c.h b/Modules/clinic/_testclinic.c.h index 831f58ca650a..cc69f5c3d2fe 100644 --- a/Modules/clinic/_testclinic.c.h +++ b/Modules/clinic/_testclinic.c.h @@ -2817,4 +2817,262 @@ gh_99240_double_free(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=e8211606b03d733a input=a9049054013a1b77]*/ + +PyDoc_STRVAR(clone_f1__doc__, +"clone_f1($module, /, path)\n" +"--\n" +"\n"); + +#define CLONE_F1_METHODDEF \ + {"clone_f1", _PyCFunction_CAST(clone_f1), METH_FASTCALL|METH_KEYWORDS, clone_f1__doc__}, + +static PyObject * +clone_f1_impl(PyObject *module, const char *path); + +static PyObject * +clone_f1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "clone_f1", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + const char *path; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("clone_f1", "argument 'path'", "str", args[0]); + goto exit; + } + Py_ssize_t path_length; + path = PyUnicode_AsUTF8AndSize(args[0], &path_length); + if (path == NULL) { + goto exit; + } + if (strlen(path) != (size_t)path_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + return_value = clone_f1_impl(module, path); + +exit: + return return_value; +} + +PyDoc_STRVAR(clone_f2__doc__, +"clone_f2($module, /, path)\n" +"--\n" +"\n"); + +#define CLONE_F2_METHODDEF \ + {"clone_f2", _PyCFunction_CAST(clone_f2), METH_FASTCALL|METH_KEYWORDS, clone_f2__doc__}, + +static PyObject * +clone_f2_impl(PyObject *module, const char *path); + +static PyObject * +clone_f2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "clone_f2", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + const char *path; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("clone_f2", "argument 'path'", "str", args[0]); + goto exit; + } + Py_ssize_t path_length; + path = PyUnicode_AsUTF8AndSize(args[0], &path_length); + if (path == NULL) { + goto exit; + } + if (strlen(path) != (size_t)path_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + return_value = clone_f2_impl(module, path); + +exit: + return return_value; +} + +PyDoc_STRVAR(clone_with_conv_f1__doc__, +"clone_with_conv_f1($module, /, path=None)\n" +"--\n" +"\n"); + +#define CLONE_WITH_CONV_F1_METHODDEF \ + {"clone_with_conv_f1", _PyCFunction_CAST(clone_with_conv_f1), METH_FASTCALL|METH_KEYWORDS, clone_with_conv_f1__doc__}, + +static PyObject * +clone_with_conv_f1_impl(PyObject *module, custom_t path); + +static PyObject * +clone_with_conv_f1(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "clone_with_conv_f1", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + custom_t path = { + .name = "clone_with_conv_f1", + }; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (!custom_converter(args[0], &path)) { + goto exit; + } +skip_optional_pos: + return_value = clone_with_conv_f1_impl(module, path); + +exit: + return return_value; +} + +PyDoc_STRVAR(clone_with_conv_f2__doc__, +"clone_with_conv_f2($module, /, path=None)\n" +"--\n" +"\n"); + +#define CLONE_WITH_CONV_F2_METHODDEF \ + {"clone_with_conv_f2", _PyCFunction_CAST(clone_with_conv_f2), METH_FASTCALL|METH_KEYWORDS, clone_with_conv_f2__doc__}, + +static PyObject * +clone_with_conv_f2_impl(PyObject *module, custom_t path); + +static PyObject * +clone_with_conv_f2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(path), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "clone_with_conv_f2", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + custom_t path = { + .name = "clone_with_conv_f2", + }; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (!custom_converter(args[0], &path)) { + goto exit; + } +skip_optional_pos: + return_value = clone_with_conv_f2_impl(module, path); + +exit: + return return_value; +} +/*[clinic end generated code: output=f58202a6e5df2d16 input=a9049054013a1b77]*/ From webhook-mailer at python.org Fri May 5 08:38:45 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 05 May 2023 12:38:45 -0000 Subject: [Python-checkins] gh-64595: Argument Clinic: Touch source file if any output file changed (#104152) Message-ID: <mailman.183.1683290326.13550.python-checkins@python.org> https://github.com/python/cpython/commit/45a9e3834a6ed20ee250e2e5a8583dffcef0eb73 commit: 45a9e3834a6ed20ee250e2e5a8583dffcef0eb73 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-05T12:38:38Z summary: gh-64595: Argument Clinic: Touch source file if any output file changed (#104152) files: M Lib/test/test_clinic.py M Tools/clinic/clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 660f7a1e296d..6aaf4d1ed8d5 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -99,8 +99,9 @@ def test_eol(self): # the last line of the block got corrupted. c = clinic.Clinic(clinic.CLanguage(None), filename="file") raw = "/*[clinic]\nfoo\n[clinic]*/" - cooked = c.parse(raw).splitlines() - end_line = cooked[2].rstrip() + cooked, _ = c.parse(raw) + lines = cooked.splitlines() + end_line = lines[2].rstrip() # this test is redundant, it's just here explicitly to catch # the regression test so we don't forget what it looked like self.assertNotEqual(end_line, "[clinic]*/[clinic]*/") @@ -259,7 +260,7 @@ def _test_clinic(self, input, output): c = clinic.Clinic(language, filename="file") c.parsers['inert'] = InertParser(c) c.parsers['copy'] = CopyParser(c) - computed = c.parse(input) + computed, _ = c.parse(input) self.assertEqual(output, computed) def test_clinic_1(self): diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 2746b24c333e..5f6e67e7d65a 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1954,12 +1954,12 @@ def dump(self): return_converters = {} -def write_file(filename, new_contents): +def write_file(filename, new_contents, force=False): try: with open(filename, 'r', encoding="utf-8") as fp: old_contents = fp.read() - if old_contents == new_contents: + if old_contents == new_contents and not force: # no change: avoid modifying the file modification time return except FileNotFoundError: @@ -2123,6 +2123,8 @@ def parse(self, input): traceback.format_exc().rstrip()) printer.print_block(block) + clinic_out = [] + # these are destinations not buffers for name, destination in self.destinations.items(): if destination.type == 'suppress': @@ -2162,10 +2164,11 @@ def parse(self, input): block.input = 'preserve\n' printer_2 = BlockPrinter(self.language) printer_2.print_block(block, core_includes=True) - write_file(destination.filename, printer_2.f.getvalue()) + pair = destination.filename, printer_2.f.getvalue() + clinic_out.append(pair) continue - return printer.f.getvalue() + return printer.f.getvalue(), clinic_out def _module_and_class(self, fields): @@ -2221,9 +2224,13 @@ def parse_file(filename, *, verify=True, output=None): return clinic = Clinic(language, verify=verify, filename=filename) - cooked = clinic.parse(raw) + src_out, clinic_out = clinic.parse(raw) - write_file(output, cooked) + # If clinic output changed, force updating the source file as well. + force = bool(clinic_out) + write_file(output, src_out, force=force) + for fn, data in clinic_out: + write_file(fn, data) def compute_checksum(input, length=None): From webhook-mailer at python.org Fri May 5 12:53:18 2023 From: webhook-mailer at python.org (markshannon) Date: Fri, 05 May 2023 16:53:18 -0000 Subject: [Python-checkins] GH-96803: Add three C-API functions to make _PyInterpreterFrame less opaque for users of PEP 523. (GH-96849) Message-ID: <mailman.184.1683305600.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a0df9ee8fc77443510ab7e9ba8fd830f255a8fec commit: a0df9ee8fc77443510ab7e9ba8fd830f255a8fec branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-05T17:53:07+01:00 summary: GH-96803: Add three C-API functions to make _PyInterpreterFrame less opaque for users of PEP 523. (GH-96849) files: A Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst M Include/cpython/frameobject.h M Include/internal/pycore_frame.h M Modules/_tracemalloc.c M Objects/frameobject.c M Objects/genobject.c M Python/ceval.c M Python/frame.c M Python/traceback.c diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index 4e19535c656f..6f3efe36ede5 100644 --- a/Include/cpython/frameobject.h +++ b/Include/cpython/frameobject.h @@ -4,6 +4,8 @@ # error "this header file must not be included directly" #endif +struct _PyInterpreterFrame; + /* Standard object interface */ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *, @@ -27,3 +29,18 @@ PyAPI_FUNC(int) _PyFrame_IsEntryFrame(PyFrameObject *frame); PyAPI_FUNC(int) PyFrame_FastToLocalsWithError(PyFrameObject *f); PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); + +/* The following functions are for use by debuggers and other tools + * implementing custom frame evaluators with PEP 523. */ + +/* Returns the code object of the frame (strong reference). + * Does not raise an exception. */ +PyAPI_FUNC(PyCodeObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); + +/* Returns a byte ofsset into the last executed instruction. + * Does not raise an exception. */ +PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame); + +/* Returns the currently executing line number, or -1 if there is no line number. + * Does not raise an exception. */ +PyAPI_FUNC(int) PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame); diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index d8d7fe9ef2eb..3d3cbbff7aae 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -265,8 +265,6 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l return new_frame; } -int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame); - static inline PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) { diff --git a/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst b/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst new file mode 100644 index 000000000000..6fc56d2249f5 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst @@ -0,0 +1,6 @@ +Add unstable C-API functions to get the code object, lasti and line number from +the internal ``_PyInterpreterFrame`` in the limited API. The functions are: + +* ``PyCodeObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` +* ``int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` +* ``int PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index d69c5636486d..c5714d5e7d5a 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -7,6 +7,7 @@ #include "pycore_runtime.h" // _Py_ID() #include "pycore_traceback.h" #include <pycore_frame.h> +#include "frameobject.h" // _PyInterpreterFrame_GetLine #include <stdlib.h> // malloc() @@ -257,7 +258,7 @@ static void tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) { frame->filename = &_Py_STR(anon_unknown); - int lineno = _PyInterpreterFrame_GetLine(pyframe); + int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); if (lineno < 0) { lineno = 0; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index ef0070199ab2..d0eca447c012 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -38,7 +38,7 @@ PyFrame_GetLineNumber(PyFrameObject *f) return f->f_lineno; } else { - return _PyInterpreterFrame_GetLine(f->f_frame); + return PyUnstable_InterpreterFrame_GetLine(f->f_frame); } } diff --git a/Objects/genobject.c b/Objects/genobject.c index 6316fa9865fe..937d497753e9 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -12,6 +12,7 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include "structmember.h" // PyMemberDef #include "opcode.h" // SEND +#include "frameobject.h" // _PyInterpreterFrame_GetLine #include "pystats.h" static PyObject *gen_close(PyGenObject *, PyObject *); @@ -1322,7 +1323,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame) frame = current_frame; for (int i = 0; i < frame_count; ++i) { PyCodeObject *code = frame->f_code; - int line = _PyInterpreterFrame_GetLine(frame); + int line = PyUnstable_InterpreterFrame_GetLine(frame); PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line, code->co_name); if (!frameinfo) { diff --git a/Python/ceval.c b/Python/ceval.c index 958689debc87..56a3b123f463 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -27,6 +27,7 @@ #include "pycore_dict.h" #include "dictobject.h" #include "pycore_frame.h" +#include "frameobject.h" // _PyInterpreterFrame_GetLine #include "opcode.h" #include "pydtrace.h" #include "setobject.h" @@ -785,7 +786,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyErr_Format(tstate, PyExc_SystemError, "%U:%d: unknown opcode %d", frame->f_code->co_filename, - _PyInterpreterFrame_GetLine(frame), + PyUnstable_InterpreterFrame_GetLine(frame), opcode); goto error; diff --git a/Python/frame.c b/Python/frame.c index c2c0be301139..d792b92fa575 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -144,8 +144,24 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) Py_DECREF(frame->f_funcobj); } +/* Unstable API functions */ + +PyCodeObject * +PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) +{ + PyCodeObject *code = frame->f_code; + Py_INCREF(code); + return code; +} + +int +PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame) +{ + return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); +} + int -_PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame) +PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame) { int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); return PyCode_Addr2Line(frame->f_code, addr); diff --git a/Python/traceback.c b/Python/traceback.c index 097f69c76abf..b24795420473 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -1180,7 +1180,7 @@ dump_frame(int fd, _PyInterpreterFrame *frame) PUTS(fd, "???"); } - int lineno = _PyInterpreterFrame_GetLine(frame); + int lineno = PyUnstable_InterpreterFrame_GetLine(frame); PUTS(fd, ", line "); if (lineno >= 0) { _Py_DumpDecimal(fd, (size_t)lineno); From webhook-mailer at python.org Fri May 5 13:38:54 2023 From: webhook-mailer at python.org (markshannon) Date: Fri, 05 May 2023 17:38:54 -0000 Subject: [Python-checkins] gh-103533: Use PEP 669 APIs for cprofile (GH-103534) Message-ID: <mailman.185.1683308336.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b9797417315cc2d1700cb2d427685016d3380711 commit: b9797417315cc2d1700cb2d427685016d3380711 branch: main author: Tian Gao <gaogaotiantian at hotmail.com> committer: markshannon <mark at hotpy.org> date: 2023-05-05T18:38:47+01:00 summary: gh-103533: Use PEP 669 APIs for cprofile (GH-103534) files: A Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst M Lib/test/test_cprofile.py M Modules/_lsprof.c M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 98648528bc81..484b8f8e3a36 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -25,7 +25,6 @@ def test_bad_counter_during_dealloc(self): with support.catch_unraisable_exception() as cm: obj = _lsprof.Profiler(lambda: int) obj.enable() - obj = _lsprof.Profiler(1) obj.disable() obj.clear() @@ -37,10 +36,11 @@ def test_profile_enable_disable(self): self.addCleanup(prof.disable) prof.enable() - self.assertIs(sys.getprofile(), prof) + self.assertEqual( + sys.monitoring.get_tool(sys.monitoring.PROFILER_ID), "cProfile") prof.disable() - self.assertIs(sys.getprofile(), None) + self.assertIs(sys.monitoring.get_tool(sys.monitoring.PROFILER_ID), None) def test_profile_as_context_manager(self): prof = self.profilerclass() @@ -53,10 +53,19 @@ def test_profile_as_context_manager(self): # profile should be set as the global profiler inside the # with-block - self.assertIs(sys.getprofile(), prof) + self.assertEqual( + sys.monitoring.get_tool(sys.monitoring.PROFILER_ID), "cProfile") # profile shouldn't be set once we leave the with-block. - self.assertIs(sys.getprofile(), None) + self.assertIs(sys.monitoring.get_tool(sys.monitoring.PROFILER_ID), None) + + def test_second_profiler(self): + pr = self.profilerclass() + pr2 = self.profilerclass() + pr.enable() + self.assertRaises(ValueError, pr2.enable) + pr.disable() + class TestCommandLine(unittest.TestCase): def test_sort(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst b/Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst new file mode 100644 index 000000000000..1008ea076c71 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst @@ -0,0 +1 @@ +Update :mod:`cProfile` to use PEP 669 API diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 83d034ae7eed..a7ce328cb530 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -49,6 +49,8 @@ typedef struct { int flags; PyObject *externalTimer; double externalTimerUnit; + int tool_id; + PyObject* missing; } ProfilerObject; #define POF_ENABLED 0x001 @@ -399,64 +401,6 @@ ptrace_leave_call(PyObject *self, void *key) pObj->freelistProfilerContext = pContext; } -static int -profiler_callback(PyObject *self, PyFrameObject *frame, int what, - PyObject *arg) -{ - switch (what) { - - /* the 'frame' of a called function is about to start its execution */ - case PyTrace_CALL: - { - PyCodeObject *code = PyFrame_GetCode(frame); - ptrace_enter_call(self, (void *)code, (PyObject *)code); - Py_DECREF(code); - break; - } - - /* the 'frame' of a called function is about to finish - (either normally or with an exception) */ - case PyTrace_RETURN: - { - PyCodeObject *code = PyFrame_GetCode(frame); - ptrace_leave_call(self, (void *)code); - Py_DECREF(code); - break; - } - - /* case PyTrace_EXCEPTION: - If the exception results in the function exiting, a - PyTrace_RETURN event will be generated, so we don't need to - handle it. */ - - /* the Python function 'frame' is issuing a call to the built-in - function 'arg' */ - case PyTrace_C_CALL: - if ((((ProfilerObject *)self)->flags & POF_BUILTINS) - && PyCFunction_Check(arg)) { - ptrace_enter_call(self, - ((PyCFunctionObject *)arg)->m_ml, - arg); - } - break; - - /* the call to the built-in function 'arg' is returning into its - caller 'frame' */ - case PyTrace_C_RETURN: /* ...normally */ - case PyTrace_C_EXCEPTION: /* ...with an exception set */ - if ((((ProfilerObject *)self)->flags & POF_BUILTINS) - && PyCFunction_Check(arg)) { - ptrace_leave_call(self, - ((PyCFunctionObject *)arg)->m_ml); - } - break; - - default: - break; - } - return 0; -} - static int pending_exception(ProfilerObject *pObj) { @@ -650,6 +594,99 @@ setBuiltins(ProfilerObject *pObj, int nvalue) return 0; } +PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +{ + PyObject* code = args[0]; + ptrace_enter_call((PyObject*)self, (void *)code, (PyObject *)code); + + Py_RETURN_NONE; +} + +PyObject* pyreturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +{ + PyObject* code = args[0]; + ptrace_leave_call((PyObject*)self, (void *)code); + + Py_RETURN_NONE; +} + +PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObject* missing) +{ + // return a new reference + if (PyCFunction_Check(callable)) { + Py_INCREF(callable); + return (PyObject*)((PyCFunctionObject *)callable); + } + if (Py_TYPE(callable) == &PyMethodDescr_Type) { + /* For backwards compatibility need to + * convert to builtin method */ + + /* If no arg, skip */ + if (self_arg == missing) { + return NULL; + } + PyObject *meth = Py_TYPE(callable)->tp_descr_get( + callable, self_arg, (PyObject*)Py_TYPE(self_arg)); + if (meth == NULL) { + return NULL; + } + if (PyCFunction_Check(meth)) { + return (PyObject*)((PyCFunctionObject *)meth); + } + } + return NULL; +} + +PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +{ + if (self->flags & POF_BUILTINS) { + PyObject* callable = args[2]; + PyObject* self_arg = args[3]; + + PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); + + if (cfunc) { + ptrace_enter_call((PyObject*)self, + ((PyCFunctionObject *)cfunc)->m_ml, + cfunc); + Py_DECREF(cfunc); + } + } + Py_RETURN_NONE; +} + +PyObject* creturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) +{ + if (self->flags & POF_BUILTINS) { + PyObject* callable = args[2]; + PyObject* self_arg = args[3]; + + PyObject* cfunc = get_cfunc_from_callable(callable, self_arg, self->missing); + + if (cfunc) { + ptrace_leave_call((PyObject*)self, + ((PyCFunctionObject *)cfunc)->m_ml); + Py_DECREF(cfunc); + } + } + Py_RETURN_NONE; +} + +static const struct { + int event; + const char* callback_method; +} callback_table[] = { + {PY_MONITORING_EVENT_PY_START, "_pystart_callback"}, + {PY_MONITORING_EVENT_PY_RESUME, "_pystart_callback"}, + {PY_MONITORING_EVENT_PY_RETURN, "_pyreturn_callback"}, + {PY_MONITORING_EVENT_PY_YIELD, "_pyreturn_callback"}, + {PY_MONITORING_EVENT_PY_UNWIND, "_pyreturn_callback"}, + {PY_MONITORING_EVENT_CALL, "_ccall_callback"}, + {PY_MONITORING_EVENT_C_RETURN, "_creturn_callback"}, + {PY_MONITORING_EVENT_C_RAISE, "_creturn_callback"}, + {0, NULL} +}; + PyDoc_STRVAR(enable_doc, "\ enable(subcalls=True, builtins=True)\n\ \n\ @@ -666,6 +703,8 @@ profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) int subcalls = -1; int builtins = -1; static char *kwlist[] = {"subcalls", "builtins", 0}; + int all_events = 0; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|pp:enable", kwlist, &subcalls, &builtins)) return NULL; @@ -673,11 +712,37 @@ profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) return NULL; } - PyThreadState *tstate = _PyThreadState_GET(); - if (_PyEval_SetProfile(tstate, profiler_callback, (PyObject*)self) < 0) { + PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); + if (!monitoring) { + return NULL; + } + + if (PyObject_CallMethod(monitoring, "use_tool_id", "is", self->tool_id, "cProfile") == NULL) { + PyErr_Format(PyExc_ValueError, "Another profiling tool is already active"); + Py_DECREF(monitoring); + return NULL; + } + + for (int i = 0; callback_table[i].callback_method; i++) { + PyObject* callback = PyObject_GetAttrString((PyObject*)self, callback_table[i].callback_method); + if (!callback) { + Py_DECREF(monitoring); + return NULL; + } + Py_XDECREF(PyObject_CallMethod(monitoring, "register_callback", "iiO", self->tool_id, + (1 << callback_table[i].event), + callback)); + Py_DECREF(callback); + all_events |= (1 << callback_table[i].event); + } + + if (!PyObject_CallMethod(monitoring, "set_events", "ii", self->tool_id, all_events)) { + Py_DECREF(monitoring); return NULL; } + Py_DECREF(monitoring); + self->flags |= POF_ENABLED; Py_RETURN_NONE; } @@ -707,13 +772,44 @@ Stop collecting profiling information.\n\ static PyObject* profiler_disable(ProfilerObject *self, PyObject* noarg) { - PyThreadState *tstate = _PyThreadState_GET(); - if (_PyEval_SetProfile(tstate, NULL, NULL) < 0) { - return NULL; + if (self->flags & POF_ENABLED) { + PyObject* result = NULL; + PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); + + if (!monitoring) { + return NULL; + } + + for (int i = 0; callback_table[i].callback_method; i++) { + result = PyObject_CallMethod(monitoring, "register_callback", "iiO", self->tool_id, + (1 << callback_table[i].event), Py_None); + if (!result) { + Py_DECREF(monitoring); + return NULL; + } + Py_DECREF(result); + } + + result = PyObject_CallMethod(monitoring, "set_events", "ii", self->tool_id, 0); + if (!result) { + Py_DECREF(monitoring); + return NULL; + } + Py_DECREF(result); + + result = PyObject_CallMethod(monitoring, "free_tool_id", "i", self->tool_id); + if (!result) { + Py_DECREF(monitoring); + return NULL; + } + Py_DECREF(result); + + Py_DECREF(monitoring); + + self->flags &= ~POF_ENABLED; + flush_unmatched(self); } - self->flags &= ~POF_ENABLED; - flush_unmatched(self); if (pending_exception(self)) { return NULL; } @@ -778,17 +874,37 @@ profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) return -1; pObj->externalTimerUnit = timeunit; Py_XSETREF(pObj->externalTimer, Py_XNewRef(timer)); + pObj->tool_id = PY_MONITORING_PROFILER_ID; + + PyObject* monitoring = _PyImport_GetModuleAttrString("sys", "monitoring"); + if (!monitoring) { + return -1; + } + pObj->missing = PyObject_GetAttrString(monitoring, "MISSING"); + if (!pObj->missing) { + Py_DECREF(monitoring); + return -1; + } + Py_DECREF(monitoring); return 0; } static PyMethodDef profiler_methods[] = { _LSPROF_PROFILER_GETSTATS_METHODDEF - {"enable", _PyCFunction_CAST(profiler_enable), + {"enable", _PyCFunction_CAST(profiler_enable), METH_VARARGS | METH_KEYWORDS, enable_doc}, - {"disable", (PyCFunction)profiler_disable, + {"disable", (PyCFunction)profiler_disable, METH_NOARGS, disable_doc}, - {"clear", (PyCFunction)profiler_clear, + {"clear", (PyCFunction)profiler_clear, METH_NOARGS, clear_doc}, + {"_pystart_callback", _PyCFunction_CAST(pystart_callback), + METH_FASTCALL, NULL}, + {"_pyreturn_callback", _PyCFunction_CAST(pyreturn_callback), + METH_FASTCALL, NULL}, + {"_ccall_callback", _PyCFunction_CAST(ccall_callback), + METH_FASTCALL, NULL}, + {"_creturn_callback", _PyCFunction_CAST(creturn_callback), + METH_FASTCALL, NULL}, {NULL, NULL} }; diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index fee493ff7f16..7ba116dcb171 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -216,6 +216,7 @@ Modules/_io/_iomodule.c - static_types - Modules/_io/textio.c - encodefuncs - Modules/_io/winconsoleio.c - _PyWindowsConsoleIO_Type - Modules/_localemodule.c - langinfo_constants - +Modules/_lsprof.c - callback_table - Modules/_pickle.c - READ_WHOLE_LINE - Modules/_sqlite/module.c - error_codes - Modules/_sre/sre.c pattern_repr flag_names - From webhook-mailer at python.org Fri May 5 14:52:32 2023 From: webhook-mailer at python.org (orsenthil) Date: Fri, 05 May 2023 18:52:32 -0000 Subject: [Python-checkins] gh-69152: Add _proxy_response_headers attribute to HTTPConnection (#26152) Message-ID: <mailman.186.1683312752.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1afe0e0320c6f19418d44d682ad95ba0c689c595 commit: 1afe0e0320c6f19418d44d682ad95ba0c689c595 branch: main author: Alexey Namyotkin <62434915+nametkin at users.noreply.github.com> committer: orsenthil <senthilx at amazon.com> date: 2023-05-05T18:52:24Z summary: gh-69152: Add _proxy_response_headers attribute to HTTPConnection (#26152) Add _proxy_response_headers attribute to HTTPConnection (#26152) --------- Co-authored-by: Senthil Kumaran <senthil at python.org> files: A Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst M Lib/http/client.py M Lib/test/test_httplib.py diff --git a/Lib/http/client.py b/Lib/http/client.py index 74f7bcb68fb6..50f2b4680769 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -858,6 +858,7 @@ def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, self._tunnel_host = None self._tunnel_port = None self._tunnel_headers = {} + self._proxy_response_headers = None (self.host, self.port) = self._get_hostport(host, port) @@ -944,21 +945,16 @@ def _tunnel(self): try: (version, code, message) = response._read_status() + self._proxy_response_headers = parse_headers(response.fp) + + if self.debuglevel > 0: + for hdr, val in self._proxy_response_headers.items(): + print("header:", hdr + ":", val) + if code != http.HTTPStatus.OK: self.close() raise OSError(f"Tunnel connection failed: {code} {message.strip()}") - while True: - line = response.fp.readline(_MAXLINE + 1) - if len(line) > _MAXLINE: - raise LineTooLong("header line") - if not line: - # for sites which EOF without sending a trailer - break - if line in (b'\r\n', b'\n', b''): - break - if self.debuglevel > 0: - print('header:', line.decode()) finally: response.close() diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 37f77fe0a320..4b1d355f550b 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2390,6 +2390,20 @@ def test_tunnel_debuglog(self): lines = output.getvalue().splitlines() self.assertIn('header: {}'.format(expected_header), lines) + def test_proxy_response_headers(self): + expected_header = ('X-Dummy', '1') + response_text = ( + 'HTTP/1.0 200 OK\r\n' + '{0}\r\n\r\n'.format(':'.join(expected_header)) + ) + + self.conn._create_connection = self._create_connection(response_text) + self.conn.set_tunnel('destination.com') + + self.conn.request('PUT', '/', '') + headers = self.conn._proxy_response_headers + self.assertIn(expected_header, headers.items()) + def test_tunnel_leak(self): sock = None diff --git a/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst b/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst new file mode 100644 index 000000000000..ba113673b7fb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst @@ -0,0 +1,3 @@ +Added attribute '_proxy_response_headers' to HTTPConnection class. This +attribute contains the headers of the proxy server response to the CONNECT +request. From webhook-mailer at python.org Fri May 5 15:05:00 2023 From: webhook-mailer at python.org (barneygale) Date: Fri, 05 May 2023 19:05:00 -0000 Subject: [Python-checkins] GH-100479: Add `pathlib.PurePath.with_segments()` (GH-103975) Message-ID: <mailman.187.1683313501.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d00d94214971621e6a3541425ee8c8072023ca1a commit: d00d94214971621e6a3541425ee8c8072023ca1a branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-05T19:04:53Z summary: GH-100479: Add `pathlib.PurePath.with_segments()` (GH-103975) Add `pathlib.PurePath.with_segments()`, which creates a path object from arguments. This method is called whenever a derivative path is created, such as from `pathlib.PurePath.parent`. Subclasses may override this method to share information between path objects. Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: A Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst M Doc/library/pathlib.rst M Doc/whatsnew/3.12.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 14118127835b..5ffa33d4e61f 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -530,10 +530,10 @@ Pure paths provide the following methods and properties: unintended effects. -.. method:: PurePath.joinpath(*other) +.. method:: PurePath.joinpath(*pathsegments) Calling this method is equivalent to combining the path with each of - the *other* arguments in turn:: + the given *pathsegments* in turn:: >>> PurePosixPath('/etc').joinpath('passwd') PurePosixPath('/etc/passwd') @@ -680,6 +680,30 @@ Pure paths provide the following methods and properties: PureWindowsPath('README') +.. method:: PurePath.with_segments(*pathsegments) + + Create a new path object of the same type by combining the given + *pathsegments*. This method is called whenever a derivative path is created, + such as from :attr:`parent` and :meth:`relative_to`. Subclasses may + override this method to pass information to derivative paths, for example:: + + from pathlib import PurePosixPath + + class MyPath(PurePosixPath): + def __init__(self, *pathsegments, session_id): + super().__init__(*pathsegments) + self.session_id = session_id + + def with_segments(self, *pathsegments): + return type(self)(*pathsegments, session_id=self.session_id) + + etc = MyPath('/etc', session_id=42) + hosts = etc / 'hosts' + print(hosts.session_id) # 42 + + .. versionadded:: 3.12 + + .. _concrete-paths: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4f952e2a37ef..ccddc8bd832f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -348,6 +348,11 @@ inspect pathlib ------- +* Add support for subclassing :class:`pathlib.PurePath` and + :class:`~pathlib.Path`, plus their Posix- and Windows-specific variants. + Subclasses may override the :meth:`~pathlib.PurePath.with_segments` method + to pass information between path instances. + * Add :meth:`~pathlib.Path.walk` for walking the directory trees and generating all file or directory names within them, similar to :func:`os.walk`. (Contributed by Stanislav Zmiev in :gh:`90385`.) diff --git a/Lib/pathlib.py b/Lib/pathlib.py index f32e1e2d8228..9aa3c1e52447 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -204,11 +204,10 @@ def _select_from(self, parent_path, scandir): 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', '_tail') + __slots__ = ('_path', '_drv', '_root', '_tail') def __init__(self, path): - # We don't store the instance to avoid reference cycles - self._pathcls = type(path) + self._path = path self._drv = path.drive self._root = path.root self._tail = path._tail @@ -224,11 +223,11 @@ def __getitem__(self, idx): raise IndexError(idx) if idx < 0: idx += len(self) - return self._pathcls._from_parsed_parts(self._drv, self._root, - self._tail[:-idx - 1]) + return self._path._from_parsed_parts(self._drv, self._root, + self._tail[:-idx - 1]) def __repr__(self): - return "<{}.parents>".format(self._pathcls.__name__) + return "<{}.parents>".format(type(self._path).__name__) class PurePath(object): @@ -316,6 +315,13 @@ def __init__(self, *args): else: self._raw_path = self._flavour.join(*paths) + def with_segments(self, *pathsegments): + """Construct a new path object from any number of path-like objects. + Subclasses may override this method to customize how new path objects + are created from methods like `iterdir()`. + """ + return type(self)(*pathsegments) + @classmethod def _parse_path(cls, path): if not path: @@ -342,15 +348,14 @@ def _load_parts(self): self._root = root self._tail_cached = tail - @classmethod - 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._tail_cached = tail - return self + def _from_parsed_parts(self, drv, root, tail): + path_str = self._format_parsed_parts(drv, root, tail) + path = self.with_segments(path_str) + path._str = path_str or '.' + path._drv = drv + path._root = root + path._tail_cached = tail + return path @classmethod def _format_parsed_parts(cls, drv, root, tail): @@ -584,8 +589,7 @@ def relative_to(self, other, /, *_deprecated, walk_up=False): "scheduled for removal in Python {remove}") warnings._deprecated("pathlib.PurePath.relative_to(*args)", msg, remove=(3, 14)) - path_cls = type(self) - other = path_cls(other, *_deprecated) + other = self.with_segments(other, *_deprecated) for step, path in enumerate([other] + list(other.parents)): if self.is_relative_to(path): break @@ -594,7 +598,7 @@ def relative_to(self, other, /, *_deprecated, walk_up=False): if step and not walk_up: raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") parts = ['..'] * step + self._tail[len(path._tail):] - return path_cls(*parts) + return self.with_segments(*parts) def is_relative_to(self, other, /, *_deprecated): """Return True if the path is relative to another path or False. @@ -605,7 +609,7 @@ def is_relative_to(self, other, /, *_deprecated): "scheduled for removal in Python {remove}") warnings._deprecated("pathlib.PurePath.is_relative_to(*args)", msg, remove=(3, 14)) - other = type(self)(other, *_deprecated) + other = self.with_segments(other, *_deprecated) return other == self or other in self.parents @property @@ -617,13 +621,13 @@ def parts(self): else: return tuple(self._tail) - def joinpath(self, *args): + def joinpath(self, *pathsegments): """Combine this path with one or several arguments, and return a new path representing either a subpath (if all arguments are relative paths) or a totally different path (if one of the arguments is anchored). """ - return self.__class__(self, *args) + return self.with_segments(self, *pathsegments) def __truediv__(self, key): try: @@ -633,7 +637,7 @@ def __truediv__(self, key): def __rtruediv__(self, key): try: - return type(self)(key, self) + return self.with_segments(key, self) except TypeError: return NotImplemented @@ -650,6 +654,8 @@ def parent(self): @property def parents(self): """A sequence of this path's logical parents.""" + # The value of this property should not be cached on the path object, + # as doing so would introduce a reference cycle. return _PathParents(self) def is_absolute(self): @@ -680,7 +686,7 @@ def match(self, path_pattern): """ Return True if this path matches the given pattern. """ - pat = type(self)(path_pattern) + pat = self.with_segments(path_pattern) if not pat.parts: raise ValueError("empty pattern") pat_parts = pat._parts_normcase @@ -755,7 +761,7 @@ def _make_child_relpath(self, name): path_str = f'{path_str}{name}' else: path_str = name - path = type(self)(path_str) + path = self.with_segments(path_str) path._str = path_str path._drv = self.drive path._root = self.root @@ -805,7 +811,7 @@ def samefile(self, other_path): try: other_st = other_path.stat() except AttributeError: - other_st = self.__class__(other_path).stat() + other_st = self.with_segments(other_path).stat() return self._flavour.samestat(st, other_st) def iterdir(self): @@ -867,7 +873,7 @@ def absolute(self): cwd = self._flavour.abspath(self.drive) else: cwd = os.getcwd() - return type(self)(cwd, self) + return self.with_segments(cwd, self) def resolve(self, strict=False): """ @@ -885,7 +891,7 @@ def check_eloop(e): except OSError as e: check_eloop(e) raise - p = type(self)(s) + p = self.with_segments(s) # In non-strict mode, realpath() doesn't raise on symlink loops. # Ensure we get an exception by calling stat() @@ -975,7 +981,7 @@ def readlink(self): """ if not hasattr(os, "readlink"): raise NotImplementedError("os.readlink() not available on this system") - return type(self)(os.readlink(self)) + return self.with_segments(os.readlink(self)) def touch(self, mode=0o666, exist_ok=True): """ @@ -1064,7 +1070,7 @@ def rename(self, target): Returns the new Path instance pointing to the target path. """ os.rename(self, target) - return self.__class__(target) + return self.with_segments(target) def replace(self, target): """ @@ -1077,7 +1083,7 @@ def replace(self, target): Returns the new Path instance pointing to the target path. """ os.replace(self, target) - return self.__class__(target) + return self.with_segments(target) def symlink_to(self, target, target_is_directory=False): """ diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index a932e03df423..7586610833b0 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -29,11 +29,12 @@ # class _BasePurePathSubclass(object): - init_called = False + def __init__(self, *pathsegments, session_id): + super().__init__(*pathsegments) + self.session_id = session_id - def __init__(self, *args): - super().__init__(*args) - self.init_called = True + def with_segments(self, *pathsegments): + return type(self)(*pathsegments, session_id=self.session_id) class _BasePurePathTest(object): @@ -121,20 +122,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): + def test_with_segments_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) + p = P('foo', 'bar', session_id=42) + self.assertEqual(42, (p / 'foo').session_id) + self.assertEqual(42, ('foo' / p).session_id) + self.assertEqual(42, p.joinpath('foo').session_id) + self.assertEqual(42, p.with_name('foo').session_id) + self.assertEqual(42, p.with_stem('foo').session_id) + self.assertEqual(42, p.with_suffix('.foo').session_id) + self.assertEqual(42, p.with_segments('foo').session_id) + self.assertEqual(42, p.relative_to('foo').session_id) + self.assertEqual(42, p.parent.session_id) for parent in p.parents: - self.assertTrue(parent.init_called) + self.assertEqual(42, parent.session_id) def _get_drive_root_parts(self, parts): path = self.cls(*parts) @@ -1647,6 +1649,26 @@ def test_home(self): env['HOME'] = os.path.join(BASE, 'home') self._test_home(self.cls.home()) + def test_with_segments(self): + class P(_BasePurePathSubclass, self.cls): + pass + p = P(BASE, session_id=42) + self.assertEqual(42, p.absolute().session_id) + self.assertEqual(42, p.resolve().session_id) + self.assertEqual(42, p.with_segments('~').expanduser().session_id) + self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id) + self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id) + if os_helper.can_symlink(): + self.assertEqual(42, (p / 'linkA').readlink().session_id) + for path in p.iterdir(): + self.assertEqual(42, path.session_id) + for path in p.glob('*'): + self.assertEqual(42, path.session_id) + for path in p.rglob('*'): + self.assertEqual(42, path.session_id) + for dirpath, dirnames, filenames in p.walk(): + self.assertEqual(42, dirpath.session_id) + def test_samefile(self): fileA_path = os.path.join(BASE, 'fileA') fileB_path = os.path.join(BASE, 'dirB', 'fileB') diff --git a/Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst b/Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst new file mode 100644 index 000000000000..58db90480d2f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst @@ -0,0 +1,4 @@ +Add :meth:`pathlib.PurePath.with_segments`, which creates a path object from +arguments. This method is called whenever a derivative path is created, such +as from :attr:`pathlib.PurePath.parent`. Subclasses may override this method +to share information between path objects. From webhook-mailer at python.org Fri May 5 15:23:07 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Fri, 05 May 2023 19:23:07 -0000 Subject: [Python-checkins] gh-99113: Share the GIL via PyInterpreterState.ceval.gil (gh-104203) Message-ID: <mailman.188.1683314589.13550.python-checkins@python.org> https://github.com/python/cpython/commit/55671fe04700ccb4e73c8db3dd1e9c031dafe700 commit: 55671fe04700ccb4e73c8db3dd1e9c031dafe700 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-05T13:23:00-06:00 summary: gh-99113: Share the GIL via PyInterpreterState.ceval.gil (gh-104203) In preparation for a per-interpreter GIL, we add PyInterpreterState.ceval.gil, set it to the shared GIL for each interpreter, and use that rather than using _PyRuntime.ceval.gil directly. Note that _PyRuntime.ceval.gil is still the actual GIL. files: M Include/internal/pycore_ceval.h M Include/internal/pycore_ceval_state.h M Modules/_xxsubinterpretersmodule.c M Python/ceval_gil.c M Python/pystate.c diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index deda070a6dea..0bbc9efdda3b 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -96,7 +96,7 @@ _PyEval_Vector(PyThreadState *tstate, PyObject* const* args, size_t argcount, PyObject *kwnames); -extern int _PyEval_ThreadsInitialized(struct pyruntimestate *runtime); +extern int _PyEval_ThreadsInitialized(void); extern PyStatus _PyEval_InitGIL(PyThreadState *tstate); extern void _PyEval_FiniGIL(PyInterpreterState *interp); diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index 9ba42eb03b26..1a00ec80270e 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -49,6 +49,8 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; + + /* This is (only) used indirectly through PyInterpreterState.ceval.gil. */ struct _gil_runtime_state gil; }; @@ -83,6 +85,7 @@ struct _pending_calls { struct _ceval_state { int recursion_limit; + struct _gil_runtime_state *gil; /* This single variable consolidates all requests to break out of the fast path in the eval loop. */ _Py_atomic_int eval_breaker; diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 95273ab278d9..433fecfda655 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -513,6 +513,7 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) // Create and initialize the new interpreter. PyThreadState *save_tstate = _PyThreadState_GET(); + assert(save_tstate != NULL); const PyInterpreterConfig config = isolated ? (PyInterpreterConfig)_PyInterpreterConfig_INIT : (PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 4d501c896617..ad33a58dedd8 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -229,6 +229,9 @@ static void _gil_initialize(struct _gil_runtime_state *gil) static int gil_created(struct _gil_runtime_state *gil) { + if (gil == NULL) { + return 0; + } return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0); } @@ -273,10 +276,9 @@ static void recreate_gil(struct _gil_runtime_state *gil) #endif static void -drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, - PyThreadState *tstate) +drop_gil(struct _ceval_state *ceval, PyThreadState *tstate) { - struct _gil_runtime_state *gil = &ceval->gil; + struct _gil_runtime_state *gil = ceval->gil; if (!_Py_atomic_load_relaxed(&gil->locked)) { Py_FatalError("drop_gil: GIL is not locked"); } @@ -296,7 +298,7 @@ drop_gil(struct _ceval_runtime_state *ceval, struct _ceval_state *ceval2, MUTEX_UNLOCK(gil->mutex); #ifdef FORCE_SWITCHING - if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request) && tstate != NULL) { + if (_Py_atomic_load_relaxed(&ceval->gil_drop_request) && tstate != NULL) { MUTEX_LOCK(gil->switch_mutex); /* Not switched yet => wait */ if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) == tstate) @@ -358,9 +360,8 @@ take_gil(PyThreadState *tstate) assert(is_tstate_valid(tstate)); PyInterpreterState *interp = tstate->interp; - struct _ceval_runtime_state *ceval = &interp->runtime->ceval; - struct _ceval_state *ceval2 = &interp->ceval; - struct _gil_runtime_state *gil = &ceval->gil; + struct _ceval_state *ceval = &interp->ceval; + struct _gil_runtime_state *gil = ceval->gil; /* Check that _PyEval_InitThreads() was called to create the lock */ assert(gil_created(gil)); @@ -434,12 +435,12 @@ take_gil(PyThreadState *tstate) in take_gil() while the main thread called wait_for_thread_shutdown() from Py_Finalize(). */ MUTEX_UNLOCK(gil->mutex); - drop_gil(ceval, ceval2, tstate); + drop_gil(ceval, tstate); PyThread_exit_thread(); } assert(is_tstate_valid(tstate)); - if (_Py_atomic_load_relaxed(&ceval2->gil_drop_request)) { + if (_Py_atomic_load_relaxed(&ceval->gil_drop_request)) { RESET_GIL_DROP_REQUEST(interp); } else { @@ -448,7 +449,7 @@ take_gil(PyThreadState *tstate) handle signals. Note: RESET_GIL_DROP_REQUEST() calls COMPUTE_EVAL_BREAKER(). */ - COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); + COMPUTE_EVAL_BREAKER(interp, &_PyRuntime.ceval, ceval); } /* Don't access tstate if the thread must exit */ @@ -463,63 +464,86 @@ take_gil(PyThreadState *tstate) void _PyEval_SetSwitchInterval(unsigned long microseconds) { - struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil; + /* XXX per-interpreter GIL */ + PyInterpreterState *interp = _PyInterpreterState_Main(); + struct _gil_runtime_state *gil = interp->ceval.gil; + assert(gil != NULL); gil->interval = microseconds; } unsigned long _PyEval_GetSwitchInterval(void) { - struct _gil_runtime_state *gil = &_PyRuntime.ceval.gil; + /* XXX per-interpreter GIL */ + PyInterpreterState *interp = _PyInterpreterState_Main(); + struct _gil_runtime_state *gil = interp->ceval.gil; + assert(gil != NULL); return gil->interval; } int -_PyEval_ThreadsInitialized(_PyRuntimeState *runtime) +_PyEval_ThreadsInitialized(void) { - return gil_created(&runtime->ceval.gil); + /* XXX per-interpreter GIL */ + PyInterpreterState *interp = _PyInterpreterState_Main(); + if (interp == NULL) { + return 0; + } + struct _gil_runtime_state *gil = interp->ceval.gil; + return gil_created(gil); } int PyEval_ThreadsInitialized(void) { - _PyRuntimeState *runtime = &_PyRuntime; - return _PyEval_ThreadsInitialized(runtime); + return _PyEval_ThreadsInitialized(); } PyStatus _PyEval_InitGIL(PyThreadState *tstate) { + assert(tstate->interp->ceval.gil == NULL); + + /* XXX per-interpreter GIL */ + struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; if (!_Py_IsMainInterpreter(tstate->interp)) { /* Currently, the GIL is shared by all interpreters, and only the main interpreter is responsible to create and destroy it. */ + assert(gil_created(gil)); + tstate->interp->ceval.gil = gil; return _PyStatus_OK(); } - struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; assert(!gil_created(gil)); PyThread_init_thread(); create_gil(gil); - - take_gil(tstate); - assert(gil_created(gil)); + tstate->interp->ceval.gil = gil; + take_gil(tstate); return _PyStatus_OK(); } void _PyEval_FiniGIL(PyInterpreterState *interp) { + if (interp->ceval.gil == NULL) { + /* It was already finalized (or hasn't been initialized yet). */ + return; + } + + /* XXX per-interpreter GIL */ + struct _gil_runtime_state *gil = &interp->runtime->ceval.gil; if (!_Py_IsMainInterpreter(interp)) { /* Currently, the GIL is shared by all interpreters, and only the main interpreter is responsible to create and destroy it. */ + assert(interp->ceval.gil == gil); + interp->ceval.gil = NULL; return; } - struct _gil_runtime_state *gil = &interp->runtime->ceval.gil; if (!gil_created(gil)) { /* First Py_InitializeFromConfig() call: the GIL doesn't exist yet: do nothing. */ @@ -528,6 +552,7 @@ _PyEval_FiniGIL(PyInterpreterState *interp) destroy_gil(gil); assert(!gil_created(gil)); + interp->ceval.gil = NULL; } void @@ -555,22 +580,19 @@ PyEval_AcquireLock(void) void PyEval_ReleaseLock(void) { - _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = _PyThreadState_GET(); /* This function must succeed when the current thread state is NULL. We therefore avoid PyThreadState_Get() which dumps a fatal error in debug mode. */ - struct _ceval_runtime_state *ceval = &runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - drop_gil(ceval, ceval2, tstate); + struct _ceval_state *ceval = &tstate->interp->ceval; + drop_gil(ceval, tstate); } void _PyEval_ReleaseLock(PyThreadState *tstate) { - struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - drop_gil(ceval, ceval2, tstate); + struct _ceval_state *ceval = &tstate->interp->ceval; + drop_gil(ceval, tstate); } void @@ -595,9 +617,8 @@ PyEval_ReleaseThread(PyThreadState *tstate) if (new_tstate != tstate) { Py_FatalError("wrong thread state"); } - struct _ceval_runtime_state *ceval = &runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - drop_gil(ceval, ceval2, tstate); + struct _ceval_state *ceval = &tstate->interp->ceval; + drop_gil(ceval, tstate); } #ifdef HAVE_FORK @@ -607,9 +628,9 @@ PyEval_ReleaseThread(PyThreadState *tstate) PyStatus _PyEval_ReInitThreads(PyThreadState *tstate) { - _PyRuntimeState *runtime = tstate->interp->runtime; + assert(tstate->interp == _PyInterpreterState_Main()); - struct _gil_runtime_state *gil = &runtime->ceval.gil; + struct _gil_runtime_state *gil = tstate->interp->ceval.gil; if (!gil_created(gil)) { return _PyStatus_OK(); } @@ -644,10 +665,9 @@ PyEval_SaveThread(void) PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL); _Py_EnsureTstateNotNULL(tstate); - struct _ceval_runtime_state *ceval = &runtime->ceval; - struct _ceval_state *ceval2 = &tstate->interp->ceval; - assert(gil_created(&ceval->gil)); - drop_gil(ceval, ceval2, tstate); + struct _ceval_state *ceval = &tstate->interp->ceval; + assert(gil_created(ceval->gil)); + drop_gil(ceval, tstate); return tstate; } @@ -906,6 +926,7 @@ Py_MakePendingCalls(void) void _PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval) { + /* XXX per-interpreter GIL */ _gil_initialize(&ceval->gil); } @@ -964,7 +985,7 @@ _Py_HandlePending(PyThreadState *tstate) if (_PyThreadState_Swap(runtime, NULL) != tstate) { Py_FatalError("tstate mix-up"); } - drop_gil(ceval, interp_ceval_state, tstate); + drop_gil(interp_ceval_state, tstate); /* Other threads may run now */ diff --git a/Python/pystate.c b/Python/pystate.c index f09d37657f9c..75bd9f41e301 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2186,7 +2186,7 @@ PyGILState_Ensure(void) /* Ensure that _PyEval_InitThreads() and _PyGILState_Init() have been called by Py_Initialize() */ - assert(_PyEval_ThreadsInitialized(runtime)); + assert(_PyEval_ThreadsInitialized()); assert(gilstate_tss_initialized(runtime)); assert(runtime->gilstate.autoInterpreterState != NULL); From webhook-mailer at python.org Fri May 5 16:05:02 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Fri, 05 May 2023 20:05:02 -0000 Subject: [Python-checkins] gh-104108: Add the Py_mod_multiple_interpreters Module Def Slot (gh-104148) Message-ID: <mailman.189.1683317103.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1c420e138fd828895b6bd3c44ef99156e8796095 commit: 1c420e138fd828895b6bd3c44ef99156e8796095 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-05T14:04:55-06:00 summary: gh-104108: Add the Py_mod_multiple_interpreters Module Def Slot (gh-104148) I'll be adding a value to indicate support for per-interpreter GIL in gh-99114. files: A Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst M Include/moduleobject.h M Lib/test/test_import/__init__.py M Modules/_testmultiphase.c M Objects/moduleobject.c diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 555564ec73b4..7ac6f6e8a4a2 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -78,11 +78,16 @@ struct PyModuleDef_Slot { #define Py_mod_create 1 #define Py_mod_exec 2 +#define Py_mod_multiple_interpreters 3 #ifndef Py_LIMITED_API -#define _Py_mod_LAST_SLOT 2 +#define _Py_mod_LAST_SLOT 3 #endif +/* for Py_mod_multiple_interpreters: */ +#define Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED ((void *)0) +#define Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED ((void *)1) + #endif /* New in 3.5 */ struct PyModuleDef { diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 41dfdaabe246..9211639b016e 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1652,26 +1652,44 @@ def pipe(self): os.set_blocking(r, False) return (r, w) - def import_script(self, name, fd, check_override=None): + def import_script(self, name, fd, filename=None, check_override=None): override_text = '' if check_override is not None: override_text = f''' - import _imp - _imp._override_multi_interp_extensions_check({check_override}) - ''' - return textwrap.dedent(f''' - import os, sys - {override_text} - try: - import {name} - except ImportError as exc: - text = 'ImportError: ' + str(exc) - else: - text = 'okay' - os.write({fd}, text.encode('utf-8')) - ''') + import _imp + _imp._override_multi_interp_extensions_check({check_override}) + ''' + if filename: + return textwrap.dedent(f''' + from importlib.util import spec_from_loader, module_from_spec + from importlib.machinery import ExtensionFileLoader + import os, sys + {override_text} + loader = ExtensionFileLoader({name!r}, {filename!r}) + spec = spec_from_loader({name!r}, loader) + try: + module = module_from_spec(spec) + loader.exec_module(module) + except ImportError as exc: + text = 'ImportError: ' + str(exc) + else: + text = 'okay' + os.write({fd}, text.encode('utf-8')) + ''') + else: + return textwrap.dedent(f''' + import os, sys + {override_text} + try: + import {name} + except ImportError as exc: + text = 'ImportError: ' + str(exc) + else: + text = 'okay' + os.write({fd}, text.encode('utf-8')) + ''') - def run_here(self, name, *, + def run_here(self, name, filename=None, *, check_singlephase_setting=False, check_singlephase_override=None, isolated=False, @@ -1700,26 +1718,30 @@ def run_here(self, name, *, ) r, w = self.pipe() - script = self.import_script(name, w, check_singlephase_override) + script = self.import_script(name, w, filename, + check_singlephase_override) ret = run_in_subinterp_with_config(script, **kwargs) self.assertEqual(ret, 0) return os.read(r, 100) - def check_compatible_here(self, name, *, strict=False, isolated=False): + def check_compatible_here(self, name, filename=None, *, + strict=False, + isolated=False, + ): # Verify that the named module may be imported in a subinterpreter. # (See run_here() for more info.) - out = self.run_here(name, + out = self.run_here(name, filename, check_singlephase_setting=strict, isolated=isolated, ) self.assertEqual(out, b'okay') - def check_incompatible_here(self, name, *, isolated=False): + def check_incompatible_here(self, name, filename=None, *, isolated=False): # Differences from check_compatible_here(): # * verify that import fails # * "strict" is always True - out = self.run_here(name, + out = self.run_here(name, filename, check_singlephase_setting=True, isolated=isolated, ) @@ -1820,6 +1842,24 @@ def test_multi_init_extension_compat(self): with self.subTest(f'{module}: strict, fresh'): self.check_compatible_fresh(module, strict=True) + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + def test_multi_init_extension_non_isolated_compat(self): + modname = '_test_non_isolated' + filename = _testmultiphase.__file__ + loader = ExtensionFileLoader(modname, filename) + spec = importlib.util.spec_from_loader(modname, loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + sys.modules[modname] = module + + require_extension(module) + with self.subTest(f'{modname}: isolated'): + self.check_incompatible_here(modname, filename, isolated=True) + with self.subTest(f'{modname}: not isolated'): + self.check_incompatible_here(modname, filename, isolated=False) + with self.subTest(f'{modname}: not strict'): + self.check_compatible_here(modname, filename, strict=False) + def test_python_compat(self): module = 'threading' require_pure_python(module) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst new file mode 100644 index 000000000000..dad843636493 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst @@ -0,0 +1,6 @@ +Multi-phase init extension modules may now indicate whether or not they +actually support multiple interpreters. By default such modules are +expected to support use in multiple interpreters. In the uncommon case that +one does not, it may use the new ``Py_mod_multiple_interpreters`` module def +slot. A value of ``0`` means the module does not support them. ``1`` means +it does. The default is ``1``. diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index cf8990a2df0a..bc7d8b64a943 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -884,3 +884,22 @@ PyInit__test_module_state_shared(void) } return module; } + + +/* multiple interpreters supports */ + +static PyModuleDef_Slot non_isolated_slots[] = { + {Py_mod_exec, execfunc}, + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {0, NULL}, +}; + +static PyModuleDef non_isolated_def = TEST_MODULE_DEF("_test_non_isolated", + non_isolated_slots, + testexport_methods); + +PyMODINIT_FUNC +PyInit__test_non_isolated(void) +{ + return PyModuleDef_Init(&non_isolated_def); +} diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index ffcd90ed122e..63f4226dd9e9 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -245,6 +245,8 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio PyObject *(*create)(PyObject *, PyModuleDef*) = NULL; PyObject *nameobj; PyObject *m = NULL; + int has_multiple_interpreters_slot = 0; + void *multiple_interpreters = (void *)0; int has_execution_slots = 0; const char *name; int ret; @@ -287,6 +289,17 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio case Py_mod_exec: has_execution_slots = 1; break; + case Py_mod_multiple_interpreters: + if (has_multiple_interpreters_slot) { + PyErr_Format( + PyExc_SystemError, + "module %s has more than one 'multiple interpreters' slots", + name); + goto error; + } + multiple_interpreters = cur_slot->value; + has_multiple_interpreters_slot = 1; + break; default: assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT); PyErr_Format( @@ -297,6 +310,20 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio } } + /* By default, multi-phase init modules are expected + to work under multiple interpreters. */ + if (!has_multiple_interpreters_slot) { + multiple_interpreters = Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED; + } + if (multiple_interpreters == Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!_Py_IsMainInterpreter(interp) + && _PyImport_CheckSubinterpIncompatibleExtensionAllowed(name) < 0) + { + goto error; + } + } + if (create) { m = create(spec, def); if (m == NULL) { @@ -421,6 +448,9 @@ PyModule_ExecDef(PyObject *module, PyModuleDef *def) return -1; } break; + case Py_mod_multiple_interpreters: + /* handled in PyModule_FromDefAndSpec2 */ + break; default: PyErr_Format( PyExc_SystemError, From webhook-mailer at python.org Fri May 5 17:11:35 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Fri, 05 May 2023 21:11:35 -0000 Subject: [Python-checkins] gh-99113: Add Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-104205) Message-ID: <mailman.190.1683321096.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a9c6e0618f26270e2591b3d99ffeef55eea02a33 commit: a9c6e0618f26270e2591b3d99ffeef55eea02a33 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-05T21:11:27Z summary: gh-99113: Add Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-104205) Here we are doing no more than adding the value for Py_mod_multiple_interpreters and using it for stdlib modules. We will start checking for it in gh-104206 (once PyInterpreterState.ceval.own_gil is added in gh-104204). files: M Include/moduleobject.h M Modules/_abc.c M Modules/_asynciomodule.c M Modules/_bisectmodule.c M Modules/_blake2/blake2module.c M Modules/_bz2module.c M Modules/_codecsmodule.c M Modules/_collectionsmodule.c M Modules/_contextvarsmodule.c M Modules/_cryptmodule.c M Modules/_csv.c M Modules/_ctypes/_ctypes_test.c M Modules/_curses_panel.c M Modules/_dbmmodule.c M Modules/_elementtree.c M Modules/_functoolsmodule.c M Modules/_gdbmmodule.c M Modules/_hashopenssl.c M Modules/_heapqmodule.c M Modules/_json.c M Modules/_localemodule.c M Modules/_lsprof.c M Modules/_lzmamodule.c M Modules/_multiprocessing/multiprocessing.c M Modules/_multiprocessing/posixshmem.c M Modules/_opcode.c M Modules/_operator.c M Modules/_pickle.c M Modules/_posixsubprocess.c M Modules/_queuemodule.c M Modules/_randommodule.c M Modules/_scproxy.c M Modules/_sha3/sha3module.c M Modules/_sqlite/module.c M Modules/_sre/sre.c M Modules/_ssl.c M Modules/_stat.c M Modules/_statisticsmodule.c M Modules/_struct.c M Modules/_testinternalcapi.c M Modules/_testmultiphase.c M Modules/_threadmodule.c M Modules/_typingmodule.c M Modules/_uuidmodule.c M Modules/_weakref.c M Modules/_winapi.c M Modules/_xxinterpchannelsmodule.c M Modules/_xxsubinterpretersmodule.c M Modules/_zoneinfo.c M Modules/arraymodule.c M Modules/atexitmodule.c M Modules/audioop.c M Modules/binascii.c M Modules/cjkcodecs/cjkcodecs.h M Modules/cjkcodecs/multibytecodec.c M Modules/cmathmodule.c M Modules/errnomodule.c M Modules/faulthandler.c M Modules/fcntlmodule.c M Modules/gcmodule.c M Modules/grpmodule.c M Modules/itertoolsmodule.c M Modules/mathmodule.c M Modules/md5module.c M Modules/mmapmodule.c M Modules/nismodule.c M Modules/overlapped.c M Modules/posixmodule.c M Modules/pwdmodule.c M Modules/pyexpat.c M Modules/resource.c M Modules/selectmodule.c M Modules/sha1module.c M Modules/sha2module.c M Modules/signalmodule.c M Modules/socketmodule.c M Modules/spwdmodule.c M Modules/symtablemodule.c M Modules/syslogmodule.c M Modules/termios.c M Modules/timemodule.c M Modules/unicodedata.c M Modules/xxlimited.c M Modules/xxlimited_35.c M Modules/xxmodule.c M Modules/xxsubtype.c M Modules/zlibmodule.c M Objects/moduleobject.c M Objects/unicodeobject.c M PC/_testconsole.c M PC/msvcrtmodule.c M PC/winreg.c M PC/winsound.c M Parser/asdl_c.py M Python/Python-ast.c M Python/Python-tokenize.c M Python/_warnings.c M Python/import.c M Python/marshal.c diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 7ac6f6e8a4a2..b8bdfe29d804 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -87,6 +87,7 @@ struct PyModuleDef_Slot { /* for Py_mod_multiple_interpreters: */ #define Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED ((void *)0) #define Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED ((void *)1) +#define Py_MOD_PER_INTERPRETER_GIL_SUPPORTED ((void *)2) #endif /* New in 3.5 */ diff --git a/Modules/_abc.c b/Modules/_abc.c index 9694331339aa..d3e405dadb66 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -944,6 +944,7 @@ _abcmodule_free(void *module) static PyModuleDef_Slot _abcmodule_slots[] = { {Py_mod_exec, _abcmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index fef34d655238..822d5f2a41de 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -3803,6 +3803,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 30801c2f87ee..0773bbd19193 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -457,6 +457,7 @@ bisect_modexec(PyObject *m) static PyModuleDef_Slot bisect_slots[] = { {Py_mod_exec, bisect_modexec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c index 44d783b40d04..0d1d88c66036 100644 --- a/Modules/_blake2/blake2module.c +++ b/Modules/_blake2/blake2module.c @@ -127,6 +127,7 @@ blake2_exec(PyObject *m) static PyModuleDef_Slot _blake2_slots[] = { {Py_mod_exec, blake2_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; @@ -146,4 +147,4 @@ PyMODINIT_FUNC PyInit__blake2(void) { return PyModuleDef_Init(&blake2_module); -} \ No newline at end of file +} diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 8e7b8e8078af..97bd44b4ac96 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -799,6 +799,7 @@ _bz2_free(void *module) static struct PyModuleDef_Slot _bz2_slots[] = { {Py_mod_exec, _bz2_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index d5035d20600a..777c753bd7c2 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -1049,6 +1049,7 @@ static PyMethodDef _codecs_functions[] = { }; static PyModuleDef_Slot _codecs_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index a9b1425177c3..9a81531bdffb 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2571,6 +2571,7 @@ collections_exec(PyObject *module) { static struct PyModuleDef_Slot collections_slots[] = { {Py_mod_exec, collections_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_contextvarsmodule.c b/Modules/_contextvarsmodule.c index d13b5962c13c..f621c1de6d42 100644 --- a/Modules/_contextvarsmodule.c +++ b/Modules/_contextvarsmodule.c @@ -44,6 +44,7 @@ _contextvars_exec(PyObject *m) static struct PyModuleDef_Slot _contextvars_slots[] = { {Py_mod_exec, _contextvars_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_cryptmodule.c b/Modules/_cryptmodule.c index 72a4f44600d9..75035084c9cd 100644 --- a/Modules/_cryptmodule.c +++ b/Modules/_cryptmodule.c @@ -58,6 +58,7 @@ static PyMethodDef crypt_methods[] = { }; static PyModuleDef_Slot _crypt_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_csv.c b/Modules/_csv.c index 2217cc2ca7a7..0cde5c5a8bdc 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -1798,6 +1798,7 @@ csv_exec(PyObject *module) { static PyModuleDef_Slot csv_slots[] = { {Py_mod_exec, csv_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index a8811d03cc91..ce652b362d5b 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -1054,6 +1054,7 @@ _testfunc_pylist_append(PyObject *list, PyObject *item) } static struct PyModuleDef_Slot _ctypes_test_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 2144345de01b..a3124ff80551 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -690,6 +690,9 @@ _curses_panel_exec(PyObject *mod) static PyModuleDef_Slot _curses_slots[] = { {Py_mod_exec, _curses_panel_exec}, + // XXX gh-103092: fix isolation. + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 54376022dcb1..9908174c94c4 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -583,6 +583,7 @@ _dbm_module_free(void *module) static PyModuleDef_Slot _dbmmodule_slots[] = { {Py_mod_exec, _dbm_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 97be89a16710..42de3c675c2e 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -4419,6 +4419,9 @@ module_exec(PyObject *m) static struct PyModuleDef_Slot elementtree_slots[] = { {Py_mod_exec, module_exec}, + // XXX gh-103092: fix isolation. + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 4032ba79374f..a8001d71223f 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1520,6 +1520,7 @@ _functools_free(void *module) static struct PyModuleDef_Slot _functools_slots[] = { {Py_mod_exec, _functools_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 4e8acdefc722..4dbb5741b2ed 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -793,6 +793,7 @@ _gdbm_module_free(void *module) static PyModuleDef_Slot _gdbm_module_slots[] = { {Py_mod_exec, _gdbm_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 7476e5dc7dd6..99d0b7281913 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -2260,6 +2260,7 @@ static PyModuleDef_Slot hashlib_slots[] = { {Py_mod_exec, hashlib_md_meth_names}, {Py_mod_exec, hashlib_init_constructors}, {Py_mod_exec, hashlib_exception}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c index 07ddc7b08512..00285ae01f85 100644 --- a/Modules/_heapqmodule.c +++ b/Modules/_heapqmodule.c @@ -682,6 +682,7 @@ heapq_exec(PyObject *m) static struct PyModuleDef_Slot heapq_slots[] = { {Py_mod_exec, heapq_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_json.c b/Modules/_json.c index fa8e2a936d2c..c90de05b046b 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1801,6 +1801,7 @@ _json_exec(PyObject *module) static PyModuleDef_Slot _json_slots[] = { {Py_mod_exec, _json_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 96675cdfb661..1ada7305117b 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -874,6 +874,7 @@ _locale_exec(PyObject *module) static struct PyModuleDef_Slot _locale_slots[] = { {Py_mod_exec, _locale_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index a7ce328cb530..1c84f66ee6f5 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -1001,6 +1001,9 @@ _lsprof_exec(PyObject *module) static PyModuleDef_Slot _lsprofslots[] = { {Py_mod_exec, _lsprof_exec}, + // XXX gh-103092: fix isolation. + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index bccab8639159..e34fbad230d5 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -1611,6 +1611,7 @@ static PyMethodDef lzma_methods[] = { static PyModuleDef_Slot lzma_slots[] = { {Py_mod_exec, lzma_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index 2463e1e1a8bf..8f9daa5c3de0 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -276,6 +276,7 @@ multiprocessing_exec(PyObject *module) static PyModuleDef_Slot multiprocessing_slots[] = { {Py_mod_exec, multiprocessing_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index d64ded416822..88c93fe31378 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -110,12 +110,19 @@ static PyMethodDef module_methods[ ] = { }; +static PyModuleDef_Slot module_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL} +}; + + static struct PyModuleDef _posixshmemmodule = { PyModuleDef_HEAD_INIT, .m_name = "_posixshmem", .m_doc = "POSIX shared memory module", .m_size = 0, .m_methods = module_methods, + .m_slots = module_slots, }; /* Module init function */ diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 99be97741774..b70d426fa29b 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -94,12 +94,18 @@ opcode_functions[] = { {NULL, NULL, 0, NULL} }; +static PyModuleDef_Slot module_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL} +}; + static struct PyModuleDef opcodemodule = { PyModuleDef_HEAD_INIT, .m_name = "_opcode", .m_doc = "Opcode support module.", .m_size = 0, - .m_methods = opcode_functions + .m_methods = opcode_functions, + .m_slots = module_slots, }; PyMODINIT_FUNC diff --git a/Modules/_operator.c b/Modules/_operator.c index 38335b699501..68ccc90562d3 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -1828,6 +1828,7 @@ operator_exec(PyObject *module) static struct PyModuleDef_Slot operator_slots[] = { {Py_mod_exec, operator_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 360c7910f671..bf7ecae0cc0e 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -7912,6 +7912,7 @@ _pickle_exec(PyObject *m) static PyModuleDef_Slot pickle_slots[] = { {Py_mod_exec, _pickle_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index f5bce8cd7628..2bf83db0e228 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -1140,6 +1140,7 @@ static PyMethodDef module_methods[] = { }; static PyModuleDef_Slot _posixsubprocess_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index af19dd6c198b..d36a911a57c0 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -431,6 +431,7 @@ queuemodule_exec(PyObject *module) static PyModuleDef_Slot queuemodule_slots[] = { {Py_mod_exec, queuemodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 6e2205323930..fda5ef267fb4 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -624,6 +624,7 @@ _random_exec(PyObject *module) static PyModuleDef_Slot _random_slots[] = { {Py_mod_exec, _random_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_scproxy.c b/Modules/_scproxy.c index 344b66f9aad5..e66918016b8d 100644 --- a/Modules/_scproxy.c +++ b/Modules/_scproxy.c @@ -232,6 +232,7 @@ static PyMethodDef mod_methods[] = { }; static PyModuleDef_Slot _scproxy_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c index 633a0c0ea08d..93abc3b2710e 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -641,6 +641,7 @@ _sha3_exec(PyObject *m) static PyModuleDef_Slot _sha3_slots[] = { {Py_mod_exec, _sha3_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 9c42faa232c7..27bd42f4595e 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -785,6 +785,7 @@ module_exec(PyObject *module) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 4b6290a59679..f8a1a05a3188 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -3221,6 +3221,7 @@ sre_exec(PyObject *m) static PyModuleDef_Slot sre_slots[] = { {Py_mod_exec, sre_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_ssl.c b/Modules/_ssl.c index c9e2f24d66cc..016a5a5cbca5 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -6161,6 +6161,9 @@ static PyModuleDef_Slot sslmodule_slots[] = { {Py_mod_exec, sslmodule_init_constants}, {Py_mod_exec, sslmodule_init_versioninfo}, {Py_mod_exec, sslmodule_init_strings}, + // XXX gh-103092: fix isolation. + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_stat.c b/Modules/_stat.c index 546e6a5f94ca..4218799103b5 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -612,6 +612,7 @@ stat_exec(PyObject *module) static PyModuleDef_Slot stat_slots[] = { {Py_mod_exec, stat_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_statisticsmodule.c b/Modules/_statisticsmodule.c index b9d1e4f16160..1d5465fbe6d0 100644 --- a/Modules/_statisticsmodule.c +++ b/Modules/_statisticsmodule.c @@ -129,6 +129,7 @@ PyDoc_STRVAR(statistics_doc, "Accelerators for the statistics module.\n"); static struct PyModuleDef_Slot _statisticsmodule_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_struct.c b/Modules/_struct.c index 3db7b991acd0..26434f714de5 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2572,6 +2572,7 @@ _structmodule_exec(PyObject *m) static PyModuleDef_Slot _structmodule_slots[] = { {Py_mod_exec, _structmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 1e38f1aa6349..24152412107c 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -789,6 +789,7 @@ module_exec(PyObject *module) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index bc7d8b64a943..58b064bb17cd 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -441,6 +441,7 @@ static int execfunc(PyObject *m) static PyModuleDef_Slot main_slots[] = { {Py_mod_exec, execfunc}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; @@ -745,6 +746,7 @@ PyInit__testmultiphase_create_unreported_exception(void) static PyModuleDef_Slot slots_nonmodule_with_exec_slots[] = { {Py_mod_create, createfunc_nonmodule}, {Py_mod_exec, execfunc}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; @@ -765,6 +767,7 @@ execfunc_err(PyObject *mod) static PyModuleDef_Slot slots_exec_err[] = { {Py_mod_exec, execfunc_err}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; @@ -786,6 +789,7 @@ execfunc_raise(PyObject *spec) static PyModuleDef_Slot slots_exec_raise[] = { {Py_mod_exec, execfunc_raise}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; @@ -807,6 +811,7 @@ execfunc_unreported_exception(PyObject *mod) static PyModuleDef_Slot slots_exec_unreported_exception[] = { {Py_mod_exec, execfunc_unreported_exception}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; @@ -845,6 +850,7 @@ meth_state_access_exec(PyObject *m) static PyModuleDef_Slot meth_state_access_slots[] = { {Py_mod_exec, meth_state_access_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index fd2fd9ab25f1..5d753b4a0ebc 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1710,6 +1710,7 @@ The 'threading' module provides a more convenient interface."); static PyModuleDef_Slot thread_module_slots[] = { {Py_mod_exec, thread_module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c index 262dddb63fd5..64286375636a 100644 --- a/Modules/_typingmodule.c +++ b/Modules/_typingmodule.c @@ -36,6 +36,7 @@ PyDoc_STRVAR(typing_doc, "Accelerators for the typing module.\n"); static struct PyModuleDef_Slot _typingmodule_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c index eae38f5c98cc..ed3b2fedfd4d 100644 --- a/Modules/_uuidmodule.c +++ b/Modules/_uuidmodule.c @@ -106,6 +106,7 @@ static PyMethodDef uuid_methods[] = { static PyModuleDef_Slot uuid_slots[] = { {Py_mod_exec, uuid_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_weakref.c b/Modules/_weakref.c index 157a852ae9a3..387b8fa9d0a6 100644 --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -174,6 +174,7 @@ weakref_exec(PyObject *module) static struct PyModuleDef_Slot weakref_slots[] = { {Py_mod_exec, weakref_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_winapi.c b/Modules/_winapi.c index fa380b8b7984..473bcb4736e9 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -2259,6 +2259,7 @@ static int winapi_exec(PyObject *m) static PyModuleDef_Slot winapi_slots[] = { {Py_mod_exec, winapi_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index 13b005eaef98..616dd5776881 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -2418,6 +2418,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 433fecfda655..d7daae254638 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -822,6 +822,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index c215a75b804f..3b2d282d65ca 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -2822,7 +2822,10 @@ zoneinfomodule_exec(PyObject *m) } static PyModuleDef_Slot zoneinfomodule_slots[] = { - {Py_mod_exec, zoneinfomodule_exec}, {0, NULL}}; + {Py_mod_exec, zoneinfomodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; static struct PyModuleDef zoneinfomodule = { .m_base = PyModuleDef_HEAD_INIT, diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 798a76292579..f94bbec8e0bb 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -3111,6 +3111,7 @@ array_modexec(PyObject *m) static PyModuleDef_Slot arrayslots[] = { {Py_mod_exec, array_modexec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c index 47afd7f07510..5882d4056364 100644 --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -314,12 +314,18 @@ upon normal program termination.\n\ Two public functions, register and unregister, are defined.\n\ "); +static PyModuleDef_Slot atexitmodule_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL} +}; + static struct PyModuleDef atexitmodule = { PyModuleDef_HEAD_INIT, .m_name = "atexit", .m_doc = atexit__doc__, .m_size = 0, .m_methods = atexit_methods, + .m_slots = atexitmodule_slots, }; PyMODINIT_FUNC diff --git a/Modules/audioop.c b/Modules/audioop.c index 9325f82f9a17..604306d44926 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -1975,6 +1975,7 @@ audioop_exec(PyObject* module) static PyModuleDef_Slot audioop_slots[] = { {Py_mod_exec, audioop_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/binascii.c b/Modules/binascii.c index 95ddb26988d6..4ecff4793be9 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -1291,6 +1291,7 @@ binascii_exec(PyObject *module) { static PyModuleDef_Slot binascii_slots[] = { {Py_mod_exec, binascii_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index e553ff3e17b8..36bc7024df9a 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -502,6 +502,7 @@ static struct PyMethodDef _cjk_methods[] = { static PyModuleDef_Slot _cjk_slots[] = { {Py_mod_exec, _cjk_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 233fc3020fd6..b501e4fb9232 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -2062,6 +2062,7 @@ static struct PyMethodDef _multibytecodec_methods[] = { static PyModuleDef_Slot _multibytecodec_slots[] = { {Py_mod_exec, _multibytecodec_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index b4f7e5424b4c..914a697f8e17 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1411,6 +1411,7 @@ cmath_exec(PyObject *mod) static PyModuleDef_Slot cmath_slots[] = { {Py_mod_exec, cmath_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/errnomodule.c b/Modules/errnomodule.c index df4e494ba8a9..fddde960a5fe 100644 --- a/Modules/errnomodule.c +++ b/Modules/errnomodule.c @@ -940,6 +940,7 @@ errno_exec(PyObject *module) static PyModuleDef_Slot errno_slots[] = { {Py_mod_exec, errno_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 9b4e4199cdc2..428b090193f0 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1274,6 +1274,8 @@ PyExec_faulthandler(PyObject *module) { static PyModuleDef_Slot faulthandler_slots[] = { {Py_mod_exec, PyExec_faulthandler}, + // XXX gh-103092: fix isolation. + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index 9a8ec8dc9858..6ca0b62bc5dc 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -686,6 +686,7 @@ fcntl_exec(PyObject *module) static PyModuleDef_Slot fcntl_slots[] = { {Py_mod_exec, fcntl_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index f4d5186ff155..26ddcdd538a4 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2044,6 +2044,7 @@ gcmodule_exec(PyObject *module) static PyModuleDef_Slot gcmodule_slots[] = { {Py_mod_exec, gcmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c index f6298ca0ee84..57cdde6064c2 100644 --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -327,6 +327,7 @@ grpmodule_exec(PyObject *module) static PyModuleDef_Slot grpmodule_slots[] = { {Py_mod_exec, grpmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index c986e02867ca..555eab09935e 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -4693,6 +4693,7 @@ itertoolsmodule_exec(PyObject *mod) static struct PyModuleDef_Slot itertoolsmodule_slots[] = { {Py_mod_exec, itertoolsmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 4a2381d96117..3737a9654575 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -4064,6 +4064,7 @@ static PyMethodDef math_methods[] = { static PyModuleDef_Slot math_slots[] = { {Py_mod_exec, math_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/md5module.c b/Modules/md5module.c index 4f7bc77a8836..86605771d964 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -340,6 +340,7 @@ md5_exec(PyObject *m) static PyModuleDef_Slot _md5_slots[] = { {Py_mod_exec, md5_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index fe76ca6eafaa..a470dd3c2f3b 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1713,6 +1713,7 @@ mmap_exec(PyObject *module) static PyModuleDef_Slot mmap_slots[] = { {Py_mod_exec, mmap_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/nismodule.c b/Modules/nismodule.c index ec7f6d8031e8..6d094490cea7 100644 --- a/Modules/nismodule.c +++ b/Modules/nismodule.c @@ -502,6 +502,9 @@ nis_exec(PyObject *module) static PyModuleDef_Slot nis_slots[] = { {Py_mod_exec, nis_exec}, + // XXX gh-103092: fix isolation. + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/overlapped.c b/Modules/overlapped.c index 02c0f401be4c..ac637316583d 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -2050,6 +2050,7 @@ overlapped_exec(PyObject *module) static PyModuleDef_Slot overlapped_slots[] = { {Py_mod_exec, overlapped_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b395c265c72d..5022fdeb0370 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -16793,6 +16793,7 @@ posixmodule_exec(PyObject *m) static PyModuleDef_Slot posixmodile_slots[] = { {Py_mod_exec, posixmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index a757380bd09f..cc2e2a438939 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -336,6 +336,7 @@ pwdmodule_exec(PyObject *module) static PyModuleDef_Slot pwdmodule_slots[] = { {Py_mod_exec, pwdmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 0a744998b6c5..c0fbd4d39f00 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -2056,6 +2056,9 @@ pyexpat_free(void *module) static PyModuleDef_Slot pyexpat_slots[] = { {Py_mod_exec, pyexpat_exec}, + // XXX gh-103092: fix isolation. + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/resource.c b/Modules/resource.c index a97fb870062b..2a8158c9be53 100644 --- a/Modules/resource.c +++ b/Modules/resource.c @@ -514,6 +514,7 @@ resource_exec(PyObject *module) static struct PyModuleDef_Slot resource_slots[] = { {Py_mod_exec, resource_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 5a1e40d0b4a4..79bd5b59ab68 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -2651,6 +2651,7 @@ _select_exec(PyObject *m) static PyModuleDef_Slot _select_slots[] = { {Py_mod_exec, _select_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/sha1module.c b/Modules/sha1module.c index f8d4056fd34b..bdb76c56f1a6 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -344,6 +344,7 @@ _sha1_exec(PyObject *module) static PyModuleDef_Slot _sha1_slots[] = { {Py_mod_exec, _sha1_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 72de20b44762..37d9b5c538fd 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -785,6 +785,7 @@ static int sha2_exec(PyObject *module) static PyModuleDef_Slot _sha2_slots[] = { {Py_mod_exec, sha2_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index fdd1450050fa..2350236ad46b 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1695,6 +1695,7 @@ _signal_module_free(void *module) static PyModuleDef_Slot signal_slots[] = { {Py_mod_exec, signal_module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index e5478382e11f..60219593be61 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -8870,6 +8870,7 @@ socket_exec(PyObject *m) static struct PyModuleDef_Slot socket_slots[] = { {Py_mod_exec, socket_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/spwdmodule.c b/Modules/spwdmodule.c index 42123c93b593..13f1115feefa 100644 --- a/Modules/spwdmodule.c +++ b/Modules/spwdmodule.c @@ -224,6 +224,7 @@ spwdmodule_exec(PyObject *module) static PyModuleDef_Slot spwdmodule_slots[] = { {Py_mod_exec, spwdmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c index 91538b4fb15c..1cc319cc3410 100644 --- a/Modules/symtablemodule.c +++ b/Modules/symtablemodule.c @@ -100,6 +100,7 @@ symtable_init_constants(PyObject *m) static PyModuleDef_Slot symtable_slots[] = { {Py_mod_exec, symtable_init_constants}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index f45aa5227f1c..6db8de9c491d 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -406,6 +406,7 @@ syslog_exec(PyObject *module) static PyModuleDef_Slot syslog_slots[] = { {Py_mod_exec, syslog_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/termios.c b/Modules/termios.c index fcc8f0426798..169a36fc6477 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -1253,6 +1253,7 @@ termios_exec(PyObject *mod) static PyModuleDef_Slot termios_slots[] = { {Py_mod_exec, termios_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/timemodule.c b/Modules/timemodule.c index c50e689bb698..3607855dbd8f 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -2107,6 +2107,7 @@ time_module_free(void *module) static struct PyModuleDef_Slot time_slots[] = { {Py_mod_exec, time_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index c108f14871f9..41dcd5f8f883 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1516,6 +1516,7 @@ unicodedata_exec(PyObject *module) static PyModuleDef_Slot unicodedata_slots[] = { {Py_mod_exec, unicodedata_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c index 5f5297ba6337..3935c00fc265 100644 --- a/Modules/xxlimited.c +++ b/Modules/xxlimited.c @@ -390,6 +390,7 @@ xx_modexec(PyObject *m) static PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_modexec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/xxlimited_35.c b/Modules/xxlimited_35.c index 361c7e76d77f..1ff3ef1cb6f2 100644 --- a/Modules/xxlimited_35.c +++ b/Modules/xxlimited_35.c @@ -293,6 +293,7 @@ xx_modexec(PyObject *m) static PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_modexec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Modules/xxmodule.c b/Modules/xxmodule.c index a676fdb4ec77..1e4e0ea3743c 100644 --- a/Modules/xxmodule.c +++ b/Modules/xxmodule.c @@ -383,6 +383,7 @@ xx_exec(PyObject *m) static struct PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c index 8512baf7cd0a..744ba7bf5d28 100644 --- a/Modules/xxsubtype.c +++ b/Modules/xxsubtype.c @@ -286,6 +286,7 @@ xxsubtype_exec(PyObject* m) static struct PyModuleDef_Slot xxsubtype_slots[] = { {Py_mod_exec, xxsubtype_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index e2f7dbaca87a..b67844a67c31 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -2109,6 +2109,7 @@ zlib_exec(PyObject *mod) static PyModuleDef_Slot zlib_slots[] = { {Py_mod_exec, zlib_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 63f4226dd9e9..c100d018d3f0 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -250,6 +250,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio int has_execution_slots = 0; const char *name; int ret; + PyInterpreterState *interp = _PyInterpreterState_GET(); PyModuleDef_Init(def); @@ -316,13 +317,13 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio multiple_interpreters = Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED; } if (multiple_interpreters == Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED) { - PyInterpreterState *interp = _PyInterpreterState_GET(); if (!_Py_IsMainInterpreter(interp) && _PyImport_CheckSubinterpIncompatibleExtensionAllowed(name) < 0) { goto error; } } + // XXX Do a similar check once we have PyInterpreterState.ceval.own_gil. if (create) { m = create(spec, def); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 6ae68cc20f7d..1585a582f00a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15192,12 +15192,18 @@ static PyMethodDef _string_methods[] = { {NULL, NULL} }; +static PyModuleDef_Slot module_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL} +}; + static struct PyModuleDef _string_module = { PyModuleDef_HEAD_INIT, .m_name = "_string", .m_doc = PyDoc_STR("string helper module"), .m_size = 0, .m_methods = _string_methods, + .m_slots = module_slots, }; PyMODINIT_FUNC diff --git a/PC/_testconsole.c b/PC/_testconsole.c index f14a2d45b1be..3221b985d01b 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -31,6 +31,7 @@ static int execfunc(PyObject *m) PyModuleDef_Slot testconsole_slots[] = { {Py_mod_exec, execfunc}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 090254befc93..53ef26b732f6 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -661,6 +661,7 @@ exec_module(PyObject* m) static PyModuleDef_Slot msvcrt_slots[] = { {Py_mod_exec, exec_module}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/PC/winreg.c b/PC/winreg.c index 4884125c3609..e2d5322f458c 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -2184,6 +2184,7 @@ exec_module(PyObject *m) static PyModuleDef_Slot winreg_slots[] = { {Py_mod_exec, exec_module}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/PC/winsound.c b/PC/winsound.c index 17ce2ef423b1..68a917810f88 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -235,6 +235,7 @@ exec_module(PyObject *module) static PyModuleDef_Slot sound_slots[] = { {Py_mod_exec, exec_module}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index b44e303ac259..5d5a05a70ca7 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1206,6 +1206,7 @@ def visitModule(self, mod): self.emit(""" static PyModuleDef_Slot astmodule_slots[] = { {Py_mod_exec, astmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 6c878474afb1..81ab71c0fc3b 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -12193,6 +12193,7 @@ astmodule_exec(PyObject *m) static PyModuleDef_Slot astmodule_slots[] = { {Py_mod_exec, astmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 416dc5971bca..3394a5108cb5 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -151,6 +151,7 @@ static PyMethodDef tokenize_methods[] = { static PyModuleDef_Slot tokenizemodule_slots[] = { {Py_mod_exec, tokenizemodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Python/_warnings.c b/Python/_warnings.c index d510381c365b..5644db9a3770 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1449,6 +1449,7 @@ warnings_module_exec(PyObject *module) static PyModuleDef_Slot warnings_slots[] = { {Py_mod_exec, warnings_module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Python/import.c b/Python/import.c index 0bf107b28d39..9e1857d5f3e4 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3840,6 +3840,7 @@ imp_module_exec(PyObject *module) static PyModuleDef_Slot imp_slots[] = { {Py_mod_exec, imp_module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Python/marshal.c b/Python/marshal.c index 2966139cec9a..208996b05fc4 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1870,6 +1870,7 @@ marshal_module_exec(PyObject *mod) static PyModuleDef_Slot marshalmodule_slots[] = { {Py_mod_exec, marshal_module_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; From webhook-mailer at python.org Fri May 5 17:35:31 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 05 May 2023 21:35:31 -0000 Subject: [Python-checkins] gh-104146: Remove unused var 'parser_body_declarations' from clinic.py (#104214) Message-ID: <mailman.191.1683322533.13550.python-checkins@python.org> https://github.com/python/cpython/commit/66558d2a16ee42afc0e2c02e6a90bfd62dcb67f6 commit: 66558d2a16ee42afc0e2c02e6a90bfd62dcb67f6 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-05T21:35:24Z summary: gh-104146: Remove unused var 'parser_body_declarations' from clinic.py (#104214) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 5f6e67e7d65a..704325670bc9 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -814,13 +814,11 @@ def output_templates(self, f): # parser_body_fields remembers the fields passed in to the # previous call to parser_body. this is used for an awful hack. parser_body_fields = () - parser_body_declarations = '' def parser_body(prototype, *fields, declarations=''): - nonlocal parser_body_fields, parser_body_declarations + nonlocal parser_body_fields add, output = text_accumulator() add(prototype) parser_body_fields = fields - parser_body_declarations = declarations fields = list(fields) fields.insert(0, normalize_snippet(""" From webhook-mailer at python.org Fri May 5 17:59:35 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Fri, 05 May 2023 21:59:35 -0000 Subject: [Python-checkins] gh-99113: Add PyInterpreterConfig.own_gil (gh-104204) Message-ID: <mailman.192.1683323976.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f3e7eb48f86057919c347f56dabf417acfd55845 commit: f3e7eb48f86057919c347f56dabf417acfd55845 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-05T15:59:20-06:00 summary: gh-99113: Add PyInterpreterConfig.own_gil (gh-104204) We also add PyInterpreterState.ceval.own_gil to record if the interpreter actually has its own GIL. Note that for now we don't actually respect own_gil; all interpreters still share the one GIL. However, PyInterpreterState.ceval.own_gil does reflect PyInterpreterConfig.own_gil. That lie is a temporary one that we will fix when the GIL really becomes per-interpreter. files: M Include/cpython/initconfig.h M Include/internal/pycore_ceval.h M Include/internal/pycore_ceval_state.h M Lib/test/test_capi/test_misc.py M Lib/test/test_embed.py M Lib/test/test_import/__init__.py M Lib/test/test_threading.py M Modules/_testcapimodule.c M Modules/_testinternalcapi.c M Python/ceval_gil.c M Python/pylifecycle.c diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index 9c1783d272f1..efae2409b500 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -252,6 +252,7 @@ typedef struct { int allow_threads; int allow_daemon_threads; int check_multi_interp_extensions; + int own_gil; } PyInterpreterConfig; #define _PyInterpreterConfig_INIT \ @@ -262,6 +263,7 @@ typedef struct { .allow_threads = 1, \ .allow_daemon_threads = 0, \ .check_multi_interp_extensions = 1, \ + .own_gil = 1, \ } #define _PyInterpreterConfig_LEGACY_INIT \ @@ -272,6 +274,7 @@ typedef struct { .allow_threads = 1, \ .allow_daemon_threads = 1, \ .check_multi_interp_extensions = 0, \ + .own_gil = 0, \ } /* --- Helper functions --------------------------------------- */ diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 0bbc9efdda3b..b7a9bf40425b 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -97,7 +97,7 @@ _PyEval_Vector(PyThreadState *tstate, PyObject *kwnames); extern int _PyEval_ThreadsInitialized(void); -extern PyStatus _PyEval_InitGIL(PyThreadState *tstate); +extern PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil); extern void _PyEval_FiniGIL(PyInterpreterState *interp); extern void _PyEval_ReleaseLock(PyThreadState *tstate); diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index 1a00ec80270e..4781dd5735dc 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -86,6 +86,7 @@ struct _pending_calls { struct _ceval_state { int recursion_limit; struct _gil_runtime_state *gil; + int own_gil; /* This single variable consolidates all requests to break out of the fast path in the eval loop. */ _Py_atomic_int eval_breaker; diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 22be3c081427..3fc2c07f9330 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1401,23 +1401,37 @@ def test_configured_settings(self): DAEMON_THREADS = 1<<11 FORK = 1<<15 EXEC = 1<<16 - - features = ['obmalloc', 'fork', 'exec', 'threads', 'daemon_threads', - 'extensions'] + ALL_FLAGS = (OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS + | EXTENSIONS); + + features = [ + 'obmalloc', + 'fork', + 'exec', + 'threads', + 'daemon_threads', + 'extensions', + 'own_gil', + ] kwlist = [f'allow_{n}' for n in features] kwlist[0] = 'use_main_obmalloc' - kwlist[-1] = 'check_multi_interp_extensions' + kwlist[-2] = 'check_multi_interp_extensions' + kwlist[-1] = 'own_gil' # expected to work for config, expected in { - (True, True, True, True, True, True): - OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS, - (True, False, False, False, False, False): OBMALLOC, - (False, False, False, True, False, True): THREADS | EXTENSIONS, + (True, True, True, True, True, True, True): + (ALL_FLAGS, True), + (True, False, False, False, False, False, False): + (OBMALLOC, False), + (False, False, False, True, False, True, False): + (THREADS | EXTENSIONS, False), }.items(): kwargs = dict(zip(kwlist, config)) + exp_flags, exp_gil = expected expected = { - 'feature_flags': expected, + 'feature_flags': exp_flags, + 'own_gil': exp_gil, } with self.subTest(config): r, w = os.pipe() @@ -1437,7 +1451,7 @@ def test_configured_settings(self): # expected to fail for config in [ - (False, False, False, False, False, False), + (False, False, False, False, False, False, False), ]: kwargs = dict(zip(kwlist, config)) with self.subTest(config): @@ -1473,6 +1487,7 @@ def test_overridden_setting_extensions_subinterp_check(self): 'allow_exec': True, 'allow_threads': True, 'allow_daemon_threads': True, + 'own_gil': False, } def check(enabled, override): @@ -1483,6 +1498,7 @@ def check(enabled, override): flags = BASE_FLAGS | EXTENSIONS if enabled else BASE_FLAGS settings = { 'feature_flags': flags, + 'own_gil': False, } expected = { diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index c9691bbf3049..582392ecddcb 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1666,6 +1666,7 @@ def test_init_main_interpreter_settings(self): # All optional features should be enabled. 'feature_flags': OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS, + 'own_gil': True, } out, err = self.run_embedded_interpreter( 'test_init_main_interpreter_settings', diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 9211639b016e..773b7094c6b8 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1640,6 +1640,7 @@ class SubinterpImportTests(unittest.TestCase): ) ISOLATED = dict( use_main_obmalloc=False, + own_gil=True, ) NOT_ISOLATED = {k: not v for k, v in ISOLATED.items()} diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index fdd74c37e262..97165264b34b 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1349,6 +1349,7 @@ def func(): allow_threads={allowed}, allow_daemon_threads={daemon_allowed}, check_multi_interp_extensions=False, + own_gil=False, ) """) with test.support.SuppressCrashReport(): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 376f04f23e32..79ab7d3f5555 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1488,6 +1488,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) int allow_threads = -1; int allow_daemon_threads = -1; int check_multi_interp_extensions = -1; + int own_gil = -1; int r; PyThreadState *substate, *mainstate; /* only initialise 'cflags.cf_flags' to test backwards compatibility */ @@ -1500,13 +1501,15 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) "allow_threads", "allow_daemon_threads", "check_multi_interp_extensions", + "own_gil", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "s$pppppp:run_in_subinterp_with_config", kwlist, + "s$ppppppp:run_in_subinterp_with_config", kwlist, &code, &use_main_obmalloc, &allow_fork, &allow_exec, &allow_threads, &allow_daemon_threads, - &check_multi_interp_extensions)) { + &check_multi_interp_extensions, + &own_gil)) { return NULL; } if (use_main_obmalloc < 0) { @@ -1525,6 +1528,10 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) PyErr_SetString(PyExc_ValueError, "missing allow_threads"); return NULL; } + if (own_gil < 0) { + PyErr_SetString(PyExc_ValueError, "missing own_gil"); + return NULL; + } if (allow_daemon_threads < 0) { PyErr_SetString(PyExc_ValueError, "missing allow_daemon_threads"); return NULL; @@ -1545,6 +1552,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_threads = allow_threads, .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, + .own_gil = own_gil, }; PyStatus status = Py_NewInterpreterFromConfig(&substate, &config); if (PyStatus_Exception(status)) { diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 24152412107c..f35e3b48df93 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -729,6 +729,13 @@ get_interp_settings(PyObject *self, PyObject *args) return NULL; } + /* "own GIL" */ + PyObject *own_gil = interp->ceval.own_gil ? Py_True : Py_False; + if (PyDict_SetItemString(settings, "own_gil", own_gil) != 0) { + Py_DECREF(settings); + return NULL; + } + return settings; } diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index ad33a58dedd8..a390bec80d55 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -500,9 +500,18 @@ PyEval_ThreadsInitialized(void) } PyStatus -_PyEval_InitGIL(PyThreadState *tstate) +_PyEval_InitGIL(PyThreadState *tstate, int own_gil) { assert(tstate->interp->ceval.gil == NULL); + if (!own_gil) { + PyInterpreterState *main_interp = _PyInterpreterState_Main(); + assert(tstate->interp != main_interp); + struct _gil_runtime_state *gil = main_interp->ceval.gil; + assert(gil_created(gil)); + tstate->interp->ceval.gil = gil; + tstate->interp->ceval.own_gil = 0; + return _PyStatus_OK(); + } /* XXX per-interpreter GIL */ struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; @@ -512,8 +521,11 @@ _PyEval_InitGIL(PyThreadState *tstate) and destroy it. */ assert(gil_created(gil)); tstate->interp->ceval.gil = gil; + // XXX For now we lie. + tstate->interp->ceval.own_gil = 1; return _PyStatus_OK(); } + assert(own_gil); assert(!gil_created(gil)); @@ -521,6 +533,7 @@ _PyEval_InitGIL(PyThreadState *tstate) create_gil(gil); assert(gil_created(gil)); tstate->interp->ceval.gil = gil; + tstate->interp->ceval.own_gil = 1; take_gil(tstate); return _PyStatus_OK(); } @@ -530,6 +543,14 @@ _PyEval_FiniGIL(PyInterpreterState *interp) { if (interp->ceval.gil == NULL) { /* It was already finalized (or hasn't been initialized yet). */ + assert(!interp->ceval.own_gil); + return; + } + else if (!interp->ceval.own_gil) { + PyInterpreterState *main_interp = _PyInterpreterState_Main(); + assert(interp != main_interp); + assert(interp->ceval.gil == main_interp->ceval.gil); + interp->ceval.gil = NULL; return; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 97957d3f17e6..705708698c6a 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -585,7 +585,7 @@ init_interp_settings(PyInterpreterState *interp, static PyStatus -init_interp_create_gil(PyThreadState *tstate) +init_interp_create_gil(PyThreadState *tstate, int own_gil) { PyStatus status; @@ -600,7 +600,7 @@ init_interp_create_gil(PyThreadState *tstate) } /* Create the GIL and take it */ - status = _PyEval_InitGIL(tstate); + status = _PyEval_InitGIL(tstate, own_gil); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -632,7 +632,9 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } - const PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; + PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; + // The main interpreter always has its own GIL. + config.own_gil = 1; status = init_interp_settings(interp, &config); if (_PyStatus_EXCEPTION(status)) { return status; @@ -645,7 +647,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, _PyThreadState_Bind(tstate); (void) PyThreadState_Swap(tstate); - status = init_interp_create_gil(tstate); + status = init_interp_create_gil(tstate, config.own_gil); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -2047,7 +2049,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) goto error; } - status = init_interp_create_gil(tstate); + status = init_interp_create_gil(tstate, config->own_gil); if (_PyStatus_EXCEPTION(status)) { goto error; } From webhook-mailer at python.org Fri May 5 19:44:14 2023 From: webhook-mailer at python.org (gvanrossum) Date: Fri, 05 May 2023 23:44:14 -0000 Subject: [Python-checkins] gh-104144: Skip scheduling a done callback if a TaskGroup task completes eagerly (#104140) Message-ID: <mailman.193.1683330255.13550.python-checkins@python.org> https://github.com/python/cpython/commit/52d8f36e8c9f6048367d7bdfede3698e3f5f70d0 commit: 52d8f36e8c9f6048367d7bdfede3698e3f5f70d0 branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-05T16:44:03-07:00 summary: gh-104144: Skip scheduling a done callback if a TaskGroup task completes eagerly (#104140) Co-authored-by: Carl Meyer <carl at oddbird.net> files: A Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst M Lib/asyncio/taskgroups.py diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 0fdea3697ece..06b2e0db86a1 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -164,8 +164,14 @@ def create_task(self, coro, *, name=None, context=None): else: task = self._loop.create_task(coro, context=context) tasks._set_task_name(task, name) - task.add_done_callback(self._on_task_done) - self._tasks.add(task) + # optimization: Immediately call the done callback if the task is + # already done (e.g. if the coro was able to complete eagerly), + # and skip scheduling a done callback + if task.done(): + self._on_task_done(task) + else: + self._tasks.add(task) + task.add_done_callback(self._on_task_done) return task # Since Python 3.8 Tasks propagate all exceptions correctly, diff --git a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst new file mode 100644 index 000000000000..59870de3e02e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst @@ -0,0 +1 @@ +Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`. Skip scheduling done callbacks when all tasks finish without blocking. From webhook-mailer at python.org Fri May 5 19:50:13 2023 From: webhook-mailer at python.org (gvanrossum) Date: Fri, 05 May 2023 23:50:13 -0000 Subject: [Python-checkins] gh-97696: Remove redundant #include (#104216) Message-ID: <mailman.194.1683330615.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8b7f37dd4c297138e9f4a256ff6750cf1402b421 commit: 8b7f37dd4c297138e9f4a256ff6750cf1402b421 branch: main author: Jacob Bower <1978924+jbower-fb at users.noreply.github.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-05T16:50:06-07:00 summary: gh-97696: Remove redundant #include (#104216) Remove "#include cpython/context.h"` from `_asynciomodule.c`. It's already included in `Python.h`. files: M Modules/_asynciomodule.c diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 822d5f2a41de..39c33fed74e2 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -8,7 +8,6 @@ #include "pycore_runtime_init.h" // _Py_ID() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef -#include "cpython/context.h" #include <stddef.h> // offsetof() From webhook-mailer at python.org Fri May 5 19:54:02 2023 From: webhook-mailer at python.org (vstinner) Date: Fri, 05 May 2023 23:54:02 -0000 Subject: [Python-checkins] gh-101819: Prepare to modernize the _io extension (#104178) Message-ID: <mailman.195.1683330843.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c84029179c3287f9c357ccac231fe78469c6f068 commit: c84029179c3287f9c357ccac231fe78469c6f068 branch: main author: Victor Stinner <vstinner at python.org> committer: vstinner <vstinner at python.org> date: 2023-05-06T01:53:55+02:00 summary: gh-101819: Prepare to modernize the _io extension (#104178) * Add references to static types to _PyIO_State: * PyBufferedIOBase_Type * PyBytesIOBuffer_Type * PyIncrementalNewlineDecoder_Type * PyRawIOBase_Type * PyTextIOBase_Type * Add the defining class to methods: * _io.BytesIO.getbuffer() * _io.FileIO.close() * Add get_io_state_by_cls() function. * Add state parameter to _textiowrapper_decode() * _io_TextIOWrapper___init__() now sets self->state before calling _textiowrapper_set_decoder(). Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/bufferedio.c M Modules/_io/bytesio.c M Modules/_io/clinic/bytesio.c.h M Modules/_io/clinic/fileio.c.h M Modules/_io/fileio.c M Modules/_io/stringio.c M Modules/_io/textio.c diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 8ec3a6081c98..403968af1b99 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -583,13 +583,18 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { Py_VISIT(state->locale_module); Py_VISIT(state->unsupported_operation); + Py_VISIT(state->PyIncrementalNewlineDecoder_Type); + Py_VISIT(state->PyRawIOBase_Type); + Py_VISIT(state->PyBufferedIOBase_Type); Py_VISIT(state->PyBufferedRWPair_Type); Py_VISIT(state->PyBufferedRandom_Type); Py_VISIT(state->PyBufferedReader_Type); Py_VISIT(state->PyBufferedWriter_Type); + Py_VISIT(state->PyBytesIOBuffer_Type); Py_VISIT(state->PyBytesIO_Type); Py_VISIT(state->PyFileIO_Type); Py_VISIT(state->PyStringIO_Type); + Py_VISIT(state->PyTextIOBase_Type); Py_VISIT(state->PyTextIOWrapper_Type); return 0; } @@ -604,13 +609,18 @@ iomodule_clear(PyObject *mod) { Py_CLEAR(state->locale_module); Py_CLEAR(state->unsupported_operation); + Py_CLEAR(state->PyIncrementalNewlineDecoder_Type); + Py_CLEAR(state->PyRawIOBase_Type); + Py_CLEAR(state->PyBufferedIOBase_Type); Py_CLEAR(state->PyBufferedRWPair_Type); Py_CLEAR(state->PyBufferedRandom_Type); Py_CLEAR(state->PyBufferedReader_Type); Py_CLEAR(state->PyBufferedWriter_Type); + Py_CLEAR(state->PyBytesIOBuffer_Type); Py_CLEAR(state->PyBytesIO_Type); Py_CLEAR(state->PyFileIO_Type); Py_CLEAR(state->PyStringIO_Type); + Py_CLEAR(state->PyTextIOBase_Type); Py_CLEAR(state->PyTextIOWrapper_Type); return 0; } @@ -749,24 +759,33 @@ PyInit__io(void) } } + // Base classes + state->PyIncrementalNewlineDecoder_Type = (PyTypeObject *)Py_NewRef(&PyIncrementalNewlineDecoder_Type); + + // PyIOBase_Type subclasses + state->PyRawIOBase_Type = (PyTypeObject *)Py_NewRef(&PyRawIOBase_Type); + state->PyBufferedIOBase_Type = (PyTypeObject *)Py_NewRef(&PyBufferedIOBase_Type); + state->PyTextIOBase_Type = (PyTypeObject *)Py_NewRef(&PyTextIOBase_Type); + // PyBufferedIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, &PyBufferedIOBase_Type); + ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec, - &PyBufferedIOBase_Type); + state->PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec, - &PyBufferedIOBase_Type); + state->PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec, - &PyBufferedIOBase_Type); + state->PyBufferedIOBase_Type); ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec, - &PyBufferedIOBase_Type); + state->PyBufferedIOBase_Type); // PyRawIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, &PyRawIOBase_Type); + state->PyBytesIOBuffer_Type = (PyTypeObject *)Py_NewRef(&_PyBytesIOBuffer_Type); + ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); // PyTextIOBase_Type(PyIOBase_Type) subclasses - ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, &PyTextIOBase_Type); + ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, state->PyTextIOBase_Type); ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, - &PyTextIOBase_Type); + state->PyTextIOBase_Type); state->initialized = 1; diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index d7224e56f9a7..8a788fbb8185 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -5,6 +5,7 @@ #include "exports.h" #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "structmember.h" /* ABCs */ @@ -147,13 +148,18 @@ typedef struct { PyObject *unsupported_operation; /* Types */ + PyTypeObject *PyIncrementalNewlineDecoder_Type; + PyTypeObject *PyRawIOBase_Type; + PyTypeObject *PyBufferedIOBase_Type; PyTypeObject *PyBufferedRWPair_Type; PyTypeObject *PyBufferedRandom_Type; PyTypeObject *PyBufferedReader_Type; PyTypeObject *PyBufferedWriter_Type; + PyTypeObject *PyBytesIOBuffer_Type; PyTypeObject *PyBytesIO_Type; PyTypeObject *PyFileIO_Type; PyTypeObject *PyStringIO_Type; + PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; } _PyIO_State; @@ -168,6 +174,14 @@ get_io_state(PyObject *module) return (_PyIO_State *)state; } +static inline _PyIO_State * +get_io_state_by_cls(PyTypeObject *cls) +{ + void *state = _PyType_GetModuleState(cls); + assert(state != NULL); + return (_PyIO_State *)state; +} + static inline _PyIO_State * find_io_state_by_def(PyTypeObject *type) { diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 2c71768be978..723d16b47fef 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2231,7 +2231,7 @@ bufferedrwpair_close(rwpair *self, PyObject *Py_UNUSED(ignored)) } else { Py_DECREF(ret); - } + } ret = _forward_call(self->reader, &_Py_ID(close), NULL); if (exc != NULL) { _PyErr_ChainExceptions1(exc); diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 7e9d28b3b965..9c7a28357987 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -308,14 +308,18 @@ _io_BytesIO_flush_impl(bytesio *self) /*[clinic input] _io.BytesIO.getbuffer + cls: defining_class + / + Get a read-write view over the contents of the BytesIO object. [clinic start generated code]*/ static PyObject * -_io_BytesIO_getbuffer_impl(bytesio *self) -/*[clinic end generated code: output=72cd7c6e13aa09ed input=8f738ef615865176]*/ +_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls) +/*[clinic end generated code: output=045091d7ce87fe4e input=0668fbb48f95dffa]*/ { - PyTypeObject *type = &_PyBytesIOBuffer_Type; + _PyIO_State *state = get_io_state_by_cls(cls); + PyTypeObject *type = state->PyBytesIOBuffer_Type; bytesiobuf *buf; PyObject *view; diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 84b58db6c7a7..9550c8728c25 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -87,15 +87,19 @@ PyDoc_STRVAR(_io_BytesIO_getbuffer__doc__, "Get a read-write view over the contents of the BytesIO object."); #define _IO_BYTESIO_GETBUFFER_METHODDEF \ - {"getbuffer", (PyCFunction)_io_BytesIO_getbuffer, METH_NOARGS, _io_BytesIO_getbuffer__doc__}, + {"getbuffer", _PyCFunction_CAST(_io_BytesIO_getbuffer), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_BytesIO_getbuffer__doc__}, static PyObject * -_io_BytesIO_getbuffer_impl(bytesio *self); +_io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls); static PyObject * -_io_BytesIO_getbuffer(bytesio *self, PyObject *Py_UNUSED(ignored)) +_io_BytesIO_getbuffer(bytesio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io_BytesIO_getbuffer_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments"); + return NULL; + } + return _io_BytesIO_getbuffer_impl(self, cls); } PyDoc_STRVAR(_io_BytesIO_getvalue__doc__, @@ -534,4 +538,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=a44770efbaeb80dd input=a9049054013a1b77]*/ +/*[clinic end generated code: output=098584d485420b65 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index b6e9bd5b65a0..dfad8a58c472 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -18,15 +18,19 @@ PyDoc_STRVAR(_io_FileIO_close__doc__, "called more than once without error."); #define _IO_FILEIO_CLOSE_METHODDEF \ - {"close", (PyCFunction)_io_FileIO_close, METH_NOARGS, _io_FileIO_close__doc__}, + {"close", _PyCFunction_CAST(_io_FileIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_close__doc__}, static PyObject * -_io_FileIO_close_impl(fileio *self); +_io_FileIO_close_impl(fileio *self, PyTypeObject *cls); static PyObject * -_io_FileIO_close(fileio *self, PyObject *Py_UNUSED(ignored)) +_io_FileIO_close(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io_FileIO_close_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } + return _io_FileIO_close_impl(self, cls); } PyDoc_STRVAR(_io_FileIO___init____doc__, @@ -466,4 +470,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=27f883807a6c29ae input=a9049054013a1b77]*/ +/*[clinic end generated code: output=29ed2ae6c451c139 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 1118d86e6c9a..cc0e7307b9da 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -130,6 +130,9 @@ internal_close(fileio *self) /*[clinic input] _io.FileIO.close + cls: defining_class + / + Close the file. A closed file cannot be used for further I/O operations. close() may be @@ -137,18 +140,20 @@ called more than once without error. [clinic start generated code]*/ static PyObject * -_io_FileIO_close_impl(fileio *self) -/*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/ +_io_FileIO_close_impl(fileio *self, PyTypeObject *cls) +/*[clinic end generated code: output=c30cbe9d1f23ca58 input=70da49e63db7c64d]*/ { PyObject *res; - PyObject *exc; int rc; - res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type, + _PyIO_State *state = get_io_state_by_cls(cls); + res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject *)self); if (!self->closefd) { self->fd = -1; return res; } + + PyObject *exc; if (res == NULL) { exc = PyErr_GetRaisedException(); } diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 54c050f0be46..13d3b870b39a 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -716,9 +716,10 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, self->writenl = Py_NewRef(self->readnl); } + _PyIO_State *module_state = find_io_state_by_def(Py_TYPE(self)); if (self->readuniversal) { self->decoder = PyObject_CallFunctionObjArgs( - (PyObject *)&PyIncrementalNewlineDecoder_Type, + (PyObject *)module_state->PyIncrementalNewlineDecoder_Type, Py_None, self->readtranslate ? Py_True : Py_False, NULL); if (self->decoder == NULL) return -1; @@ -750,7 +751,7 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, self->state = STATE_ACCUMULATING; } self->pos = 0; - self->module_state = find_io_state_by_def(Py_TYPE(self)); + self->module_state = module_state; self->closed = 0; self->ok = 1; return 0; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 3ff84cb623af..2dba382f4f8f 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -18,10 +18,10 @@ /*[clinic input] module _io -class _io.IncrementalNewlineDecoder "nldecoder_object *" "&PyIncrementalNewlineDecoder_Type" +class _io.IncrementalNewlineDecoder "nldecoder_object *" "clinic_state()->PyIncrementalNewlineDecoder_Type" class _io.TextIOWrapper "textio *" "clinic_state()->TextIOWrapper_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d3f032e90f74c8f2]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81f67cf54eaa6001]*/ /* TextIOBase */ @@ -872,8 +872,9 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, return -1; if (self->readuniversal) { + _PyIO_State *state = self->state; PyObject *incrementalDecoder = PyObject_CallFunctionObjArgs( - (PyObject *)&PyIncrementalNewlineDecoder_Type, + (PyObject *)state->PyIncrementalNewlineDecoder_Type, self->decoder, self->readtranslate ? Py_True : Py_False, NULL); if (incrementalDecoder == NULL) return -1; @@ -884,11 +885,12 @@ _textiowrapper_set_decoder(textio *self, PyObject *codec_info, } static PyObject* -_textiowrapper_decode(PyObject *decoder, PyObject *bytes, int eof) +_textiowrapper_decode(_PyIO_State *state, PyObject *decoder, PyObject *bytes, + int eof) { PyObject *chars; - if (Py_IS_TYPE(decoder, &PyIncrementalNewlineDecoder_Type)) + if (Py_IS_TYPE(decoder, state->PyIncrementalNewlineDecoder_Type)) chars = _PyIncrementalNewlineDecoder_decode(decoder, bytes, eof); else chars = PyObject_CallMethodObjArgs(decoder, &_Py_ID(decode), bytes, @@ -1167,6 +1169,8 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, self->buffer = Py_NewRef(buffer); /* Build the decoder object */ + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + self->state = state; if (_textiowrapper_set_decoder(self, codec_info, PyUnicode_AsUTF8(errors)) != 0) goto error; @@ -1177,7 +1181,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, /* Finished sorting out the codec details */ Py_CLEAR(codec_info); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); if (Py_IS_TYPE(buffer, state->PyBufferedReader_Type) || Py_IS_TYPE(buffer, state->PyBufferedWriter_Type) || Py_IS_TYPE(buffer, state->PyBufferedRandom_Type)) @@ -1214,7 +1217,6 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; } - self->state = state; self->ok = 1; return 0; @@ -1843,7 +1845,8 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) nbytes = input_chunk_buf.len; eof = (nbytes == 0); - decoded_chars = _textiowrapper_decode(self->decoder, input_chunk, eof); + decoded_chars = _textiowrapper_decode(self->state, self->decoder, + input_chunk, eof); PyBuffer_Release(&input_chunk_buf); if (decoded_chars == NULL) goto fail; @@ -1913,7 +1916,8 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) if (bytes == NULL) goto fail; - if (Py_IS_TYPE(self->decoder, &PyIncrementalNewlineDecoder_Type)) + _PyIO_State *state = self->state; + if (Py_IS_TYPE(self->decoder, state->PyIncrementalNewlineDecoder_Type)) decoded = _PyIncrementalNewlineDecoder_decode(self->decoder, bytes, 1); else From webhook-mailer at python.org Fri May 5 22:40:32 2023 From: webhook-mailer at python.org (FFY00) Date: Sat, 06 May 2023 02:40:32 -0000 Subject: [Python-checkins] gh-102215: importlib documentation cleanups Message-ID: <mailman.196.1683340833.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4cd95dce0b8d7bb8a16468ec8b5b3429555417f1 commit: 4cd95dce0b8d7bb8a16468ec8b5b3429555417f1 branch: main author: Sam Morris <sam at robots.org.uk> committer: FFY00 <filipe.lains at gmail.com> date: 2023-05-06T03:40:19+01:00 summary: gh-102215: importlib documentation cleanups files: M Doc/library/importlib.metadata.rst M Doc/library/importlib.resources.rst diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 3097bcf47b62..d2cc769e2c84 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -1,11 +1,11 @@ .. _using: -================================= - Using :mod:`!importlib.metadata` -================================= +======================================================== +:mod:`!importlib.metadata` -- Accessing package metadata +======================================================== .. module:: importlib.metadata - :synopsis: The implementation of the importlib metadata. + :synopsis: Accessing package metadata .. versionadded:: 3.8 .. versionchanged:: 3.10 @@ -13,7 +13,7 @@ **Source code:** :source:`Lib/importlib/metadata/__init__.py` -``importlib_metadata`` is a library that provides access to +``importlib.metadata`` is a library that provides access to the metadata of an installed `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_, such as its entry points or its top-level names (`Import Package <https://packaging.python.org/en/latest/glossary/#term-Import-Package>`_\s, modules, if any). @@ -24,7 +24,7 @@ API`_ and `metadata API`_ of ``pkg_resources``. Along with this package can eliminate the need to use the older and less efficient ``pkg_resources`` package. -``importlib_metadata`` operates on third-party *distribution packages* +``importlib.metadata`` operates on third-party *distribution packages* installed into Python's ``site-packages`` directory via tools such as `pip <https://pypi.org/project/pip/>`_. Specifically, it works with distributions with discoverable @@ -368,7 +368,7 @@ system :ref:`finders <finders-and-loaders>`. To find a distribution package's m ``importlib.metadata`` queries the list of :term:`meta path finders <meta path finder>` on :data:`sys.meta_path`. -By default ``importlib_metadata`` installs a finder for distribution packages +By default ``importlib.metadata`` installs a finder for distribution packages found on the file system. This finder doesn't actually find any *distributions*, but it can find their metadata. diff --git a/Doc/library/importlib.resources.rst b/Doc/library/importlib.resources.rst index 4c6aa59bf9f5..755693840fec 100644 --- a/Doc/library/importlib.resources.rst +++ b/Doc/library/importlib.resources.rst @@ -1,5 +1,5 @@ -:mod:`importlib.resources` -- Resources ---------------------------------------- +:mod:`importlib.resources` -- Package resource reading, opening and access +-------------------------------------------------------------------------- .. module:: importlib.resources :synopsis: Package resource reading, opening, and access @@ -97,7 +97,7 @@ for example, a package and its resources can be imported from a zip file using Deprecated functions --------------------- +^^^^^^^^^^^^^^^^^^^^ An older, deprecated set of functions is still available, but is scheduled for removal in a future version of Python. From webhook-mailer at python.org Fri May 5 23:54:15 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 06 May 2023 03:54:15 -0000 Subject: [Python-checkins] GH-97950: Use new-style index directive ('builtin') (#104164) Message-ID: <mailman.197.1683345256.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f5088006ca8e9654fbc3de119462f0ab764e408b commit: f5088006ca8e9654fbc3de119462f0ab764e408b branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-06T06:54:08+03:00 summary: GH-97950: Use new-style index directive ('builtin') (#104164) * Uncomment builtin removal in pairindextypes * Use new-style index directive ('builtin') - C API * Use new-style index directive ('builtin') - Extending * Use new-style index directive ('builtin') - Library * Use new-style index directive ('builtin') - Reference * Use new-style index directive ('builtin') - Tutorial files: M Doc/c-api/dict.rst M Doc/c-api/import.rst M Doc/c-api/list.rst M Doc/c-api/mapping.rst M Doc/c-api/number.rst M Doc/c-api/object.rst M Doc/c-api/sequence.rst M Doc/c-api/set.rst M Doc/c-api/structures.rst M Doc/c-api/typeobj.rst M Doc/extending/newtypes.rst M Doc/library/dis.rst M Doc/library/functions.rst M Doc/library/pprint.rst M Doc/library/stdtypes.rst M Doc/library/types.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/simple_stmts.rst M Doc/reference/toplevel_components.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/inputoutput.rst M Doc/tutorial/stdlib.rst diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index f02abb01f022..0ca8ad624b20 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -154,7 +154,7 @@ Dictionary Objects .. c:function:: Py_ssize_t PyDict_Size(PyObject *p) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the number of items in the dictionary. This is equivalent to ``len(p)`` on a dictionary. diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 8e5af32b65e0..79843ba521ab 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -41,7 +41,7 @@ Importing Modules .. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist) - .. index:: builtin: __import__ + .. index:: pair: built-in function; __import__ Import a module. This is best described by referring to the built-in Python function :func:`__import__`. @@ -120,7 +120,7 @@ Importing Modules .. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co) - .. index:: builtin: compile + .. index:: pair: built-in function; compile Given a module name (possibly of the form ``package.module``) and a code object read from a Python bytecode file or obtained from the built-in function diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index 317421f0db84..dbf35611eccd 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -45,7 +45,7 @@ List Objects .. c:function:: Py_ssize_t PyList_Size(PyObject *list) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the length of the list object in *list*; this is equivalent to ``len(list)`` on a list object. @@ -138,7 +138,7 @@ List Objects .. c:function:: PyObject* PyList_AsTuple(PyObject *list) - .. index:: builtin: tuple + .. index:: pair: built-in function; tuple Return a new tuple object containing the contents of *list*; equivalent to ``tuple(list)``. diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst index 3c9d282c6d0a..cffb0ed50fb7 100644 --- a/Doc/c-api/mapping.rst +++ b/Doc/c-api/mapping.rst @@ -20,7 +20,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and .. c:function:: Py_ssize_t PyMapping_Size(PyObject *o) Py_ssize_t PyMapping_Length(PyObject *o) - .. index:: builtin: len + .. index:: pair: built-in function; len Returns the number of keys in object *o* on success, and ``-1`` on failure. This is equivalent to the Python expression ``len(o)``. diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst index 70b91f8c2d0c..13d3c5af9569 100644 --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -64,7 +64,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Divmod(PyObject *o1, PyObject *o2) - .. index:: builtin: divmod + .. index:: pair: built-in function; divmod See the built-in function :func:`divmod`. Returns ``NULL`` on failure. This is the equivalent of the Python expression ``divmod(o1, o2)``. @@ -72,7 +72,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Power(PyObject *o1, PyObject *o2, PyObject *o3) - .. index:: builtin: pow + .. index:: pair: built-in function; pow See the built-in function :func:`pow`. Returns ``NULL`` on failure. This is the equivalent of the Python expression ``pow(o1, o2, o3)``, where *o3* is optional. @@ -94,7 +94,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Absolute(PyObject *o) - .. index:: builtin: abs + .. index:: pair: built-in function; abs Returns the absolute value of *o*, or ``NULL`` on failure. This is the equivalent of the Python expression ``abs(o)``. @@ -192,7 +192,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_InPlacePower(PyObject *o1, PyObject *o2, PyObject *o3) - .. index:: builtin: pow + .. index:: pair: built-in function; pow See the built-in function :func:`pow`. Returns ``NULL`` on failure. The operation is done *in-place* when *o1* supports it. This is the equivalent of the Python @@ -238,7 +238,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Long(PyObject *o) - .. index:: builtin: int + .. index:: pair: built-in function; int Returns the *o* converted to an integer object on success, or ``NULL`` on failure. This is the equivalent of the Python expression ``int(o)``. @@ -246,7 +246,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Float(PyObject *o) - .. index:: builtin: float + .. index:: pair: built-in function; float Returns the *o* converted to a float object on success, or ``NULL`` on failure. This is the equivalent of the Python expression ``float(o)``. diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index a0c3194ab0fb..a25ff244c9f0 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -190,7 +190,7 @@ Object Protocol .. c:function:: PyObject* PyObject_Repr(PyObject *o) - .. index:: builtin: repr + .. index:: pair: built-in function; repr Compute a string representation of object *o*. Returns the string representation on success, ``NULL`` on failure. This is the equivalent of the @@ -202,7 +202,7 @@ Object Protocol .. c:function:: PyObject* PyObject_ASCII(PyObject *o) - .. index:: builtin: ascii + .. index:: pair: built-in function; ascii As :c:func:`PyObject_Repr`, compute a string representation of object *o*, but escape the non-ASCII characters in the string returned by @@ -227,7 +227,7 @@ Object Protocol .. c:function:: PyObject* PyObject_Bytes(PyObject *o) - .. index:: builtin: bytes + .. index:: pair: built-in function; bytes Compute a bytes representation of object *o*. ``NULL`` is returned on failure and a bytes object on success. This is equivalent to the Python @@ -278,7 +278,7 @@ Object Protocol .. c:function:: Py_hash_t PyObject_Hash(PyObject *o) - .. index:: builtin: hash + .. index:: pair: built-in function; hash Compute and return the hash value of an object *o*. On failure, return ``-1``. This is the equivalent of the Python expression ``hash(o)``. @@ -312,7 +312,7 @@ Object Protocol .. c:function:: PyObject* PyObject_Type(PyObject *o) - .. index:: builtin: type + .. index:: pair: built-in function; type When *o* is non-``NULL``, returns a type object corresponding to the object type of object *o*. On failure, raises :exc:`SystemError` and returns ``NULL``. This @@ -332,7 +332,7 @@ Object Protocol .. c:function:: Py_ssize_t PyObject_Size(PyObject *o) Py_ssize_t PyObject_Length(PyObject *o) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the length of object *o*. If the object *o* provides either the sequence and mapping protocols, the sequence length is returned. On error, ``-1`` is diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst index c78d273f9f14..402a3e5e09ff 100644 --- a/Doc/c-api/sequence.rst +++ b/Doc/c-api/sequence.rst @@ -18,7 +18,7 @@ Sequence Protocol .. c:function:: Py_ssize_t PySequence_Size(PyObject *o) Py_ssize_t PySequence_Length(PyObject *o) - .. index:: builtin: len + .. index:: pair: built-in function; len Returns the number of objects in sequence *o* on success, and ``-1`` on failure. This is equivalent to the Python expression ``len(o)``. @@ -120,7 +120,7 @@ Sequence Protocol .. c:function:: PyObject* PySequence_Tuple(PyObject *o) - .. index:: builtin: tuple + .. index:: pair: built-in function; tuple Return a tuple object with the same contents as the sequence or iterable *o*, or ``NULL`` on failure. If *o* is a tuple, a new reference will be returned, diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 8e8af6025225..d642a5f1902e 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -107,7 +107,7 @@ or :class:`frozenset` or instances of their subtypes. .. c:function:: Py_ssize_t PySet_Size(PyObject *anyset) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the length of a :class:`set` or :class:`frozenset` object. Equivalent to ``len(anyset)``. Raises a :exc:`PyExc_SystemError` if *anyset* is not a diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 338db6378d24..aae1b9518044 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -347,7 +347,7 @@ method. .. data:: METH_CLASS - .. index:: builtin: classmethod + .. index:: pair: built-in function; classmethod The method will be passed the type object as the first parameter rather than an instance of the type. This is used to create *class methods*, @@ -357,7 +357,7 @@ method. .. data:: METH_STATIC - .. index:: builtin: staticmethod + .. index:: pair: built-in function; staticmethod The method will be passed ``NULL`` as the first parameter rather than an instance of the type. This is used to create *static methods*, similar to diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index e13db3fb2211..0584989233de 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -805,7 +805,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: reprfunc PyTypeObject.tp_repr - .. index:: builtin: repr + .. index:: pair: built-in function; repr An optional pointer to a function that implements the built-in function :func:`repr`. @@ -870,7 +870,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: hashfunc PyTypeObject.tp_hash - .. index:: builtin: hash + .. index:: pair: built-in function; hash An optional pointer to a function that implements the built-in function :func:`hash`. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 56b40acdb69f..6852a385f0c6 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -149,7 +149,7 @@ done. This can be done using the :c:func:`PyErr_Fetch` and .. index:: single: string; object representation - builtin: repr + pair: built-in function; repr Object Presentation ------------------- diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 6c3f436ddb14..296d8a9c66fa 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1367,7 +1367,7 @@ iterations of the loop. .. opcode:: BUILD_SLICE (argc) - .. index:: builtin: slice + .. index:: pair: built-in function; slice Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2, implements:: diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 80b7b8b4f4ed..48a832db60e9 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -562,7 +562,7 @@ are always available. They are listed here in alphabetical order. Raises an :ref:`auditing event <auditing>` ``exec`` with the code object as the argument. Code compilation events may also be raised. -.. index:: builtin: exec +.. index:: pair: built-in function; exec .. function:: exec(object, globals=None, locals=None, /, *, closure=None) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 4e29192311fc..d8269ef48cb3 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -159,7 +159,7 @@ The :mod:`pprint` module defines one class: .. function:: isreadable(object) - .. index:: builtin: eval + .. index:: pair: built-in function; eval Determine if the formatted representation of *object* is "readable", or can be used to reconstruct the value using :func:`eval`. This always returns ``False`` @@ -218,7 +218,7 @@ created. .. method:: PrettyPrinter.isreadable(object) - .. index:: builtin: eval + .. index:: pair: built-in function; eval Determine if the formatted representation of the object is "readable," or can be used to reconstruct the value using :func:`eval`. Note that this returns diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index c739485c5564..9203afbf6a4e 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -244,9 +244,9 @@ and imaginary parts. .. index:: single: arithmetic - builtin: int - builtin: float - builtin: complex + pair: built-in function; int + pair: built-in function; float + pair: built-in function; complex single: operator; + (plus) single: + (plus); unary operator single: + (plus); binary operator @@ -945,9 +945,9 @@ operations have the same priority as the corresponding numeric operations. [3]_ .. index:: triple: operations on; sequence; types - builtin: len - builtin: min - builtin: max + pair: built-in function; len + pair: built-in function; min + pair: built-in function; max pair: concatenation; operation pair: repetition; operation pair: subscript; operation @@ -1113,7 +1113,7 @@ Immutable Sequence Types .. index:: triple: immutable; sequence; types pair: object; tuple - builtin: hash + pair: built-in function; hash The only operation that immutable sequence types generally implement that is not also implemented by mutable sequence types is support for the :func:`hash` @@ -4419,7 +4419,7 @@ Mapping Types --- :class:`dict` triple: operations on; mapping; types triple: operations on; dictionary; type pair: statement; del - builtin: len + pair: built-in function; len A :term:`mapping` object maps :term:`hashable` values to arbitrary objects. Mappings are mutable objects. There is currently only one standard mapping @@ -5348,7 +5348,7 @@ Code Objects ------------ .. index:: - builtin: compile + pair: built-in function; compile single: __code__ (function object attribute) Code objects are used by the implementation to represent "pseudo-compiled" @@ -5362,8 +5362,8 @@ Accessing ``__code__`` raises an :ref:`auditing event <auditing>` ``object.__getattr__`` with arguments ``obj`` and ``"__code__"``. .. index:: - builtin: exec - builtin: eval + pair: built-in function; exec + pair: built-in function; eval A code object can be executed or evaluated by passing it (instead of a source string) to the :func:`exec` or :func:`eval` built-in functions. @@ -5377,7 +5377,7 @@ Type Objects ------------ .. index:: - builtin: type + pair: built-in function; type pair: module; types Type objects represent the various object types. An object's type is accessed diff --git a/Doc/library/types.rst b/Doc/library/types.rst index a15fb5cfa494..8cbe17df16f1 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -186,7 +186,7 @@ Standard names are defined for the following types: .. class:: CodeType(**kwargs) - .. index:: builtin: compile + .. index:: pair: built-in function; compile The type for code objects such as returned by :func:`compile`. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index e9c1c493ae42..9d1e5b6c596d 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -188,7 +188,7 @@ those made in the suite of the for-loop:: .. index:: - builtin: range + pair: built-in function; range Names in the target list are not deleted when the loop is finished, but if the sequence is empty, they will not have been assigned to at all by the loop. Hint: diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 0a9cabc158b9..c0734e49f291 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -21,8 +21,8 @@ conformance to Von Neumann's model of a "stored program computer", code is also represented by objects.) .. index:: - builtin: id - builtin: type + pair: built-in function; id + pair: built-in function; type single: identity of an object single: value of an object single: type of an object @@ -267,7 +267,7 @@ Ellipsis Sequences .. index:: - builtin: len + pair: built-in function; len pair: object; sequence single: index operation single: item selection @@ -308,8 +308,8 @@ Sequences Strings .. index:: - builtin: chr - builtin: ord + pair: built-in function; chr + pair: built-in function; ord single: character single: integer single: Unicode @@ -384,7 +384,7 @@ Sequences Set types .. index:: - builtin: len + pair: built-in function; len pair: object; set type These represent unordered, finite sets of unique, immutable objects. As such, @@ -418,7 +418,7 @@ Set types Mappings .. index:: - builtin: len + pair: built-in function; len single: subscription pair: object; mapping @@ -908,7 +908,7 @@ Class instances I/O objects (also known as file objects) .. index:: - builtin: open + pair: built-in function; open pair: module; io single: popen() (in module os) single: makefile() (socket method) @@ -1177,7 +1177,7 @@ Internal types and the ``tb_next`` attribute of existing instances can be updated. Slice objects - .. index:: builtin: slice + .. index:: pair: built-in function; slice Slice objects are used to represent slices for :meth:`~object.__getitem__` @@ -1411,7 +1411,7 @@ Basic customization .. method:: object.__bytes__(self) - .. index:: builtin: bytes + .. index:: pair: built-in function; bytes Called by :ref:`bytes <func-bytes>` to compute a byte-string representation of an object. This should return a :class:`bytes` object. @@ -1419,7 +1419,7 @@ Basic customization .. index:: single: string; __format__() (object method) pair: string; conversion - builtin: print + pair: built-in function; print .. method:: object.__format__(self, format_spec) @@ -1499,7 +1499,7 @@ Basic customization .. index:: pair: object; dictionary - builtin: hash + pair: built-in function; hash Called by built-in function :func:`hash` and for operations on members of hashed collections including :class:`set`, :class:`frozenset`, and @@ -2050,7 +2050,7 @@ Metaclasses .. index:: single: metaclass - builtin: type + pair: built-in function; type single: = (equals); class definition By default, classes are constructed using :func:`type`. The class body is @@ -2477,7 +2477,7 @@ through the object's keys; for sequences, it should iterate through the values. .. method:: object.__len__(self) .. index:: - builtin: len + pair: built-in function; len single: __bool__() (object method) Called to implement the built-in function :func:`len`. Should return the length @@ -2635,9 +2635,9 @@ left undefined. object.__or__(self, other) .. index:: - builtin: divmod - builtin: pow - builtin: pow + pair: built-in function; divmod + pair: built-in function; pow + pair: built-in function; pow These methods are called to implement the binary arithmetic operations (``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`, @@ -2670,8 +2670,8 @@ left undefined. object.__ror__(self, other) .. index:: - builtin: divmod - builtin: pow + pair: built-in function; divmod + pair: built-in function; pow These methods are called to implement the binary arithmetic operations (``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`, @@ -2683,7 +2683,7 @@ left undefined. ``type(y).__rsub__(y, x)`` is called if ``type(x).__sub__(x, y)`` returns *NotImplemented*. - .. index:: builtin: pow + .. index:: pair: built-in function; pow Note that ternary :func:`pow` will not try calling :meth:`__rpow__` (the coercion rules would become too complicated). @@ -2730,7 +2730,7 @@ left undefined. object.__abs__(self) object.__invert__(self) - .. index:: builtin: abs + .. index:: pair: built-in function; abs Called to implement the unary arithmetic operations (``-``, ``+``, :func:`abs` and ``~``). @@ -2741,9 +2741,9 @@ left undefined. object.__float__(self) .. index:: - builtin: complex - builtin: int - builtin: float + pair: built-in function; complex + pair: built-in function; int + pair: built-in function; float Called to implement the built-in functions :func:`complex`, :func:`int` and :func:`float`. Should return a value @@ -2768,7 +2768,7 @@ left undefined. object.__floor__(self) object.__ceil__(self) - .. index:: builtin: round + .. index:: pair: built-in function; round Called to implement the built-in function :func:`round` and :mod:`math` functions :func:`~math.trunc`, :func:`~math.floor` and :func:`~math.ceil`. diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index ca1aa744389b..f7a8b44d1954 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -53,7 +53,7 @@ An expression statement evaluates the expression list (which may be a single expression). .. index:: - builtin: repr + pair: built-in function; repr pair: object; None pair: string; conversion single: output @@ -970,9 +970,9 @@ annotation. them or silently change the meaning of the program. .. index:: - builtin: exec - builtin: eval - builtin: compile + pair: built-in function; exec + pair: built-in function; eval + pair: built-in function; compile **Programmer's note:** :keyword:`global` is a directive to the parser. It applies only to code parsed at the same time as the :keyword:`!global` statement. diff --git a/Doc/reference/toplevel_components.rst b/Doc/reference/toplevel_components.rst index ee472ace6e21..dd3d3d6878e2 100644 --- a/Doc/reference/toplevel_components.rst +++ b/Doc/reference/toplevel_components.rst @@ -98,7 +98,7 @@ Expression input ================ .. index:: single: input -.. index:: builtin: eval +.. index:: pair: built-in function; eval :func:`eval` is used for expression input. It ignores leading whitespace. The string argument to :func:`eval` must have the following form: diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 8fc44cab4445..4fe54e30b82b 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -695,7 +695,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('object', None) pairindextypes.pop('exception', None) pairindextypes.pop('statement', None) - # pairindextypes.pop('builtin', None) + pairindextypes.pop('builtin', None) def setup(app): diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 3fcf4e3f43a3..f5cdd84cbade 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -285,7 +285,7 @@ Reading and Writing Files ========================= .. index:: - builtin: open + pair: built-in function; open pair: object; file :func:`open` returns a :term:`file object`, and is most commonly used with diff --git a/Doc/tutorial/stdlib.rst b/Doc/tutorial/stdlib.rst index 4f5ada90eb57..6bae279c5e9c 100644 --- a/Doc/tutorial/stdlib.rst +++ b/Doc/tutorial/stdlib.rst @@ -24,7 +24,7 @@ Be sure to use the ``import os`` style instead of ``from os import *``. This will keep :func:`os.open` from shadowing the built-in :func:`open` function which operates much differently. -.. index:: builtin: help +.. index:: pair: built-in function; help The built-in :func:`dir` and :func:`help` functions are useful as interactive aids for working with large modules like :mod:`os`:: From webhook-mailer at python.org Sat May 6 00:14:43 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 06 May 2023 04:14:43 -0000 Subject: [Python-checkins] [3.11] GH-97950: Use new-style index directive ('builtin') (GH-104164) (#104221) Message-ID: <mailman.198.1683346485.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4b11af058e9c5df2b737f785a2615676650810f4 commit: 4b11af058e9c5df2b737f785a2615676650810f4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-06T07:14:37+03:00 summary: [3.11] GH-97950: Use new-style index directive ('builtin') (GH-104164) (#104221) GH-97950: Use new-style index directive ('builtin') (GH-104164) * Uncomment builtin removal in pairindextypes * Use new-style index directive ('builtin') - C API * Use new-style index directive ('builtin') - Extending * Use new-style index directive ('builtin') - Library * Use new-style index directive ('builtin') - Reference * Use new-style index directive ('builtin') - Tutorial (cherry picked from commit f5088006ca8e9654fbc3de119462f0ab764e408b) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/c-api/dict.rst M Doc/c-api/import.rst M Doc/c-api/list.rst M Doc/c-api/mapping.rst M Doc/c-api/number.rst M Doc/c-api/object.rst M Doc/c-api/sequence.rst M Doc/c-api/set.rst M Doc/c-api/structures.rst M Doc/c-api/typeobj.rst M Doc/extending/newtypes.rst M Doc/library/dis.rst M Doc/library/functions.rst M Doc/library/pprint.rst M Doc/library/stdtypes.rst M Doc/library/types.rst M Doc/reference/compound_stmts.rst M Doc/reference/datamodel.rst M Doc/reference/simple_stmts.rst M Doc/reference/toplevel_components.rst M Doc/tools/extensions/pyspecific.py M Doc/tutorial/inputoutput.rst M Doc/tutorial/stdlib.rst diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 4bfd1d01590b..17cde77c186f 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -154,7 +154,7 @@ Dictionary Objects .. c:function:: Py_ssize_t PyDict_Size(PyObject *p) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the number of items in the dictionary. This is equivalent to ``len(p)`` on a dictionary. diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 0922956c607b..57328fc16198 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -41,7 +41,7 @@ Importing Modules .. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist) - .. index:: builtin: __import__ + .. index:: pair: built-in function; __import__ Import a module. This is best described by referring to the built-in Python function :func:`__import__`. @@ -120,7 +120,7 @@ Importing Modules .. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co) - .. index:: builtin: compile + .. index:: pair: built-in function; compile Given a module name (possibly of the form ``package.module``) and a code object read from a Python bytecode file or obtained from the built-in function diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index 317421f0db84..dbf35611eccd 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -45,7 +45,7 @@ List Objects .. c:function:: Py_ssize_t PyList_Size(PyObject *list) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the length of the list object in *list*; this is equivalent to ``len(list)`` on a list object. @@ -138,7 +138,7 @@ List Objects .. c:function:: PyObject* PyList_AsTuple(PyObject *list) - .. index:: builtin: tuple + .. index:: pair: built-in function; tuple Return a new tuple object containing the contents of *list*; equivalent to ``tuple(list)``. diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst index 3c9d282c6d0a..cffb0ed50fb7 100644 --- a/Doc/c-api/mapping.rst +++ b/Doc/c-api/mapping.rst @@ -20,7 +20,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and .. c:function:: Py_ssize_t PyMapping_Size(PyObject *o) Py_ssize_t PyMapping_Length(PyObject *o) - .. index:: builtin: len + .. index:: pair: built-in function; len Returns the number of keys in object *o* on success, and ``-1`` on failure. This is equivalent to the Python expression ``len(o)``. diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst index 70b91f8c2d0c..13d3c5af9569 100644 --- a/Doc/c-api/number.rst +++ b/Doc/c-api/number.rst @@ -64,7 +64,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Divmod(PyObject *o1, PyObject *o2) - .. index:: builtin: divmod + .. index:: pair: built-in function; divmod See the built-in function :func:`divmod`. Returns ``NULL`` on failure. This is the equivalent of the Python expression ``divmod(o1, o2)``. @@ -72,7 +72,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Power(PyObject *o1, PyObject *o2, PyObject *o3) - .. index:: builtin: pow + .. index:: pair: built-in function; pow See the built-in function :func:`pow`. Returns ``NULL`` on failure. This is the equivalent of the Python expression ``pow(o1, o2, o3)``, where *o3* is optional. @@ -94,7 +94,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Absolute(PyObject *o) - .. index:: builtin: abs + .. index:: pair: built-in function; abs Returns the absolute value of *o*, or ``NULL`` on failure. This is the equivalent of the Python expression ``abs(o)``. @@ -192,7 +192,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_InPlacePower(PyObject *o1, PyObject *o2, PyObject *o3) - .. index:: builtin: pow + .. index:: pair: built-in function; pow See the built-in function :func:`pow`. Returns ``NULL`` on failure. The operation is done *in-place* when *o1* supports it. This is the equivalent of the Python @@ -238,7 +238,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Long(PyObject *o) - .. index:: builtin: int + .. index:: pair: built-in function; int Returns the *o* converted to an integer object on success, or ``NULL`` on failure. This is the equivalent of the Python expression ``int(o)``. @@ -246,7 +246,7 @@ Number Protocol .. c:function:: PyObject* PyNumber_Float(PyObject *o) - .. index:: builtin: float + .. index:: pair: built-in function; float Returns the *o* converted to a float object on success, or ``NULL`` on failure. This is the equivalent of the Python expression ``float(o)``. diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 0a12bb9e8c54..1a0fe332590d 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -190,7 +190,7 @@ Object Protocol .. c:function:: PyObject* PyObject_Repr(PyObject *o) - .. index:: builtin: repr + .. index:: pair: built-in function; repr Compute a string representation of object *o*. Returns the string representation on success, ``NULL`` on failure. This is the equivalent of the @@ -202,7 +202,7 @@ Object Protocol .. c:function:: PyObject* PyObject_ASCII(PyObject *o) - .. index:: builtin: ascii + .. index:: pair: built-in function; ascii As :c:func:`PyObject_Repr`, compute a string representation of object *o*, but escape the non-ASCII characters in the string returned by @@ -227,7 +227,7 @@ Object Protocol .. c:function:: PyObject* PyObject_Bytes(PyObject *o) - .. index:: builtin: bytes + .. index:: pair: built-in function; bytes Compute a bytes representation of object *o*. ``NULL`` is returned on failure and a bytes object on success. This is equivalent to the Python @@ -278,7 +278,7 @@ Object Protocol .. c:function:: Py_hash_t PyObject_Hash(PyObject *o) - .. index:: builtin: hash + .. index:: pair: built-in function; hash Compute and return the hash value of an object *o*. On failure, return ``-1``. This is the equivalent of the Python expression ``hash(o)``. @@ -312,7 +312,7 @@ Object Protocol .. c:function:: PyObject* PyObject_Type(PyObject *o) - .. index:: builtin: type + .. index:: pair: built-in function; type When *o* is non-``NULL``, returns a type object corresponding to the object type of object *o*. On failure, raises :exc:`SystemError` and returns ``NULL``. This @@ -332,7 +332,7 @@ Object Protocol .. c:function:: Py_ssize_t PyObject_Size(PyObject *o) Py_ssize_t PyObject_Length(PyObject *o) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the length of object *o*. If the object *o* provides either the sequence and mapping protocols, the sequence length is returned. On error, ``-1`` is diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst index c78d273f9f14..402a3e5e09ff 100644 --- a/Doc/c-api/sequence.rst +++ b/Doc/c-api/sequence.rst @@ -18,7 +18,7 @@ Sequence Protocol .. c:function:: Py_ssize_t PySequence_Size(PyObject *o) Py_ssize_t PySequence_Length(PyObject *o) - .. index:: builtin: len + .. index:: pair: built-in function; len Returns the number of objects in sequence *o* on success, and ``-1`` on failure. This is equivalent to the Python expression ``len(o)``. @@ -120,7 +120,7 @@ Sequence Protocol .. c:function:: PyObject* PySequence_Tuple(PyObject *o) - .. index:: builtin: tuple + .. index:: pair: built-in function; tuple Return a tuple object with the same contents as the sequence or iterable *o*, or ``NULL`` on failure. If *o* is a tuple, a new reference will be returned, diff --git a/Doc/c-api/set.rst b/Doc/c-api/set.rst index 8e8af6025225..d642a5f1902e 100644 --- a/Doc/c-api/set.rst +++ b/Doc/c-api/set.rst @@ -107,7 +107,7 @@ or :class:`frozenset` or instances of their subtypes. .. c:function:: Py_ssize_t PySet_Size(PyObject *anyset) - .. index:: builtin: len + .. index:: pair: built-in function; len Return the length of a :class:`set` or :class:`frozenset` object. Equivalent to ``len(anyset)``. Raises a :exc:`PyExc_SystemError` if *anyset* is not a diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 30760c0db88c..cfd6d20a3489 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -366,7 +366,7 @@ method. .. data:: METH_CLASS - .. index:: builtin: classmethod + .. index:: pair: built-in function; classmethod The method will be passed the type object as the first parameter rather than an instance of the type. This is used to create *class methods*, @@ -376,7 +376,7 @@ method. .. data:: METH_STATIC - .. index:: builtin: staticmethod + .. index:: pair: built-in function; staticmethod The method will be passed ``NULL`` as the first parameter rather than an instance of the type. This is used to create *static methods*, similar to diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index aa2de3344778..ce327166f3ab 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -803,7 +803,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: reprfunc PyTypeObject.tp_repr - .. index:: builtin: repr + .. index:: pair: built-in function; repr An optional pointer to a function that implements the built-in function :func:`repr`. @@ -868,7 +868,7 @@ and :c:type:`PyType_Type` effectively act as defaults.) .. c:member:: hashfunc PyTypeObject.tp_hash - .. index:: builtin: hash + .. index:: pair: built-in function; hash An optional pointer to a function that implements the built-in function :func:`hash`. diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 5ba6383640cc..e60db11b5f10 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -149,7 +149,7 @@ done. This can be done using the :c:func:`PyErr_Fetch` and .. index:: single: string; object representation - builtin: repr + pair: built-in function; repr Object Presentation ------------------- diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 7915be81f1f4..aec095dd7601 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1268,7 +1268,7 @@ iterations of the loop. .. opcode:: BUILD_SLICE (argc) - .. index:: builtin: slice + .. index:: pair: built-in function; slice Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2, ``slice(TOS1, TOS)`` is pushed; if it is 3, ``slice(TOS2, TOS1, TOS)`` is diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 1a7311911ba7..f3dc02f03db0 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -561,7 +561,7 @@ are always available. They are listed here in alphabetical order. Raises an :ref:`auditing event <auditing>` ``exec`` with the code object as the argument. Code compilation events may also be raised. -.. index:: builtin: exec +.. index:: pair: built-in function; exec .. function:: exec(object, globals=None, locals=None, /, *, closure=None) diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst index 3da5aa9389b1..2a3bc92e1733 100644 --- a/Doc/library/pprint.rst +++ b/Doc/library/pprint.rst @@ -159,7 +159,7 @@ The :mod:`pprint` module defines one class: .. function:: isreadable(object) - .. index:: builtin: eval + .. index:: pair: built-in function; eval Determine if the formatted representation of *object* is "readable", or can be used to reconstruct the value using :func:`eval`. This always returns ``False`` @@ -214,7 +214,7 @@ created. .. method:: PrettyPrinter.isreadable(object) - .. index:: builtin: eval + .. index:: pair: built-in function; eval Determine if the formatted representation of the object is "readable," or can be used to reconstruct the value using :func:`eval`. Note that this returns diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index d57581f1d535..12f2fe9e2e89 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -244,9 +244,9 @@ and imaginary parts. .. index:: single: arithmetic - builtin: int - builtin: float - builtin: complex + pair: built-in function; int + pair: built-in function; float + pair: built-in function; complex single: operator; + (plus) single: + (plus); unary operator single: + (plus); binary operator @@ -906,9 +906,9 @@ operations have the same priority as the corresponding numeric operations. [3]_ .. index:: triple: operations on; sequence; types - builtin: len - builtin: min - builtin: max + pair: built-in function; len + pair: built-in function; min + pair: built-in function; max pair: concatenation; operation pair: repetition; operation pair: subscript; operation @@ -1074,7 +1074,7 @@ Immutable Sequence Types .. index:: triple: immutable; sequence; types pair: object; tuple - builtin: hash + pair: built-in function; hash The only operation that immutable sequence types generally implement that is not also implemented by mutable sequence types is support for the :func:`hash` @@ -4372,7 +4372,7 @@ Mapping Types --- :class:`dict` triple: operations on; mapping; types triple: operations on; dictionary; type pair: statement; del - builtin: len + pair: built-in function; len A :term:`mapping` object maps :term:`hashable` values to arbitrary objects. Mappings are mutable objects. There is currently only one standard mapping @@ -5295,7 +5295,7 @@ Code Objects ------------ .. index:: - builtin: compile + pair: built-in function; compile single: __code__ (function object attribute) Code objects are used by the implementation to represent "pseudo-compiled" @@ -5309,8 +5309,8 @@ Accessing ``__code__`` raises an :ref:`auditing event <auditing>` ``object.__getattr__`` with arguments ``obj`` and ``"__code__"``. .. index:: - builtin: exec - builtin: eval + pair: built-in function; exec + pair: built-in function; eval A code object can be executed or evaluated by passing it (instead of a source string) to the :func:`exec` or :func:`eval` built-in functions. @@ -5324,7 +5324,7 @@ Type Objects ------------ .. index:: - builtin: type + pair: built-in function; type pair: module; types Type objects represent the various object types. An object's type is accessed diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 89d30156fc73..5625140b50b9 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -146,7 +146,7 @@ Standard names are defined for the following types: .. class:: CodeType(**kwargs) - .. index:: builtin: compile + .. index:: pair: built-in function; compile The type for code objects such as returned by :func:`compile`. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index cd448d213487..d6492ac18f92 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -188,7 +188,7 @@ those made in the suite of the for-loop:: .. index:: - builtin: range + pair: built-in function; range Names in the target list are not deleted when the loop is finished, but if the sequence is empty, they will not have been assigned to at all by the loop. Hint: diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 73eb402b7166..112d5f8e8a84 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -21,8 +21,8 @@ conformance to Von Neumann's model of a "stored program computer", code is also represented by objects.) .. index:: - builtin: id - builtin: type + pair: built-in function; id + pair: built-in function; type single: identity of an object single: value of an object single: type of an object @@ -267,7 +267,7 @@ Ellipsis Sequences .. index:: - builtin: len + pair: built-in function; len pair: object; sequence single: index operation single: item selection @@ -308,8 +308,8 @@ Sequences Strings .. index:: - builtin: chr - builtin: ord + pair: built-in function; chr + pair: built-in function; ord single: character single: integer single: Unicode @@ -384,7 +384,7 @@ Sequences Set types .. index:: - builtin: len + pair: built-in function; len pair: object; set type These represent unordered, finite sets of unique, immutable objects. As such, @@ -418,7 +418,7 @@ Set types Mappings .. index:: - builtin: len + pair: built-in function; len single: subscription pair: object; mapping @@ -908,7 +908,7 @@ Class instances I/O objects (also known as file objects) .. index:: - builtin: open + pair: built-in function; open pair: module; io single: popen() (in module os) single: makefile() (socket method) @@ -1176,7 +1176,7 @@ Internal types and the ``tb_next`` attribute of existing instances can be updated. Slice objects - .. index:: builtin: slice + .. index:: pair: built-in function; slice Slice objects are used to represent slices for :meth:`~object.__getitem__` @@ -1410,7 +1410,7 @@ Basic customization .. method:: object.__bytes__(self) - .. index:: builtin: bytes + .. index:: pair: built-in function; bytes Called by :ref:`bytes <func-bytes>` to compute a byte-string representation of an object. This should return a :class:`bytes` object. @@ -1418,7 +1418,7 @@ Basic customization .. index:: single: string; __format__() (object method) pair: string; conversion - builtin: print + pair: built-in function; print .. method:: object.__format__(self, format_spec) @@ -1498,7 +1498,7 @@ Basic customization .. index:: pair: object; dictionary - builtin: hash + pair: built-in function; hash Called by built-in function :func:`hash` and for operations on members of hashed collections including :class:`set`, :class:`frozenset`, and @@ -2049,7 +2049,7 @@ Metaclasses .. index:: single: metaclass - builtin: type + pair: built-in function; type single: = (equals); class definition By default, classes are constructed using :func:`type`. The class body is @@ -2472,7 +2472,7 @@ through the object's keys; for sequences, it should iterate through the values. .. method:: object.__len__(self) .. index:: - builtin: len + pair: built-in function; len single: __bool__() (object method) Called to implement the built-in function :func:`len`. Should return the length @@ -2630,9 +2630,9 @@ left undefined. object.__or__(self, other) .. index:: - builtin: divmod - builtin: pow - builtin: pow + pair: built-in function; divmod + pair: built-in function; pow + pair: built-in function; pow These methods are called to implement the binary arithmetic operations (``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`, @@ -2665,8 +2665,8 @@ left undefined. object.__ror__(self, other) .. index:: - builtin: divmod - builtin: pow + pair: built-in function; divmod + pair: built-in function; pow These methods are called to implement the binary arithmetic operations (``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`, @@ -2678,7 +2678,7 @@ left undefined. ``type(y).__rsub__(y, x)`` is called if ``type(x).__sub__(x, y)`` returns *NotImplemented*. - .. index:: builtin: pow + .. index:: pair: built-in function; pow Note that ternary :func:`pow` will not try calling :meth:`__rpow__` (the coercion rules would become too complicated). @@ -2725,7 +2725,7 @@ left undefined. object.__abs__(self) object.__invert__(self) - .. index:: builtin: abs + .. index:: pair: built-in function; abs Called to implement the unary arithmetic operations (``-``, ``+``, :func:`abs` and ``~``). @@ -2736,9 +2736,9 @@ left undefined. object.__float__(self) .. index:: - builtin: complex - builtin: int - builtin: float + pair: built-in function; complex + pair: built-in function; int + pair: built-in function; float Called to implement the built-in functions :func:`complex`, :func:`int` and :func:`float`. Should return a value @@ -2763,7 +2763,7 @@ left undefined. object.__floor__(self) object.__ceil__(self) - .. index:: builtin: round + .. index:: pair: built-in function; round Called to implement the built-in function :func:`round` and :mod:`math` functions :func:`~math.trunc`, :func:`~math.floor` and :func:`~math.ceil`. diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index ca1aa744389b..f7a8b44d1954 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -53,7 +53,7 @@ An expression statement evaluates the expression list (which may be a single expression). .. index:: - builtin: repr + pair: built-in function; repr pair: object; None pair: string; conversion single: output @@ -970,9 +970,9 @@ annotation. them or silently change the meaning of the program. .. index:: - builtin: exec - builtin: eval - builtin: compile + pair: built-in function; exec + pair: built-in function; eval + pair: built-in function; compile **Programmer's note:** :keyword:`global` is a directive to the parser. It applies only to code parsed at the same time as the :keyword:`!global` statement. diff --git a/Doc/reference/toplevel_components.rst b/Doc/reference/toplevel_components.rst index ee472ace6e21..dd3d3d6878e2 100644 --- a/Doc/reference/toplevel_components.rst +++ b/Doc/reference/toplevel_components.rst @@ -98,7 +98,7 @@ Expression input ================ .. index:: single: input -.. index:: builtin: eval +.. index:: pair: built-in function; eval :func:`eval` is used for expression input. It ignores leading whitespace. The string argument to :func:`eval` must have the following form: diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index f9b2bfdc639a..c63a5cd817be 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -700,7 +700,7 @@ def patch_pairindextypes(app) -> None: pairindextypes.pop('object', None) pairindextypes.pop('exception', None) pairindextypes.pop('statement', None) - # pairindextypes.pop('builtin', None) + pairindextypes.pop('builtin', None) def setup(app): diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 3fcf4e3f43a3..f5cdd84cbade 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -285,7 +285,7 @@ Reading and Writing Files ========================= .. index:: - builtin: open + pair: built-in function; open pair: object; file :func:`open` returns a :term:`file object`, and is most commonly used with diff --git a/Doc/tutorial/stdlib.rst b/Doc/tutorial/stdlib.rst index a94a7f459ea2..084b09a9e907 100644 --- a/Doc/tutorial/stdlib.rst +++ b/Doc/tutorial/stdlib.rst @@ -24,7 +24,7 @@ Be sure to use the ``import os`` style instead of ``from os import *``. This will keep :func:`os.open` from shadowing the built-in :func:`open` function which operates much differently. -.. index:: builtin: help +.. index:: pair: built-in function; help The built-in :func:`dir` and :func:`help` functions are useful as interactive aids for working with large modules like :mod:`os`:: From webhook-mailer at python.org Sat May 6 10:58:51 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 06 May 2023 14:58:51 -0000 Subject: [Python-checkins] gh-104233: Fix "unused variable" warning in `ceval_gil.c` (#104234) Message-ID: <mailman.199.1683385133.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6616710731b9ad1a4e6b73696e8bd5c40cf8762d commit: 6616710731b9ad1a4e6b73696e8bd5c40cf8762d branch: main author: Nikita Sobolev <mail at sobolevn.me> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-06T20:28:32+05:30 summary: gh-104233: Fix "unused variable" warning in `ceval_gil.c` (#104234) files: M Python/ceval_gil.c diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index a390bec80d55..1ac0dbcf2ecf 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -547,9 +547,11 @@ _PyEval_FiniGIL(PyInterpreterState *interp) return; } else if (!interp->ceval.own_gil) { +#ifdef Py_DEBUG PyInterpreterState *main_interp = _PyInterpreterState_Main(); assert(interp != main_interp); assert(interp->ceval.gil == main_interp->ceval.gil); +#endif interp->ceval.gil = NULL; return; } From webhook-mailer at python.org Sat May 6 11:04:48 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 06 May 2023 15:04:48 -0000 Subject: [Python-checkins] gh-65772: Clean-up turtle module (#104218) Message-ID: <mailman.200.1683385489.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e407661e7a70ad49a69df3058634bc4fccebbcd6 commit: e407661e7a70ad49a69df3058634bc4fccebbcd6 branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-06T11:04:41-04:00 summary: gh-65772: Clean-up turtle module (#104218) * Remove the unused, private, and undocumented name `_ver` and the commented-out `print` call. * Don't add math functions to `__all__`. Beginners should learn to `import math` to access them. * Gregor Lindel, who wrote this version of turtle, dropped plans to implement turtle on another toolkit at least a decade ago. Drop `_dot` code preparing for this, but add a hint comment. * `_Screen` is meant to be a singleton class. To enforce that, it needs either a `__new__` that returns the singleton or `else...raise` in `__iter__`. Merely removing the `if` clauses as suggested might break something if a user were to call `_Screen` directly. Leave the code alone until a problem is evident. * Turtledemo injects into _Screen both _root and _canvas, configured as it needs them to be. Making _canvas an `__init__` option would require skipping some but not all of the lines under 'if _Screen._canvas is None:`. Leave working code alone. files: A Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst M Lib/turtle.py diff --git a/Lib/turtle.py b/Lib/turtle.py index 2de406e0f517..cf111158b7c1 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -21,7 +21,6 @@ # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. - """ Turtle graphics is a popular way for introducing programming to kids. It was part of the original Logo programming language developed @@ -97,13 +96,8 @@ Behind the scenes there are some features included with possible extensions in mind. These will be commented and documented elsewhere. - """ -_ver = "turtle 1.1b- - for Python 3.1 - 4. 5. 2009" - -# print(_ver) - import tkinter as TK import types import math @@ -141,7 +135,7 @@ _tg_utilities = ['write_docstringdict', 'done'] __all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions + - _tg_utilities + ['Terminator']) # + _math_functions) + _tg_utilities + ['Terminator']) _alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos', 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st', @@ -598,9 +592,6 @@ def _write(self, pos, txt, align, font, pencolor): x0, y0, x1, y1 = self.cv.bbox(item) return item, x1-1 -## def _dot(self, pos, size, color): -## """may be implemented for some other graphics toolkit""" - def _onclick(self, item, fun, num=1, add=None): """Bind fun to mouse-click event on turtle. fun must be a function with two arguments, the coordinates @@ -2726,7 +2717,7 @@ def _cc(self, args): if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)): raise TurtleGraphicsError("bad color sequence: %s" % str(args)) return "#%02x%02x%02x" % (r, g, b) - + def teleport(self, x=None, y=None, *, fill_gap: bool = False) -> None: """Instantly move turtle to an absolute position. @@ -2738,14 +2729,14 @@ def teleport(self, x=None, y=None, *, fill_gap: bool = False) -> None: call: teleport(x, y) # two coordinates --or: teleport(x) # teleport to x position, keeping y as is --or: teleport(y=y) # teleport to y position, keeping x as is - --or: teleport(x, y, fill_gap=True) + --or: teleport(x, y, fill_gap=True) # teleport but fill the gap in between Move turtle to an absolute position. Unlike goto(x, y), a line will not be drawn. The turtle's orientation does not change. If currently filling, the polygon(s) teleported from will be filled after leaving, and filling will begin again after teleporting. This can be disabled - with fill_gap=True, which makes the imaginary line traveled during + with fill_gap=True, which makes the imaginary line traveled during teleporting act as a fill barrier like in goto(x, y). Example (for a Turtle instance named turtle): @@ -2773,7 +2764,7 @@ def teleport(self, x=None, y=None, *, fill_gap: bool = False) -> None: self._position = Vec2D(new_x, new_y) self.pen(pendown=pendown) if was_filling and not fill_gap: - self.begin_fill() + self.begin_fill() def clone(self): """Create and return a clone of the turtle. @@ -3455,27 +3446,22 @@ def dot(self, size=None, *color): if size is None: size = self._pensize + max(self._pensize, 4) color = self._colorstr(color) - if hasattr(self.screen, "_dot"): - item = self.screen._dot(self._position, size, color) - self.items.append(item) - if self.undobuffer: - self.undobuffer.push(("dot", item)) - else: - pen = self.pen() - if self.undobuffer: - self.undobuffer.push(["seq"]) - self.undobuffer.cumulate = True - try: - if self.resizemode() == 'auto': - self.ht() - self.pendown() - self.pensize(size) - self.pencolor(color) - self.forward(0) - finally: - self.pen(pen) - if self.undobuffer: - self.undobuffer.cumulate = False + # If screen were to gain a dot function, see GH #104218. + pen = self.pen() + if self.undobuffer: + self.undobuffer.push(["seq"]) + self.undobuffer.cumulate = True + try: + if self.resizemode() == 'auto': + self.ht() + self.pendown() + self.pensize(size) + self.pencolor(color) + self.forward(0) + finally: + self.pen(pen) + if self.undobuffer: + self.undobuffer.cumulate = False def _write(self, txt, align, font): """Performs the writing for write() @@ -3751,11 +3737,6 @@ class _Screen(TurtleScreen): _title = _CFG["title"] def __init__(self): - # XXX there is no need for this code to be conditional, - # as there will be only a single _Screen instance, anyway - # XXX actually, the turtle demo is injecting root window, - # so perhaps the conditional creation of a root should be - # preserved (perhaps by passing it as an optional parameter) if _Screen._root is None: _Screen._root = self._root = _Root() self._root.title(_Screen._title) diff --git a/Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst b/Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst new file mode 100644 index 000000000000..54b019019286 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst @@ -0,0 +1 @@ +Remove unneeded comments and code in turtle.py. From webhook-mailer at python.org Sat May 6 11:09:15 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 06 May 2023 15:09:15 -0000 Subject: [Python-checkins] Rewrite the turtledemo makeGraphFrame method (#104224) Message-ID: <mailman.201.1683385756.13550.python-checkins@python.org> https://github.com/python/cpython/commit/96f95df48e41ccf984de1ee1312c81809fd9e876 commit: 96f95df48e41ccf984de1ee1312c81809fd9e876 branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-06T11:09:08-04:00 summary: Rewrite the turtledemo makeGraphFrame method (#104224) Replace `self._canvas` and `self.scanvas`, both bound to `canvas`, with `self.canvas, which is accessed in other methods. Replace `_s_` with `screen` and `_s_._canvas` with `canvas`. Add a comment explaining the unorthodox use of function turtle.Screen and singleton class turtle._Screen. files: M Lib/turtledemo/__main__.py diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py index caea022da4a6..f6c9d6aa6f9a 100755 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -203,10 +203,10 @@ def __init__(self, filename=None): def onResize(self, event): - cwidth = self._canvas.winfo_width() - cheight = self._canvas.winfo_height() - self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) - self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight) + cwidth = self.canvas.winfo_width() + cheight = self.canvas.winfo_height() + self.canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) + self.canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight) def makeTextFrame(self, root): self.text_frame = text_frame = Frame(root) @@ -237,19 +237,23 @@ def makeTextFrame(self, root): return text_frame def makeGraphFrame(self, root): + # t._Screen is a singleton class instantiated or retrieved + # by calling Screen. Since tdemo canvas needs a different + # configuration, we manually set class attributes before + # calling Screen and manually call superclass init after. turtle._Screen._root = root + self.canvwidth = 1000 self.canvheight = 800 - turtle._Screen._canvas = self._canvas = canvas = turtle.ScrolledCanvas( + turtle._Screen._canvas = self.canvas = canvas = turtle.ScrolledCanvas( root, 800, 600, self.canvwidth, self.canvheight) canvas.adjustScrolls() canvas._rootwindow.bind('<Configure>', self.onResize) canvas._canvas['borderwidth'] = 0 - self.screen = _s_ = turtle.Screen() - turtle.TurtleScreen.__init__(_s_, _s_._canvas) - self.scanvas = _s_._canvas - turtle.RawTurtle.screens = [_s_] + self.screen = screen = turtle.Screen() + turtle.TurtleScreen.__init__(screen, canvas) + turtle.RawTurtle.screens = [screen] return canvas def set_txtsize(self, size): @@ -373,7 +377,7 @@ def startDemo(self): def clearCanvas(self): self.refreshCanvas() self.screen._delete("all") - self.scanvas.config(cursor="") + self.canvas.config(cursor="") self.configGUI(NORMAL, DISABLED, DISABLED) def stopIt(self): From webhook-mailer at python.org Sat May 6 11:15:34 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 06 May 2023 15:15:34 -0000 Subject: [Python-checkins] gh-104144: Optimize gather to finish eagerly when all futures complete eagerly (#104138) Message-ID: <mailman.202.1683386135.13550.python-checkins@python.org> https://github.com/python/cpython/commit/263abd333d18b8825cf6d68a5051818826dbffce commit: 263abd333d18b8825cf6d68a5051818826dbffce branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-06T15:15:27Z summary: gh-104144: Optimize gather to finish eagerly when all futures complete eagerly (#104138) files: A Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst M Lib/asyncio/tasks.py diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index aa5269ade19a..7eb647bd1298 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -813,6 +813,7 @@ def _done_callback(fut): children = [] nfuts = 0 nfinished = 0 + done_futs = [] loop = None outer = None # bpo-46672 for arg in coros_or_futures: @@ -829,7 +830,10 @@ def _done_callback(fut): nfuts += 1 arg_to_fut[arg] = fut - fut.add_done_callback(_done_callback) + if fut.done(): + done_futs.append(fut) + else: + fut.add_done_callback(_done_callback) else: # There's a duplicate Future object in coros_or_futures. @@ -838,6 +842,13 @@ def _done_callback(fut): children.append(fut) outer = _GatheringFuture(children, loop=loop) + # Run done callbacks after GatheringFuture created so any post-processing + # can be performed at this point + # optimization: in the special case that *all* futures finished eagerly, + # this will effectively complete the gather eagerly, with the last + # callback setting the result (or exception) on outer before returning it + for fut in done_futs: + _done_callback(fut) return outer diff --git a/Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst b/Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst new file mode 100644 index 000000000000..b975d48ed338 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst @@ -0,0 +1,3 @@ +Optimize :func:`asyncio.gather` when using :func:`asyncio.eager_task_factory` +to complete eagerly if all fututres completed eagerly. +Avoid scheduling done callbacks for futures that complete eagerly. From webhook-mailer at python.org Sat May 6 11:31:35 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 06 May 2023 15:31:35 -0000 Subject: [Python-checkins] [3.11] Rewrite the turtledemo makeGraphFrame method (GH-104224) (#104238) Message-ID: <mailman.203.1683387095.13550.python-checkins@python.org> https://github.com/python/cpython/commit/10ee19b7371e333f1e22c9471b61954485f2268c commit: 10ee19b7371e333f1e22c9471b61954485f2268c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-06T15:31:28Z summary: [3.11] Rewrite the turtledemo makeGraphFrame method (GH-104224) (#104238) Rewrite the turtledemo makeGraphFrame method (GH-104224) Replace `self._canvas` and `self.scanvas`, both bound to `canvas`, with `self.canvas, which is accessed in other methods. Replace `_s_` with `screen` and `_s_._canvas` with `canvas`. Add a comment explaining the unorthodox use of function turtle.Screen and singleton class turtle._Screen. (cherry picked from commit 96f95df48e41ccf984de1ee1312c81809fd9e876) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: M Lib/turtledemo/__main__.py diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py index caea022da4a6..f6c9d6aa6f9a 100755 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -203,10 +203,10 @@ def __init__(self, filename=None): def onResize(self, event): - cwidth = self._canvas.winfo_width() - cheight = self._canvas.winfo_height() - self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) - self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight) + cwidth = self.canvas.winfo_width() + cheight = self.canvas.winfo_height() + self.canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth) + self.canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight) def makeTextFrame(self, root): self.text_frame = text_frame = Frame(root) @@ -237,19 +237,23 @@ def makeTextFrame(self, root): return text_frame def makeGraphFrame(self, root): + # t._Screen is a singleton class instantiated or retrieved + # by calling Screen. Since tdemo canvas needs a different + # configuration, we manually set class attributes before + # calling Screen and manually call superclass init after. turtle._Screen._root = root + self.canvwidth = 1000 self.canvheight = 800 - turtle._Screen._canvas = self._canvas = canvas = turtle.ScrolledCanvas( + turtle._Screen._canvas = self.canvas = canvas = turtle.ScrolledCanvas( root, 800, 600, self.canvwidth, self.canvheight) canvas.adjustScrolls() canvas._rootwindow.bind('<Configure>', self.onResize) canvas._canvas['borderwidth'] = 0 - self.screen = _s_ = turtle.Screen() - turtle.TurtleScreen.__init__(_s_, _s_._canvas) - self.scanvas = _s_._canvas - turtle.RawTurtle.screens = [_s_] + self.screen = screen = turtle.Screen() + turtle.TurtleScreen.__init__(screen, canvas) + turtle.RawTurtle.screens = [screen] return canvas def set_txtsize(self, size): @@ -373,7 +377,7 @@ def startDemo(self): def clearCanvas(self): self.refreshCanvas() self.screen._delete("all") - self.scanvas.config(cursor="") + self.canvas.config(cursor="") self.configGUI(NORMAL, DISABLED, DISABLED) def stopIt(self): From webhook-mailer at python.org Sat May 6 12:48:13 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 06 May 2023 16:48:13 -0000 Subject: [Python-checkins] gh-90953: Emit deprecation warnings for `ast` features deprecated in Python 3.8 (#104199) Message-ID: <mailman.204.1683391694.13550.python-checkins@python.org> https://github.com/python/cpython/commit/376137f6ec73e0800e49cec6100e401f6154b693 commit: 376137f6ec73e0800e49cec6100e401f6154b693 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-06T16:48:07Z summary: gh-90953: Emit deprecation warnings for `ast` features deprecated in Python 3.8 (#104199) `ast.Num`, `ast.Str`, `ast.Bytes`, `ast.Ellipsis` and `ast.NameConstant` now all emit deprecation warnings on import, access, instantation or `isinstance()` checks. Co-authored-by: Serhiy Storchaka <storchaka at gmail.com> files: A Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst M Doc/whatsnew/3.12.rst M Lib/ast.py M Lib/test/test_ast.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ccddc8bd832f..ec04178238b6 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -844,6 +844,19 @@ Pending Removal in Python 3.14 use :func:`importlib.util.find_spec` instead. (Contributed by Nikita Sobolev in :gh:`97850`.) +* The following :mod:`ast` features have been deprecated in documentation since + Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at runtime + when they are accessed or used, and will be removed in Python 3.14: + + * :class:`!ast.Num` + * :class:`!ast.Str` + * :class:`!ast.Bytes` + * :class:`!ast.NameConstant` + * :class:`!ast.Ellipsis` + + Use :class:`ast.Constant` instead. + (Contributed by Serhiy Storchaka in :gh:`90953`.) + Pending Removal in Future Versions ---------------------------------- diff --git a/Lib/ast.py b/Lib/ast.py index d9733a79d3a7..65152047a223 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -294,9 +294,7 @@ def get_docstring(node, clean=True): if not(node.body and isinstance(node.body[0], Expr)): return None node = node.body[0].value - if isinstance(node, Str): - text = node.s - elif isinstance(node, Constant) and isinstance(node.value, str): + if isinstance(node, Constant) and isinstance(node.value, str): text = node.value else: return None @@ -499,20 +497,52 @@ def generic_visit(self, node): return node +_DEPRECATED_VALUE_ALIAS_MESSAGE = ( + "{name} is deprecated and will be removed in Python {remove}; use value instead" +) +_DEPRECATED_CLASS_MESSAGE = ( + "{name} is deprecated and will be removed in Python {remove}; " + "use ast.Constant instead" +) + + # If the ast module is loaded more than once, only add deprecated methods once if not hasattr(Constant, 'n'): # The following code is for backward compatibility. # It will be removed in future. - def _getter(self): + def _n_getter(self): + """Deprecated. Use value instead.""" + import warnings + warnings._deprecated( + "Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14) + ) + return self.value + + def _n_setter(self, value): + import warnings + warnings._deprecated( + "Attribute n", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14) + ) + self.value = value + + def _s_getter(self): """Deprecated. Use value instead.""" + import warnings + warnings._deprecated( + "Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14) + ) return self.value - def _setter(self, value): + def _s_setter(self, value): + import warnings + warnings._deprecated( + "Attribute s", message=_DEPRECATED_VALUE_ALIAS_MESSAGE, remove=(3, 14) + ) self.value = value - Constant.n = property(_getter, _setter) - Constant.s = property(_getter, _setter) + Constant.n = property(_n_getter, _n_setter) + Constant.s = property(_s_getter, _s_setter) class _ABC(type): @@ -520,6 +550,13 @@ def __init__(cls, *args): cls.__doc__ = """Deprecated AST node class. Use ast.Constant instead""" def __instancecheck__(cls, inst): + if cls in _const_types: + import warnings + warnings._deprecated( + f"ast.{cls.__qualname__}", + message=_DEPRECATED_CLASS_MESSAGE, + remove=(3, 14) + ) if not isinstance(inst, Constant): return False if cls in _const_types: @@ -543,6 +580,10 @@ def _new(cls, *args, **kwargs): if pos < len(args): raise TypeError(f"{cls.__name__} got multiple values for argument {key!r}") if cls in _const_types: + import warnings + warnings._deprecated( + f"ast.{cls.__qualname__}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14) + ) return Constant(*args, **kwargs) return Constant.__new__(cls, *args, **kwargs) @@ -565,10 +606,19 @@ class Ellipsis(Constant, metaclass=_ABC): _fields = () def __new__(cls, *args, **kwargs): - if cls is Ellipsis: + if cls is _ast_Ellipsis: + import warnings + warnings._deprecated( + "ast.Ellipsis", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14) + ) return Constant(..., *args, **kwargs) return Constant.__new__(cls, *args, **kwargs) +# Keep another reference to Ellipsis in the global namespace +# so it can be referenced in Ellipsis.__new__ +# (The original "Ellipsis" name is removed from the global namespace later on) +_ast_Ellipsis = Ellipsis + _const_types = { Num: (int, float, complex), Str: (str,), @@ -1699,6 +1749,22 @@ def unparse(ast_obj): return unparser.visit(ast_obj) +_deprecated_globals = { + name: globals().pop(name) + for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis') +} + +def __getattr__(name): + if name in _deprecated_globals: + globals()[name] = value = _deprecated_globals[name] + import warnings + warnings._deprecated( + f"ast.{name}", message=_DEPRECATED_CLASS_MESSAGE, remove=(3, 14) + ) + return value + raise AttributeError(f"module 'ast' has no attribute '{name}'") + + def main(): import argparse diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 8eef7baec701..fdd21aca06ff 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -8,9 +8,11 @@ import unittest import warnings import weakref +from functools import partial from textwrap import dedent from test import support +from test.support.import_helper import import_fresh_module from test.support import os_helper, script_helper from test.support.ast_helper import ASTTestMixin @@ -267,6 +269,7 @@ def to_tuple(t): # excepthandler, arguments, keywords, alias class AST_Tests(unittest.TestCase): + maxDiff = None def _is_ast_node(self, name, node): if not isinstance(node, type): @@ -435,16 +438,42 @@ def test_base_classes(self): self.assertTrue(issubclass(ast.comprehension, ast.AST)) self.assertTrue(issubclass(ast.Gt, ast.AST)) + def test_import_deprecated(self): + ast = import_fresh_module('ast') + depr_regex = ( + r'ast\.{} is deprecated and will be removed in Python 3.14; ' + r'use ast\.Constant instead' + ) + for name in 'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis': + with self.assertWarnsRegex(DeprecationWarning, depr_regex.format(name)): + getattr(ast, name) + + def test_field_attr_existence_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + for name in ('Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'): + item = getattr(ast, name) + if self._is_ast_node(name, item): + with self.subTest(item): + with self.assertWarns(DeprecationWarning): + x = item() + if isinstance(x, ast.AST): + self.assertIs(type(x._fields), tuple) + def test_field_attr_existence(self): for name, item in ast.__dict__.items(): + # These emit DeprecationWarnings + if name in {'Num', 'Str', 'Bytes', 'NameConstant', 'Ellipsis'}: + continue + # constructor has a different signature + if name == 'Index': + continue if self._is_ast_node(name, item): - if name == 'Index': - # Index(value) just returns value now. - # The argument is required. - continue x = item() if isinstance(x, ast.AST): - self.assertEqual(type(x._fields), tuple) + self.assertIs(type(x._fields), tuple) def test_arguments(self): x = ast.arguments() @@ -459,25 +488,108 @@ def test_arguments(self): self.assertEqual(x.args, 2) self.assertEqual(x.vararg, 3) + def test_field_attr_writable_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + x = ast.Num() + # We can assign to _fields + x._fields = 666 + self.assertEqual(x._fields, 666) + def test_field_attr_writable(self): - x = ast.Num() + x = ast.Constant() # We can assign to _fields x._fields = 666 self.assertEqual(x._fields, 666) + def test_classattrs_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('always', '', DeprecationWarning) + x = ast.Num() + self.assertEqual(x._fields, ('value', 'kind')) + + with self.assertRaises(AttributeError): + x.value + + with self.assertRaises(AttributeError): + x.n + + x = ast.Num(42) + self.assertEqual(x.value, 42) + self.assertEqual(x.n, 42) + + with self.assertRaises(AttributeError): + x.lineno + + with self.assertRaises(AttributeError): + x.foobar + + x = ast.Num(lineno=2) + self.assertEqual(x.lineno, 2) + + x = ast.Num(42, lineno=0) + self.assertEqual(x.lineno, 0) + self.assertEqual(x._fields, ('value', 'kind')) + self.assertEqual(x.value, 42) + self.assertEqual(x.n, 42) + + self.assertRaises(TypeError, ast.Num, 1, None, 2) + self.assertRaises(TypeError, ast.Num, 1, None, 2, lineno=0) + + # Arbitrary keyword arguments are supported + self.assertEqual(ast.Num(1, foo='bar').foo, 'bar') + + with self.assertRaisesRegex(TypeError, "Num got multiple values for argument 'n'"): + ast.Num(1, n=2) + + self.assertEqual(ast.Num(42).n, 42) + self.assertEqual(ast.Num(4.25).n, 4.25) + self.assertEqual(ast.Num(4.25j).n, 4.25j) + self.assertEqual(ast.Str('42').s, '42') + self.assertEqual(ast.Bytes(b'42').s, b'42') + self.assertIs(ast.NameConstant(True).value, True) + self.assertIs(ast.NameConstant(False).value, False) + self.assertIs(ast.NameConstant(None).value, None) + + self.assertEqual([str(w.message) for w in wlog], [ + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + ]) + def test_classattrs(self): - x = ast.Num() + x = ast.Constant() self.assertEqual(x._fields, ('value', 'kind')) with self.assertRaises(AttributeError): x.value - with self.assertRaises(AttributeError): - x.n - - x = ast.Num(42) + x = ast.Constant(42) self.assertEqual(x.value, 42) - self.assertEqual(x.n, 42) with self.assertRaises(AttributeError): x.lineno @@ -485,36 +597,23 @@ def test_classattrs(self): with self.assertRaises(AttributeError): x.foobar - x = ast.Num(lineno=2) + x = ast.Constant(lineno=2) self.assertEqual(x.lineno, 2) - x = ast.Num(42, lineno=0) + x = ast.Constant(42, lineno=0) self.assertEqual(x.lineno, 0) self.assertEqual(x._fields, ('value', 'kind')) self.assertEqual(x.value, 42) - self.assertEqual(x.n, 42) - self.assertRaises(TypeError, ast.Num, 1, None, 2) - self.assertRaises(TypeError, ast.Num, 1, None, 2, lineno=0) + self.assertRaises(TypeError, ast.Constant, 1, None, 2) + self.assertRaises(TypeError, ast.Constant, 1, None, 2, lineno=0) # Arbitrary keyword arguments are supported self.assertEqual(ast.Constant(1, foo='bar').foo, 'bar') - self.assertEqual(ast.Num(1, foo='bar').foo, 'bar') - with self.assertRaisesRegex(TypeError, "Num got multiple values for argument 'n'"): - ast.Num(1, n=2) with self.assertRaisesRegex(TypeError, "Constant got multiple values for argument 'value'"): ast.Constant(1, value=2) - self.assertEqual(ast.Num(42).n, 42) - self.assertEqual(ast.Num(4.25).n, 4.25) - self.assertEqual(ast.Num(4.25j).n, 4.25j) - self.assertEqual(ast.Str('42').s, '42') - self.assertEqual(ast.Bytes(b'42').s, b'42') - self.assertIs(ast.NameConstant(True).value, True) - self.assertIs(ast.NameConstant(False).value, False) - self.assertIs(ast.NameConstant(None).value, None) - self.assertEqual(ast.Constant(42).value, 42) self.assertEqual(ast.Constant(4.25).value, 4.25) self.assertEqual(ast.Constant(4.25j).value, 4.25j) @@ -526,85 +625,211 @@ def test_classattrs(self): self.assertIs(ast.Constant(...).value, ...) def test_realtype(self): - self.assertEqual(type(ast.Num(42)), ast.Constant) - self.assertEqual(type(ast.Num(4.25)), ast.Constant) - self.assertEqual(type(ast.Num(4.25j)), ast.Constant) - self.assertEqual(type(ast.Str('42')), ast.Constant) - self.assertEqual(type(ast.Bytes(b'42')), ast.Constant) - self.assertEqual(type(ast.NameConstant(True)), ast.Constant) - self.assertEqual(type(ast.NameConstant(False)), ast.Constant) - self.assertEqual(type(ast.NameConstant(None)), ast.Constant) - self.assertEqual(type(ast.Ellipsis()), ast.Constant) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('always', '', DeprecationWarning) + self.assertIs(type(ast.Num(42)), ast.Constant) + self.assertIs(type(ast.Num(4.25)), ast.Constant) + self.assertIs(type(ast.Num(4.25j)), ast.Constant) + self.assertIs(type(ast.Str('42')), ast.Constant) + self.assertIs(type(ast.Bytes(b'42')), ast.Constant) + self.assertIs(type(ast.NameConstant(True)), ast.Constant) + self.assertIs(type(ast.NameConstant(False)), ast.Constant) + self.assertIs(type(ast.NameConstant(None)), ast.Constant) + self.assertIs(type(ast.Ellipsis()), ast.Constant) + + self.assertEqual([str(w.message) for w in wlog], [ + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Bytes is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Ellipsis is deprecated and will be removed in Python 3.14; use ast.Constant instead', + ]) def test_isinstance(self): - self.assertTrue(isinstance(ast.Num(42), ast.Num)) - self.assertTrue(isinstance(ast.Num(4.2), ast.Num)) - self.assertTrue(isinstance(ast.Num(4.2j), ast.Num)) - self.assertTrue(isinstance(ast.Str('42'), ast.Str)) - self.assertTrue(isinstance(ast.Bytes(b'42'), ast.Bytes)) - self.assertTrue(isinstance(ast.NameConstant(True), ast.NameConstant)) - self.assertTrue(isinstance(ast.NameConstant(False), ast.NameConstant)) - self.assertTrue(isinstance(ast.NameConstant(None), ast.NameConstant)) - self.assertTrue(isinstance(ast.Ellipsis(), ast.Ellipsis)) - - self.assertTrue(isinstance(ast.Constant(42), ast.Num)) - self.assertTrue(isinstance(ast.Constant(4.2), ast.Num)) - self.assertTrue(isinstance(ast.Constant(4.2j), ast.Num)) - self.assertTrue(isinstance(ast.Constant('42'), ast.Str)) - self.assertTrue(isinstance(ast.Constant(b'42'), ast.Bytes)) - self.assertTrue(isinstance(ast.Constant(True), ast.NameConstant)) - self.assertTrue(isinstance(ast.Constant(False), ast.NameConstant)) - self.assertTrue(isinstance(ast.Constant(None), ast.NameConstant)) - self.assertTrue(isinstance(ast.Constant(...), ast.Ellipsis)) - - self.assertFalse(isinstance(ast.Str('42'), ast.Num)) - self.assertFalse(isinstance(ast.Num(42), ast.Str)) - self.assertFalse(isinstance(ast.Str('42'), ast.Bytes)) - self.assertFalse(isinstance(ast.Num(42), ast.NameConstant)) - self.assertFalse(isinstance(ast.Num(42), ast.Ellipsis)) - self.assertFalse(isinstance(ast.NameConstant(True), ast.Num)) - self.assertFalse(isinstance(ast.NameConstant(False), ast.Num)) - - self.assertFalse(isinstance(ast.Constant('42'), ast.Num)) - self.assertFalse(isinstance(ast.Constant(42), ast.Str)) - self.assertFalse(isinstance(ast.Constant('42'), ast.Bytes)) - self.assertFalse(isinstance(ast.Constant(42), ast.NameConstant)) - self.assertFalse(isinstance(ast.Constant(42), ast.Ellipsis)) - self.assertFalse(isinstance(ast.Constant(True), ast.Num)) - self.assertFalse(isinstance(ast.Constant(False), ast.Num)) - - self.assertFalse(isinstance(ast.Constant(), ast.Num)) - self.assertFalse(isinstance(ast.Constant(), ast.Str)) - self.assertFalse(isinstance(ast.Constant(), ast.Bytes)) - self.assertFalse(isinstance(ast.Constant(), ast.NameConstant)) - self.assertFalse(isinstance(ast.Constant(), ast.Ellipsis)) + from ast import Constant + + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import Num, Str, Bytes, NameConstant, Ellipsis + + cls_depr_msg = ( + 'ast.{} is deprecated and will be removed in Python 3.14; ' + 'use ast.Constant instead' + ) + + assertNumDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Num") + ) + assertStrDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Str") + ) + assertBytesDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Bytes") + ) + assertNameConstantDeprecated = partial( + self.assertWarnsRegex, + DeprecationWarning, + cls_depr_msg.format("NameConstant") + ) + assertEllipsisDeprecated = partial( + self.assertWarnsRegex, DeprecationWarning, cls_depr_msg.format("Ellipsis") + ) + + for arg in 42, 4.2, 4.2j: + with self.subTest(arg=arg): + with assertNumDeprecated(): + n = Num(arg) + with assertNumDeprecated(): + self.assertIsInstance(n, Num) + + with assertStrDeprecated(): + s = Str('42') + with assertStrDeprecated(): + self.assertIsInstance(s, Str) + + with assertBytesDeprecated(): + b = Bytes(b'42') + with assertBytesDeprecated(): + self.assertIsInstance(b, Bytes) + + for arg in True, False, None: + with self.subTest(arg=arg): + with assertNameConstantDeprecated(): + n = NameConstant(arg) + with assertNameConstantDeprecated(): + self.assertIsInstance(n, NameConstant) + + with assertEllipsisDeprecated(): + e = Ellipsis() + with assertEllipsisDeprecated(): + self.assertIsInstance(e, Ellipsis) + + for arg in 42, 4.2, 4.2j: + with self.subTest(arg=arg): + with assertNumDeprecated(): + self.assertIsInstance(Constant(arg), Num) + + with assertStrDeprecated(): + self.assertIsInstance(Constant('42'), Str) + + with assertBytesDeprecated(): + self.assertIsInstance(Constant(b'42'), Bytes) + + for arg in True, False, None: + with self.subTest(arg=arg): + with assertNameConstantDeprecated(): + self.assertIsInstance(Constant(arg), NameConstant) + + with assertEllipsisDeprecated(): + self.assertIsInstance(Constant(...), Ellipsis) + + with assertStrDeprecated(): + s = Str('42') + assertNumDeprecated(self.assertNotIsInstance, s, Num) + assertBytesDeprecated(self.assertNotIsInstance, s, Bytes) + + with assertNumDeprecated(): + n = Num(42) + assertStrDeprecated(self.assertNotIsInstance, n, Str) + assertNameConstantDeprecated(self.assertNotIsInstance, n, NameConstant) + assertEllipsisDeprecated(self.assertNotIsInstance, n, Ellipsis) + + with assertNameConstantDeprecated(): + n = NameConstant(True) + with assertNumDeprecated(): + self.assertNotIsInstance(n, Num) + + with assertNameConstantDeprecated(): + n = NameConstant(False) + with assertNumDeprecated(): + self.assertNotIsInstance(n, Num) + + for arg in '42', True, False: + with self.subTest(arg=arg): + with assertNumDeprecated(): + self.assertNotIsInstance(Constant(arg), Num) + + assertStrDeprecated(self.assertNotIsInstance, Constant(42), Str) + assertBytesDeprecated(self.assertNotIsInstance, Constant('42'), Bytes) + assertNameConstantDeprecated(self.assertNotIsInstance, Constant(42), NameConstant) + assertEllipsisDeprecated(self.assertNotIsInstance, Constant(42), Ellipsis) + assertNumDeprecated(self.assertNotIsInstance, Constant(), Num) + assertStrDeprecated(self.assertNotIsInstance, Constant(), Str) + assertBytesDeprecated(self.assertNotIsInstance, Constant(), Bytes) + assertNameConstantDeprecated(self.assertNotIsInstance, Constant(), NameConstant) + assertEllipsisDeprecated(self.assertNotIsInstance, Constant(), Ellipsis) class S(str): pass - self.assertTrue(isinstance(ast.Constant(S('42')), ast.Str)) - self.assertFalse(isinstance(ast.Constant(S('42')), ast.Num)) + with assertStrDeprecated(): + self.assertIsInstance(Constant(S('42')), Str) + with assertNumDeprecated(): + self.assertNotIsInstance(Constant(S('42')), Num) + + def test_constant_subclasses_deprecated(self): + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import Num - def test_subclasses(self): - class N(ast.Num): + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('always', '', DeprecationWarning) + class N(ast.Num): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.z = 'spam' + class N2(ast.Num): + pass + + n = N(42) + self.assertEqual(n.n, 42) + self.assertEqual(n.z, 'spam') + self.assertIs(type(n), N) + self.assertIsInstance(n, N) + self.assertIsInstance(n, ast.Num) + self.assertNotIsInstance(n, N2) + self.assertNotIsInstance(ast.Num(42), N) + n = N(n=42) + self.assertEqual(n.n, 42) + self.assertIs(type(n), N) + + self.assertEqual([str(w.message) for w in wlog], [ + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', + ]) + + def test_constant_subclasses(self): + class N(ast.Constant): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.z = 'spam' - class N2(ast.Num): + class N2(ast.Constant): pass n = N(42) - self.assertEqual(n.n, 42) + self.assertEqual(n.value, 42) self.assertEqual(n.z, 'spam') self.assertEqual(type(n), N) self.assertTrue(isinstance(n, N)) - self.assertTrue(isinstance(n, ast.Num)) + self.assertTrue(isinstance(n, ast.Constant)) self.assertFalse(isinstance(n, N2)) - self.assertFalse(isinstance(ast.Num(42), N)) - n = N(n=42) - self.assertEqual(n.n, 42) + self.assertFalse(isinstance(ast.Constant(42), N)) + n = N(value=42) + self.assertEqual(n.value, 42) self.assertEqual(type(n), N) def test_module(self): - body = [ast.Num(42)] + body = [ast.Constant(42)] x = ast.Module(body, []) self.assertEqual(x.body, body) @@ -617,8 +842,8 @@ def test_nodeclasses(self): x.foobarbaz = 5 self.assertEqual(x.foobarbaz, 5) - n1 = ast.Num(1) - n3 = ast.Num(3) + n1 = ast.Constant(1) + n3 = ast.Constant(3) addop = ast.Add() x = ast.BinOp(n1, addop, n3) self.assertEqual(x.left, n1) @@ -987,7 +1212,7 @@ def test_dump_incomplete(self): def test_copy_location(self): src = ast.parse('1 + 1', mode='eval') - src.body.right = ast.copy_location(ast.Num(2), src.body.right) + src.body.right = ast.copy_location(ast.Constant(2), src.body.right) self.assertEqual(ast.dump(src, include_attributes=True), 'Expression(body=BinOp(left=Constant(value=1, lineno=1, col_offset=0, ' 'end_lineno=1, end_col_offset=1), op=Add(), right=Constant(value=2, ' @@ -1004,7 +1229,7 @@ def test_copy_location(self): def test_fix_missing_locations(self): src = ast.parse('write("spam")') src.body.append(ast.Expr(ast.Call(ast.Name('spam', ast.Load()), - [ast.Str('eggs')], []))) + [ast.Constant('eggs')], []))) self.assertEqual(src, ast.fix_missing_locations(src)) self.maxDiff = None self.assertEqual(ast.dump(src, include_attributes=True), @@ -1317,9 +1542,9 @@ def arguments(args=None, posonlyargs=None, vararg=None, check(arguments(args=args), "must have Load context") check(arguments(posonlyargs=args), "must have Load context") check(arguments(kwonlyargs=args), "must have Load context") - check(arguments(defaults=[ast.Num(3)]), + check(arguments(defaults=[ast.Constant(3)]), "more positional defaults than args") - check(arguments(kw_defaults=[ast.Num(4)]), + check(arguments(kw_defaults=[ast.Constant(4)]), "length of kwonlyargs is not the same as kw_defaults") args = [ast.arg("x", ast.Name("x", ast.Load()))] check(arguments(args=args, defaults=[ast.Name("x", ast.Store())]), @@ -1372,9 +1597,9 @@ def test_delete(self): "must have Del context") def test_assign(self): - self.stmt(ast.Assign([], ast.Num(3)), "empty targets on Assign") - self.stmt(ast.Assign([None], ast.Num(3)), "None disallowed") - self.stmt(ast.Assign([ast.Name("x", ast.Load())], ast.Num(3)), + self.stmt(ast.Assign([], ast.Constant(3)), "empty targets on Assign") + self.stmt(ast.Assign([None], ast.Constant(3)), "None disallowed") + self.stmt(ast.Assign([ast.Name("x", ast.Load())], ast.Constant(3)), "must have Store context") self.stmt(ast.Assign([ast.Name("x", ast.Store())], ast.Name("y", ast.Store())), @@ -1402,39 +1627,39 @@ def test_for(self): self.stmt(ast.For(x, y, [p], [e]), "must have Load context") def test_while(self): - self.stmt(ast.While(ast.Num(3), [], []), "empty body on While") + self.stmt(ast.While(ast.Constant(3), [], []), "empty body on While") self.stmt(ast.While(ast.Name("x", ast.Store()), [ast.Pass()], []), "must have Load context") - self.stmt(ast.While(ast.Num(3), [ast.Pass()], + self.stmt(ast.While(ast.Constant(3), [ast.Pass()], [ast.Expr(ast.Name("x", ast.Store()))]), "must have Load context") def test_if(self): - self.stmt(ast.If(ast.Num(3), [], []), "empty body on If") + self.stmt(ast.If(ast.Constant(3), [], []), "empty body on If") i = ast.If(ast.Name("x", ast.Store()), [ast.Pass()], []) self.stmt(i, "must have Load context") - i = ast.If(ast.Num(3), [ast.Expr(ast.Name("x", ast.Store()))], []) + i = ast.If(ast.Constant(3), [ast.Expr(ast.Name("x", ast.Store()))], []) self.stmt(i, "must have Load context") - i = ast.If(ast.Num(3), [ast.Pass()], + i = ast.If(ast.Constant(3), [ast.Pass()], [ast.Expr(ast.Name("x", ast.Store()))]) self.stmt(i, "must have Load context") def test_with(self): p = ast.Pass() self.stmt(ast.With([], [p]), "empty items on With") - i = ast.withitem(ast.Num(3), None) + i = ast.withitem(ast.Constant(3), None) self.stmt(ast.With([i], []), "empty body on With") i = ast.withitem(ast.Name("x", ast.Store()), None) self.stmt(ast.With([i], [p]), "must have Load context") - i = ast.withitem(ast.Num(3), ast.Name("x", ast.Load())) + i = ast.withitem(ast.Constant(3), ast.Name("x", ast.Load())) self.stmt(ast.With([i], [p]), "must have Store context") def test_raise(self): - r = ast.Raise(None, ast.Num(3)) + r = ast.Raise(None, ast.Constant(3)) self.stmt(r, "Raise with cause but no exception") r = ast.Raise(ast.Name("x", ast.Store()), None) self.stmt(r, "must have Load context") - r = ast.Raise(ast.Num(4), ast.Name("x", ast.Store())) + r = ast.Raise(ast.Constant(4), ast.Name("x", ast.Store())) self.stmt(r, "must have Load context") def test_try(self): @@ -1505,11 +1730,11 @@ def test_expr(self): def test_boolop(self): b = ast.BoolOp(ast.And(), []) self.expr(b, "less than 2 values") - b = ast.BoolOp(ast.And(), [ast.Num(3)]) + b = ast.BoolOp(ast.And(), [ast.Constant(3)]) self.expr(b, "less than 2 values") - b = ast.BoolOp(ast.And(), [ast.Num(4), None]) + b = ast.BoolOp(ast.And(), [ast.Constant(4), None]) self.expr(b, "None disallowed") - b = ast.BoolOp(ast.And(), [ast.Num(4), ast.Name("x", ast.Store())]) + b = ast.BoolOp(ast.And(), [ast.Constant(4), ast.Name("x", ast.Store())]) self.expr(b, "must have Load context") def test_unaryop(self): @@ -1597,11 +1822,11 @@ def test_compare(self): left = ast.Name("x", ast.Load()) comp = ast.Compare(left, [ast.In()], []) self.expr(comp, "no comparators") - comp = ast.Compare(left, [ast.In()], [ast.Num(4), ast.Num(5)]) + comp = ast.Compare(left, [ast.In()], [ast.Constant(4), ast.Constant(5)]) self.expr(comp, "different number of comparators and operands") - comp = ast.Compare(ast.Num("blah"), [ast.In()], [left]) + comp = ast.Compare(ast.Constant("blah"), [ast.In()], [left]) self.expr(comp) - comp = ast.Compare(left, [ast.In()], [ast.Num("blah")]) + comp = ast.Compare(left, [ast.In()], [ast.Constant("blah")]) self.expr(comp) def test_call(self): @@ -1617,23 +1842,37 @@ def test_call(self): self.expr(call, "must have Load context") def test_num(self): - class subint(int): - pass - class subfloat(float): - pass - class subcomplex(complex): - pass - for obj in "0", "hello": - self.expr(ast.Num(obj)) - for obj in subint(), subfloat(), subcomplex(): - self.expr(ast.Num(obj), "invalid type", exc=TypeError) + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import Num + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('always', '', DeprecationWarning) + class subint(int): + pass + class subfloat(float): + pass + class subcomplex(complex): + pass + for obj in "0", "hello": + self.expr(ast.Num(obj)) + for obj in subint(), subfloat(), subcomplex(): + self.expr(ast.Num(obj), "invalid type", exc=TypeError) + + self.assertEqual([str(w.message) for w in wlog], [ + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + 'ast.Num is deprecated and will be removed in Python 3.14; use ast.Constant instead', + ]) def test_attribute(self): attr = ast.Attribute(ast.Name("x", ast.Store()), "y", ast.Load()) self.expr(attr, "must have Load context") def test_subscript(self): - sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Num(3), + sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Constant(3), ast.Load()) self.expr(sub, "must have Load context") x = ast.Name("x", ast.Load()) @@ -1653,7 +1892,7 @@ def test_subscript(self): def test_starred(self): left = ast.List([ast.Starred(ast.Name("x", ast.Load()), ast.Store())], ast.Store()) - assign = ast.Assign([left], ast.Num(4)) + assign = ast.Assign([left], ast.Constant(4)) self.stmt(assign, "must have Store context") def _sequence(self, fac): @@ -1668,7 +1907,17 @@ def test_tuple(self): self._sequence(ast.Tuple) def test_nameconstant(self): - self.expr(ast.NameConstant(4)) + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('ignore', '', DeprecationWarning) + from ast import NameConstant + + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('always', '', DeprecationWarning) + self.expr(ast.NameConstant(4)) + + self.assertEqual([str(w.message) for w in wlog], [ + 'ast.NameConstant is deprecated and will be removed in Python 3.14; use ast.Constant instead', + ]) def test_stdlib_validates(self): stdlib = os.path.dirname(ast.__file__) @@ -2357,10 +2606,15 @@ def visit_Ellipsis(self, node): ]) self.assertEqual([str(w.message) for w in wlog], [ 'visit_Num is deprecated; add visit_Constant', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', 'visit_Num is deprecated; add visit_Constant', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', 'visit_Num is deprecated; add visit_Constant', + 'Attribute n is deprecated and will be removed in Python 3.14; use value instead', 'visit_Str is deprecated; add visit_Constant', + 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', 'visit_Bytes is deprecated; add visit_Constant', + 'Attribute s is deprecated and will be removed in Python 3.14; use value instead', 'visit_NameConstant is deprecated; add visit_Constant', 'visit_NameConstant is deprecated; add visit_Constant', 'visit_Ellipsis is deprecated; add visit_Constant', diff --git a/Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst b/Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst new file mode 100644 index 000000000000..6539efbc9d0e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst @@ -0,0 +1,4 @@ +Deprecation warnings are now emitted for :class:`!ast.Num`, +:class:`!ast.Bytes`, :class:`!ast.Str`, :class:`!ast.NameConstant` and +:class:`!ast.Ellipsis`. These have been documented as deprecated since Python +3.8, and will be removed in Python 3.14. From webhook-mailer at python.org Sat May 6 14:03:21 2023 From: webhook-mailer at python.org (barneygale) Date: Sat, 06 May 2023 18:03:21 -0000 Subject: [Python-checkins] GH-103548: Improve performance of `pathlib.Path.[is_]absolute()` (GH-103549) Message-ID: <mailman.205.1683396202.13550.python-checkins@python.org> https://github.com/python/cpython/commit/de7f694e3c92797fe65f04cd2c6941ed0446bb24 commit: de7f694e3c92797fe65f04cd2c6941ed0446bb24 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-06T18:03:07Z summary: GH-103548: Improve performance of `pathlib.Path.[is_]absolute()` (GH-103549) Improve performance of `pathlib.Path.absolute()` and `cwd()` by joining paths only when necessary. Also improve performance of `PurePath.is_absolute()` on Posix by skipping path parsing and normalization. files: A Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst M Lib/pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 9aa3c1e52447..480c354ce8b6 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -664,7 +664,7 @@ def is_absolute(self): # ntpath.isabs() is defective - see GH-44626 . if self._flavour is ntpath: return bool(self.drive and self.root) - return self._flavour.isabs(self) + return self._flavour.isabs(self._raw_path) def is_reserved(self): """Return True if the path contains one of the special names reserved @@ -873,6 +873,15 @@ def absolute(self): cwd = self._flavour.abspath(self.drive) else: cwd = os.getcwd() + # Fast path for "empty" paths, e.g. Path("."), Path("") or Path(). + # We pass only one argument to with_segments() to avoid the cost + # of joining, and we exploit the fact that getcwd() returns a + # fully-normalized string by storing it in _str. This is used to + # implement Path.cwd(). + if not self.root and not self._tail: + result = self.with_segments(cwd) + result._str = cwd + return result return self.with_segments(cwd, self) def resolve(self, strict=False): diff --git a/Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst b/Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst new file mode 100644 index 000000000000..238f28688674 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst @@ -0,0 +1,4 @@ +Improve performance of :meth:`pathlib.Path.absolute` and +:meth:`~pathlib.Path.cwd` by joining paths only when necessary. Also improve +performance of :meth:`pathlib.PurePath.is_absolute` on Posix by skipping path +parsing and normalization. From webhook-mailer at python.org Sat May 6 16:26:13 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sat, 06 May 2023 20:26:13 -0000 Subject: [Python-checkins] gh-101819: Remove unused 'locale_module' from _io state (#104246) Message-ID: <mailman.206.1683404775.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3b14b51d11ae23a915299a8f9bf650ca2ae90566 commit: 3b14b51d11ae23a915299a8f9bf650ca2ae90566 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-06T20:26:06Z summary: gh-101819: Remove unused 'locale_module' from _io state (#104246) The locale module reference was introduced by 932ff8368 in 2013, and rendered unused by 710e82630 (gh-23050) in 2020. files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 403968af1b99..99b8a8e09ecf 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -580,7 +580,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { _PyIO_State *state = get_io_state(mod); if (!state->initialized) return 0; - Py_VISIT(state->locale_module); Py_VISIT(state->unsupported_operation); Py_VISIT(state->PyIncrementalNewlineDecoder_Type); @@ -605,8 +604,6 @@ iomodule_clear(PyObject *mod) { _PyIO_State *state = get_io_state(mod); if (!state->initialized) return 0; - if (state->locale_module != NULL) - Py_CLEAR(state->locale_module); Py_CLEAR(state->unsupported_operation); Py_CLEAR(state->PyIncrementalNewlineDecoder_Type); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 8a788fbb8185..c971c987cf5f 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -143,8 +143,6 @@ extern PyModuleDef _PyIO_Module; typedef struct { int initialized; - PyObject *locale_module; - PyObject *unsupported_operation; /* Types */ From webhook-mailer at python.org Sat May 6 17:57:42 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Sat, 06 May 2023 21:57:42 -0000 Subject: [Python-checkins] gh-99113: Add a check for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-104206) Message-ID: <mailman.207.1683410264.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fff193bbfebe7b00229856b1e8105ab3de36437f commit: fff193bbfebe7b00229856b1e8105ab3de36437f branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-06T21:57:35Z summary: gh-99113: Add a check for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-104206) Py_MOD_PER_INTERPRETER_GIL_SUPPORTED is a new supported value for Py_mod_multiple_interpreters, added in gh-104205. files: A Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst M Lib/test/test_import/__init__.py M Lib/test/test_importlib/extension/test_loader.py M Modules/_testmultiphase.c M Objects/moduleobject.c diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 773b7094c6b8..e2384a08ecaa 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1861,6 +1861,26 @@ def test_multi_init_extension_non_isolated_compat(self): with self.subTest(f'{modname}: not strict'): self.check_compatible_here(modname, filename, strict=False) + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + def test_multi_init_extension_per_interpreter_gil_compat(self): + modname = '_test_shared_gil_only' + filename = _testmultiphase.__file__ + loader = ExtensionFileLoader(modname, filename) + spec = importlib.util.spec_from_loader(modname, loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + sys.modules[modname] = module + + require_extension(module) + with self.subTest(f'{modname}: isolated, strict'): + self.check_incompatible_here(modname, filename, isolated=True) + with self.subTest(f'{modname}: not isolated, strict'): + self.check_compatible_here(modname, filename, + strict=True, isolated=False) + with self.subTest(f'{modname}: not isolated, not strict'): + self.check_compatible_here(modname, filename, + strict=False, isolated=False) + def test_python_compat(self): module = 'threading' require_pure_python(module) diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 3bf2bbdcdcc4..3a74b821eaee 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -348,6 +348,8 @@ def test_bad_modules(self): 'exec_err', 'exec_raise', 'exec_unreported_exception', + 'multiple_create_slots', + 'multiple_multiple_interpreters_slots', ]: with self.subTest(name_base): name = self.name + '_' + name_base diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst new file mode 100644 index 000000000000..afd267508461 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst @@ -0,0 +1,11 @@ +Multi-phase init extension modules may now indicate that they support +running in subinterpreters that have their own GIL. This is done by using +``Py_MOD_PER_INTERPRETER_GIL_SUPPORTED`` as the value for the +``Py_mod_multiple_interpreters`` module def slot. Otherwise the module, by +default, cannot be imported in such subinterpreters. (This does not affect +the main interpreter or subinterpreters that do not have their own GIL.) In +addition to the isolation that multi-phase init already normally requires, +support for per-interpreter GIL involves one additional constraint: +thread-safety. If the module has external (linked) dependencies and those +libraries have any state that isn't thread-safe then the module must do the +additional work to add thread-safety. This should be an uncommon case. diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index 58b064bb17cd..ca71b6156b00 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -681,6 +681,27 @@ PyInit__testmultiphase_export_unreported_exception(void) return PyModuleDef_Init(&main_def); } +static PyObject* +createfunc_noop(PyObject *spec, PyModuleDef *def) +{ + return PyModule_New("spam"); +} + +static PyModuleDef_Slot slots_multiple_create_slots[] = { + {Py_mod_create, createfunc_noop}, + {Py_mod_create, createfunc_noop}, + {0, NULL}, +}; + +static PyModuleDef def_multiple_create_slots = TEST_MODULE_DEF( + "_testmultiphase_multiple_create_slots", slots_multiple_create_slots, NULL); + +PyMODINIT_FUNC +PyInit__testmultiphase_multiple_create_slots(void) +{ + return PyModuleDef_Init(&def_multiple_create_slots); +} + static PyObject* createfunc_null(PyObject *spec, PyModuleDef *def) { @@ -892,7 +913,24 @@ PyInit__test_module_state_shared(void) } -/* multiple interpreters supports */ +/* multiple interpreters support */ + +static PyModuleDef_Slot slots_multiple_multiple_interpreters_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; + +static PyModuleDef def_multiple_multiple_interpreters_slots = TEST_MODULE_DEF( + "_testmultiphase_multiple_multiple_interpreters_slots", + slots_multiple_multiple_interpreters_slots, + NULL); + +PyMODINIT_FUNC +PyInit__testmultiphase_multiple_multiple_interpreters_slots(void) +{ + return PyModuleDef_Init(&def_multiple_multiple_interpreters_slots); +} static PyModuleDef_Slot non_isolated_slots[] = { {Py_mod_exec, execfunc}, @@ -909,3 +947,23 @@ PyInit__test_non_isolated(void) { return PyModuleDef_Init(&non_isolated_def); } + + +static PyModuleDef_Slot shared_gil_only_slots[] = { + {Py_mod_exec, execfunc}, + /* Note that Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED is the default. + We put it here explicitly to draw attention to the contrast + with Py_MOD_PER_INTERPRETER_GIL_SUPPORTED. */ + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED}, + {0, NULL}, +}; + +static PyModuleDef shared_gil_only_def = TEST_MODULE_DEF("_test_shared_gil_only", + shared_gil_only_slots, + testexport_methods); + +PyMODINIT_FUNC +PyInit__test_shared_gil_only(void) +{ + return PyModuleDef_Init(&shared_gil_only_def); +} diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index c100d018d3f0..985be58d02c7 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -323,7 +323,13 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio goto error; } } - // XXX Do a similar check once we have PyInterpreterState.ceval.own_gil. + else if (multiple_interpreters != Py_MOD_PER_INTERPRETER_GIL_SUPPORTED + && interp->ceval.own_gil + && !_Py_IsMainInterpreter(interp) + && _PyImport_CheckSubinterpIncompatibleExtensionAllowed(name) < 0) + { + goto error; + } if (create) { m = create(spec, def); From webhook-mailer at python.org Sat May 6 17:59:37 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Sat, 06 May 2023 21:59:37 -0000 Subject: [Python-checkins] gh-99113: Make Sure the GIL is Acquired at the Right Places (gh-104208) Message-ID: <mailman.208.1683410377.13550.python-checkins@python.org> https://github.com/python/cpython/commit/92d8bfffbf377e91d8b92666525cb8700bb1d5e8 commit: 92d8bfffbf377e91d8b92666525cb8700bb1d5e8 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-06T15:59:30-06:00 summary: gh-99113: Make Sure the GIL is Acquired at the Right Places (gh-104208) This is a pre-requisite for a per-interpreter GIL. Without it this change isn't strictly necessary. However, there is no real downside otherwise. files: M Include/internal/pycore_ceval.h M Python/ceval_gil.c M Python/pylifecycle.c M Python/pystate.c diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index b7a9bf40425b..9fd8571cbc87 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -100,7 +100,9 @@ extern int _PyEval_ThreadsInitialized(void); extern PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil); extern void _PyEval_FiniGIL(PyInterpreterState *interp); +extern void _PyEval_AcquireLock(PyThreadState *tstate); extern void _PyEval_ReleaseLock(PyThreadState *tstate); +extern PyThreadState * _PyThreadState_SwapNoGIL(PyThreadState *); extern void _PyEval_DeactivateOpCache(void); diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 1ac0dbcf2ecf..9958856bae80 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -499,42 +499,66 @@ PyEval_ThreadsInitialized(void) return _PyEval_ThreadsInitialized(); } +static inline int +current_thread_holds_gil(struct _gil_runtime_state *gil, PyThreadState *tstate) +{ + if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) != tstate) { + return 0; + } + return _Py_atomic_load_relaxed(&gil->locked); +} + +static void +init_shared_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) +{ + assert(gil_created(gil)); + interp->ceval.gil = gil; + interp->ceval.own_gil = 0; +} + +static void +init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) +{ + assert(!gil_created(gil)); + create_gil(gil); + assert(gil_created(gil)); + interp->ceval.gil = gil; + interp->ceval.own_gil = 1; +} + PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil) { assert(tstate->interp->ceval.gil == NULL); + int locked; if (!own_gil) { PyInterpreterState *main_interp = _PyInterpreterState_Main(); assert(tstate->interp != main_interp); struct _gil_runtime_state *gil = main_interp->ceval.gil; - assert(gil_created(gil)); - tstate->interp->ceval.gil = gil; - tstate->interp->ceval.own_gil = 0; - return _PyStatus_OK(); + init_shared_gil(tstate->interp, gil); + locked = current_thread_holds_gil(gil, tstate); } - /* XXX per-interpreter GIL */ - struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil; - if (!_Py_IsMainInterpreter(tstate->interp)) { + else if (!_Py_IsMainInterpreter(tstate->interp)) { /* Currently, the GIL is shared by all interpreters, and only the main interpreter is responsible to create and destroy it. */ - assert(gil_created(gil)); - tstate->interp->ceval.gil = gil; + struct _gil_runtime_state *main_gil = _PyInterpreterState_Main()->ceval.gil; + init_shared_gil(tstate->interp, main_gil); // XXX For now we lie. tstate->interp->ceval.own_gil = 1; - return _PyStatus_OK(); + locked = current_thread_holds_gil(main_gil, tstate); + } + else { + PyThread_init_thread(); + // XXX per-interpreter GIL: switch to interp->_gil. + init_own_gil(tstate->interp, &tstate->interp->runtime->ceval.gil); + locked = 0; + } + if (!locked) { + take_gil(tstate); } - assert(own_gil); - - assert(!gil_created(gil)); - PyThread_init_thread(); - create_gil(gil); - assert(gil_created(gil)); - tstate->interp->ceval.gil = gil; - tstate->interp->ceval.own_gil = 1; - take_gil(tstate); return _PyStatus_OK(); } @@ -611,9 +635,17 @@ PyEval_ReleaseLock(void) drop_gil(ceval, tstate); } +void +_PyEval_AcquireLock(PyThreadState *tstate) +{ + _Py_EnsureTstateNotNULL(tstate); + take_gil(tstate); +} + void _PyEval_ReleaseLock(PyThreadState *tstate) { + _Py_EnsureTstateNotNULL(tstate); struct _ceval_state *ceval = &tstate->interp->ceval; drop_gil(ceval, tstate); } @@ -625,7 +657,7 @@ PyEval_AcquireThread(PyThreadState *tstate) take_gil(tstate); - if (_PyThreadState_Swap(tstate->interp->runtime, tstate) != NULL) { + if (_PyThreadState_SwapNoGIL(tstate) != NULL) { Py_FatalError("non-NULL old thread state"); } } @@ -635,8 +667,7 @@ PyEval_ReleaseThread(PyThreadState *tstate) { assert(is_tstate_valid(tstate)); - _PyRuntimeState *runtime = tstate->interp->runtime; - PyThreadState *new_tstate = _PyThreadState_Swap(runtime, NULL); + PyThreadState *new_tstate = _PyThreadState_SwapNoGIL(NULL); if (new_tstate != tstate) { Py_FatalError("wrong thread state"); } @@ -684,8 +715,7 @@ _PyEval_SignalAsyncExc(PyInterpreterState *interp) PyThreadState * PyEval_SaveThread(void) { - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL); + PyThreadState *tstate = _PyThreadState_SwapNoGIL(NULL); _Py_EnsureTstateNotNULL(tstate); struct _ceval_state *ceval = &tstate->interp->ceval; @@ -701,7 +731,7 @@ PyEval_RestoreThread(PyThreadState *tstate) take_gil(tstate); - _PyThreadState_Swap(tstate->interp->runtime, tstate); + _PyThreadState_SwapNoGIL(tstate); } @@ -1005,7 +1035,7 @@ _Py_HandlePending(PyThreadState *tstate) /* GIL drop request */ if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gil_drop_request)) { /* Give another thread a chance */ - if (_PyThreadState_Swap(runtime, NULL) != tstate) { + if (_PyThreadState_SwapNoGIL(NULL) != tstate) { Py_FatalError("tstate mix-up"); } drop_gil(interp_ceval_state, tstate); @@ -1014,7 +1044,7 @@ _Py_HandlePending(PyThreadState *tstate) take_gil(tstate); - if (_PyThreadState_Swap(runtime, tstate) != NULL) { + if (_PyThreadState_SwapNoGIL(tstate) != NULL) { Py_FatalError("orphan tstate"); } } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 705708698c6a..61f87c5eba60 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -591,6 +591,7 @@ init_interp_create_gil(PyThreadState *tstate, int own_gil) /* finalize_interp_delete() comment explains why _PyEval_FiniGIL() is only called here. */ + // XXX This is broken with a per-interpreter GIL. _PyEval_FiniGIL(tstate->interp); /* Auto-thread-state API */ @@ -645,7 +646,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return _PyStatus_ERR("can't make first thread"); } _PyThreadState_Bind(tstate); - (void) PyThreadState_Swap(tstate); + // XXX For now we do this before the GIL is created. + (void) _PyThreadState_SwapNoGIL(tstate); status = init_interp_create_gil(tstate, config.own_gil); if (_PyStatus_EXCEPTION(status)) { @@ -2025,11 +2027,20 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) } _PyThreadState_Bind(tstate); - PyThreadState *save_tstate = PyThreadState_Swap(tstate); + // XXX For now we do this before the GIL is created. + PyThreadState *save_tstate = _PyThreadState_SwapNoGIL(tstate); + int has_gil = 0; + + /* From this point until the init_interp_create_gil() call, + we must not do anything that requires that the GIL be held + (or otherwise exist). That applies whether or not the new + interpreter has its own GIL (e.g. the main interpreter). */ /* Copy the current interpreter config into the new interpreter */ const PyConfig *src_config; if (save_tstate != NULL) { + // XXX Might new_interpreter() have been called without the GIL held? + _PyEval_ReleaseLock(save_tstate); src_config = _PyInterpreterState_GetConfig(save_tstate->interp); } else @@ -2039,11 +2050,13 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) src_config = _PyInterpreterState_GetConfig(main_interp); } + /* This does not require that the GIL be held. */ status = _PyConfig_Copy(&interp->config, src_config); if (_PyStatus_EXCEPTION(status)) { goto error; } + /* This does not require that the GIL be held. */ status = init_interp_settings(interp, config); if (_PyStatus_EXCEPTION(status)) { goto error; @@ -2053,6 +2066,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) if (_PyStatus_EXCEPTION(status)) { goto error; } + has_gil = 1; status = pycore_interp_init(tstate); if (_PyStatus_EXCEPTION(status)) { @@ -2072,7 +2086,12 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); - PyThreadState_Swap(save_tstate); + if (has_gil) { + PyThreadState_Swap(save_tstate); + } + else { + _PyThreadState_SwapNoGIL(save_tstate); + } PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); diff --git a/Python/pystate.c b/Python/pystate.c index 75bd9f41e301..f14934361dab 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1863,17 +1863,11 @@ PyThreadState_Get(void) } -PyThreadState * -_PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts) +static void +_swap_thread_states(_PyRuntimeState *runtime, + PyThreadState *oldts, PyThreadState *newts) { -#if defined(Py_DEBUG) - /* This can be called from PyEval_RestoreThread(). Similar - to it, we need to ensure errno doesn't change. - */ - int err = errno; -#endif - PyThreadState *oldts = current_fast_get(runtime); - + // XXX Do this only if oldts != NULL? current_fast_clear(runtime); if (oldts != NULL) { @@ -1887,6 +1881,20 @@ _PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts) current_fast_set(runtime, newts); tstate_activate(newts); } +} + +PyThreadState * +_PyThreadState_SwapNoGIL(PyThreadState *newts) +{ +#if defined(Py_DEBUG) + /* This can be called from PyEval_RestoreThread(). Similar + to it, we need to ensure errno doesn't change. + */ + int err = errno; +#endif + + PyThreadState *oldts = current_fast_get(&_PyRuntime); + _swap_thread_states(&_PyRuntime, oldts, newts); #if defined(Py_DEBUG) errno = err; @@ -1894,6 +1902,20 @@ _PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts) return oldts; } +PyThreadState * +_PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts) +{ + PyThreadState *oldts = current_fast_get(runtime); + if (oldts != NULL) { + _PyEval_ReleaseLock(oldts); + } + _swap_thread_states(runtime, oldts, newts); + if (newts != NULL) { + _PyEval_AcquireLock(newts); + } + return oldts; +} + PyThreadState * PyThreadState_Swap(PyThreadState *newts) { From webhook-mailer at python.org Sat May 6 18:53:54 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 06 May 2023 22:53:54 -0000 Subject: [Python-checkins] gh-101640: Make argparse _print_message catch any write error (#101802) Message-ID: <mailman.209.1683413635.13550.python-checkins@python.org> https://github.com/python/cpython/commit/42f54d1f9244784fec99e0610aa05a5051e594bb commit: 42f54d1f9244784fec99e0610aa05a5051e594bb branch: main author: Oleg Iarygin <oleg at arhadthedev.net> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-06T18:53:48-04:00 summary: gh-101640: Make argparse _print_message catch any write error (#101802) * In particular, don't exit when trying to print to stderr = None. * Add tests Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: A Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst M Lib/argparse.py M Lib/test/test_argparse.py diff --git a/Lib/argparse.py b/Lib/argparse.py index a819d2650e85..68089a5c1e80 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2605,9 +2605,11 @@ def print_help(self, file=None): def _print_message(self, message, file=None): if message: - if file is None: - file = _sys.stderr - file.write(message) + file = file or _sys.stderr + try: + file.write(message) + except (AttributeError, OSError): + pass # =============== # Exiting methods diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 861da2326d12..0659d244d356 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1,5 +1,7 @@ # Author: Steven J. Bethard <steven.bethard at gmail.com>. +import contextlib +import functools import inspect import io import operator @@ -35,6 +37,35 @@ def getvalue(self): return self.buffer.raw.getvalue().decode('utf-8') +class StdStreamTest(unittest.TestCase): + + def test_skip_invalid_stderr(self): + parser = argparse.ArgumentParser() + with ( + contextlib.redirect_stderr(None), + mock.patch('argparse._sys.exit') + ): + parser.exit(status=0, message='foo') + + def test_skip_invalid_stdout(self): + parser = argparse.ArgumentParser() + for func in ( + parser.print_usage, + parser.print_help, + functools.partial(parser.parse_args, ['-h']) + ): + with ( + self.subTest(func=func), + contextlib.redirect_stdout(None), + # argparse uses stderr as a fallback + StdIOBuffer() as mocked_stderr, + contextlib.redirect_stderr(mocked_stderr), + mock.patch('argparse._sys.exit'), + ): + func() + self.assertRegex(mocked_stderr.getvalue(), r'usage:') + + class TestCase(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst b/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst new file mode 100644 index 000000000000..917cf0f97b9e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst @@ -0,0 +1 @@ +:class:`argparse.ArgumentParser` now catches errors when writing messages, such as when :data:`sys.stderr` is ``None``. Patch by Oleg Iarygin. From webhook-mailer at python.org Sat May 6 19:17:33 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 06 May 2023 23:17:33 -0000 Subject: [Python-checkins] [3.11] gh-101640: Make argparse _print_message catch any write error (GH-101802) (#104250) Message-ID: <mailman.210.1683415055.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cf1c25fd6e38df682a9de2e06e87ee3c6b63f4d7 commit: cf1c25fd6e38df682a9de2e06e87ee3c6b63f4d7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-06T23:17:27Z summary: [3.11] gh-101640: Make argparse _print_message catch any write error (GH-101802) (#104250) gh-101640: Make argparse _print_message catch any write error (GH-101802) * In particular, don't exit when trying to print to stderr = None. * Add tests (cherry picked from commit 42f54d1f9244784fec99e0610aa05a5051e594bb) Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: A Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst M Lib/argparse.py M Lib/test/test_argparse.py diff --git a/Lib/argparse.py b/Lib/argparse.py index 96617464966f..9962e61a679e 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2602,9 +2602,11 @@ def print_help(self, file=None): def _print_message(self, message, file=None): if message: - if file is None: - file = _sys.stderr - file.write(message) + file = file or _sys.stderr + try: + file.write(message) + except (AttributeError, OSError): + pass # =============== # Exiting methods diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 3fb88e5c6371..6322ebbb8405 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1,5 +1,7 @@ # Author: Steven J. Bethard <steven.bethard at gmail.com>. +import contextlib +import functools import inspect import io import operator @@ -35,6 +37,35 @@ def getvalue(self): return self.buffer.raw.getvalue().decode('utf-8') +class StdStreamTest(unittest.TestCase): + + def test_skip_invalid_stderr(self): + parser = argparse.ArgumentParser() + with ( + contextlib.redirect_stderr(None), + mock.patch('argparse._sys.exit') + ): + parser.exit(status=0, message='foo') + + def test_skip_invalid_stdout(self): + parser = argparse.ArgumentParser() + for func in ( + parser.print_usage, + parser.print_help, + functools.partial(parser.parse_args, ['-h']) + ): + with ( + self.subTest(func=func), + contextlib.redirect_stdout(None), + # argparse uses stderr as a fallback + StdIOBuffer() as mocked_stderr, + contextlib.redirect_stderr(mocked_stderr), + mock.patch('argparse._sys.exit'), + ): + func() + self.assertRegex(mocked_stderr.getvalue(), r'usage:') + + class TestCase(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst b/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst new file mode 100644 index 000000000000..917cf0f97b9e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst @@ -0,0 +1 @@ +:class:`argparse.ArgumentParser` now catches errors when writing messages, such as when :data:`sys.stderr` is ``None``. Patch by Oleg Iarygin. From webhook-mailer at python.org Sat May 6 21:32:00 2023 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 07 May 2023 01:32:00 -0000 Subject: [Python-checkins] gh-104254: Document the optional keyword-only "context" argument to Task constructor (#104251) Message-ID: <mailman.211.1683423121.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4ee2068c34bd45eddba7f6a8ee83f62d5b6932fc commit: 4ee2068c34bd45eddba7f6a8ee83f62d5b6932fc branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-06T18:31:53-07:00 summary: gh-104254: Document the optional keyword-only "context" argument to Task constructor (#104251) (This was added in 3.11. It was already documented for `create_task()`, but not for `Task()`.) files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index f8727b980669..a46ebc1c3d25 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1014,7 +1014,7 @@ Introspection Task Object =========== -.. class:: Task(coro, *, loop=None, name=None) +.. class:: Task(coro, *, loop=None, name=None, context=None) A :class:`Future-like <Future>` object that runs a Python :ref:`coroutine <coroutine>`. Not thread-safe. @@ -1049,9 +1049,10 @@ Task Object APIs except :meth:`Future.set_result` and :meth:`Future.set_exception`. - Tasks support the :mod:`contextvars` module. When a Task - is created it copies the current context and later runs its - coroutine in the copied context. + An optional keyword-only *context* argument allows specifying a + custom :class:`contextvars.Context` for the *coro* to run in. + If no *context* is provided, the Task copies the current context + and later runs its coroutine in the copied context. .. versionchanged:: 3.7 Added support for the :mod:`contextvars` module. @@ -1063,6 +1064,9 @@ Task Object Deprecation warning is emitted if *loop* is not specified and there is no running event loop. + .. versionchanged:: 3.11 + Added the *context* parameter. + .. method:: done() Return ``True`` if the Task is *done*. From webhook-mailer at python.org Sat May 6 22:05:41 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 07 May 2023 02:05:41 -0000 Subject: [Python-checkins] gh-103886: Improve `builtins.__doc__` (#104179) Message-ID: <mailman.212.1683425142.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b35711d17a90251bdd57d255090e07daafe89f6c commit: b35711d17a90251bdd57d255090e07daafe89f6c branch: main author: Tomas R <tomas.roun8 at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-06T19:05:34-07:00 summary: gh-103886: Improve `builtins.__doc__` (#104179) Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Python/bltinmodule.c diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 8840bbabe4b5..ddddc03ca316 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3014,9 +3014,16 @@ static PyMethodDef builtin_methods[] = { }; PyDoc_STRVAR(builtin_doc, -"Built-in functions, exceptions, and other objects.\n\ +"Built-in functions, types, exceptions, and other objects.\n\ \n\ -Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices."); +This module provides direct access to all 'built-in'\n\ +identifiers of Python; for example, builtins.len is\n\ +the full name for the built-in function len().\n\ +\n\ +This module is not normally accessed explicitly by most\n\ +applications, but can be useful in modules that provide\n\ +objects with the same name as a built-in value, but in\n\ +which the built-in of that name is also needed."); static struct PyModuleDef builtinsmodule = { PyModuleDef_HEAD_INIT, From webhook-mailer at python.org Sat May 6 22:28:13 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 07 May 2023 02:28:13 -0000 Subject: [Python-checkins] [3.11] gh-103886: Improve `builtins.__doc__` (GH-104179) (#104257) Message-ID: <mailman.213.1683426494.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8f23cadc4ca0c56e18c32985ae0c087e79633c0f commit: 8f23cadc4ca0c56e18c32985ae0c087e79633c0f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-07T02:28:04Z summary: [3.11] gh-103886: Improve `builtins.__doc__` (GH-104179) (#104257) gh-103886: Improve `builtins.__doc__` (GH-104179) (cherry picked from commit b35711d17a90251bdd57d255090e07daafe89f6c) Co-authored-by: Tomas R <tomas.roun8 at gmail.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Python/bltinmodule.c diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 6c8725f98231..e20bd5396bf5 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2999,9 +2999,16 @@ static PyMethodDef builtin_methods[] = { }; PyDoc_STRVAR(builtin_doc, -"Built-in functions, exceptions, and other objects.\n\ +"Built-in functions, types, exceptions, and other objects.\n\ \n\ -Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices."); +This module provides direct access to all 'built-in'\n\ +identifiers of Python; for example, builtins.len is\n\ +the full name for the built-in function len().\n\ +\n\ +This module is not normally accessed explicitly by most\n\ +applications, but can be useful in modules that provide\n\ +objects with the same name as a built-in value, but in\n\ +which the built-in of that name is also needed."); static struct PyModuleDef builtinsmodule = { PyModuleDef_HEAD_INIT, From webhook-mailer at python.org Sun May 7 00:22:30 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 07 May 2023 04:22:30 -0000 Subject: [Python-checkins] [3.11] gh-104254: Document the optional keyword-only "context" argument to Task constructor (GH-104251) (#104258) Message-ID: <mailman.214.1683433351.13550.python-checkins@python.org> https://github.com/python/cpython/commit/efcd4bcb87a8a461ccf8f6038f75e638d86eeb8c commit: efcd4bcb87a8a461ccf8f6038f75e638d86eeb8c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-07T09:52:23+05:30 summary: [3.11] gh-104254: Document the optional keyword-only "context" argument to Task constructor (GH-104251) (#104258) gh-104254: Document the optional keyword-only "context" argument to Task constructor (GH-104251) (This was added in 3.11. It was already documented for `create_task()`, but not for `Task()`.) (cherry picked from commit 4ee2068c34bd45eddba7f6a8ee83f62d5b6932fc) Co-authored-by: Itamar Ostricher <itamarost at gmail.com> files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index bfefe8e3815b..550a84ebae39 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -967,7 +967,7 @@ Introspection Task Object =========== -.. class:: Task(coro, *, loop=None, name=None) +.. class:: Task(coro, *, loop=None, name=None, context=None) A :class:`Future-like <Future>` object that runs a Python :ref:`coroutine <coroutine>`. Not thread-safe. @@ -1002,9 +1002,10 @@ Task Object APIs except :meth:`Future.set_result` and :meth:`Future.set_exception`. - Tasks support the :mod:`contextvars` module. When a Task - is created it copies the current context and later runs its - coroutine in the copied context. + An optional keyword-only *context* argument allows specifying a + custom :class:`contextvars.Context` for the *coro* to run in. + If no *context* is provided, the Task copies the current context + and later runs its coroutine in the copied context. .. versionchanged:: 3.7 Added support for the :mod:`contextvars` module. @@ -1016,6 +1017,9 @@ Task Object Deprecation warning is emitted if *loop* is not specified and there is no running event loop. + .. versionchanged:: 3.11 + Added the *context* parameter. + .. method:: done() Return ``True`` if the Task is *done*. From webhook-mailer at python.org Sun May 7 00:25:52 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 07 May 2023 04:25:52 -0000 Subject: [Python-checkins] gh-97696: Use `PyObject_CallMethodNoArgs` and inline is_loop_running check in `_asyncio` (#104255) Message-ID: <mailman.215.1683433553.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c53547c907371be53c8016145d73ba4ea0a22756 commit: c53547c907371be53c8016145d73ba4ea0a22756 branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-07T09:55:45+05:30 summary: gh-97696: Use `PyObject_CallMethodNoArgs` and inline is_loop_running check in `_asyncio` (#104255) files: M Modules/_asynciomodule.c diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 39c33fed74e2..3830245abe87 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2063,21 +2063,6 @@ swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task) return prev_task; } -static int -is_loop_running(PyObject *loop) -{ - PyObject *func = PyObject_GetAttr(loop, &_Py_ID(is_running)); - if (func == NULL) { - PyErr_Format(PyExc_TypeError, "Loop missing is_running()"); - return -1; - } - PyObject *res = PyObject_CallNoArgs(func); - int retval = Py_IsTrue(res); - Py_DECREF(func); - Py_DECREF(res); - return !!retval; -} - /* ----- Task */ /*[clinic input] @@ -2148,11 +2133,13 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop, } if (eager_start) { - int loop_running = is_loop_running(self->task_loop); - if (loop_running == -1) { + PyObject *res = PyObject_CallMethodNoArgs(loop, &_Py_ID(is_running)); + if (res == NULL) { return -1; } - if (loop_running) { + int is_loop_running = Py_IsTrue(res); + Py_DECREF(res); + if (is_loop_running) { if (task_eager_start(state, self)) { return -1; } From webhook-mailer at python.org Sun May 7 00:41:49 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 07 May 2023 04:41:49 -0000 Subject: [Python-checkins] gh-104018: remove unused format "z" handling in string formatfloat() (#104107) Message-ID: <mailman.216.1683434510.13550.python-checkins@python.org> https://github.com/python/cpython/commit/69621d1b09c996e43a1e13d2fa4c317d3dd4d738 commit: 69621d1b09c996e43a1e13d2fa4c317d3dd4d738 branch: main author: John Belmonte <john at neggie.net> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-07T10:11:42+05:30 summary: gh-104018: remove unused format "z" handling in string formatfloat() (#104107) This is a cleanup overlooked in PR #104033. files: M Include/internal/pycore_format.h M Objects/bytesobject.c M Objects/unicodeobject.c M Python/ast_opt.c diff --git a/Include/internal/pycore_format.h b/Include/internal/pycore_format.h index 1899609e77ef..1b8d57539ca5 100644 --- a/Include/internal/pycore_format.h +++ b/Include/internal/pycore_format.h @@ -14,14 +14,12 @@ extern "C" { * F_BLANK ' ' * F_ALT '#' * F_ZERO '0' - * F_NO_NEG_0 'z' */ #define F_LJUST (1<<0) #define F_SIGN (1<<1) #define F_BLANK (1<<2) #define F_ALT (1<<3) #define F_ZERO (1<<4) -#define F_NO_NEG_0 (1<<5) #ifdef __cplusplus } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index e7e85cc19cda..abbf3eeb16c3 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -423,9 +423,6 @@ formatfloat(PyObject *v, int flags, int prec, int type, if (flags & F_ALT) { dtoa_flags |= Py_DTSF_ALT; } - if (flags & F_NO_NEG_0) { - dtoa_flags |= Py_DTSF_NO_NEG_0; - } p = PyOS_double_to_string(x, type, prec, dtoa_flags, NULL); if (p == NULL) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 1585a582f00a..7726f2fb17af 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -13452,8 +13452,6 @@ formatfloat(PyObject *v, struct unicode_format_arg_t *arg, if (arg->flags & F_ALT) dtoa_flags |= Py_DTSF_ALT; - if (arg->flags & F_NO_NEG_0) - dtoa_flags |= Py_DTSF_NO_NEG_0; p = PyOS_double_to_string(x, arg->ch, prec, dtoa_flags, NULL); if (p == NULL) return -1; diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 8270fa8e372d..3883ec9e21c7 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -317,7 +317,6 @@ simple_format_arg_parse(PyObject *fmt, Py_ssize_t *ppos, case ' ': *flags |= F_BLANK; continue; case '#': *flags |= F_ALT; continue; case '0': *flags |= F_ZERO; continue; - case 'z': *flags |= F_NO_NEG_0; continue; } break; } From webhook-mailer at python.org Sun May 7 00:44:52 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 07 May 2023 04:44:52 -0000 Subject: [Python-checkins] Re-enable commented-out test in test_generators.py (#104130) Message-ID: <mailman.217.1683434694.13550.python-checkins@python.org> https://github.com/python/cpython/commit/472938316a85c706c06ad1b3727a205d5bffcb1f commit: 472938316a85c706c06ad1b3727a205d5bffcb1f branch: main author: ymki4360 <132453923+ymki4360 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-07T10:14:46+05:30 summary: Re-enable commented-out test in test_generators.py (#104130) files: M Lib/test/test_generators.py diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index cc782ea1ee5d..31680b5a92e0 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -2141,11 +2141,10 @@ def printsolution(self, x): ... SyntaxError: 'yield' outside function -# Pegen does not produce this error message yet -# >>> def f(): x = yield = y -# Traceback (most recent call last): -# ... -# SyntaxError: assignment to yield expression not possible +>>> def f(): x = yield = y +Traceback (most recent call last): + ... +SyntaxError: assignment to yield expression not possible >>> def f(): (yield bar) = y Traceback (most recent call last): From webhook-mailer at python.org Sun May 7 01:06:13 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 07 May 2023 05:06:13 -0000 Subject: [Python-checkins] [3.11] gh-104018: remove unused format "z" handling in string formatfloat() (GH-104107) (#104260) Message-ID: <mailman.218.1683435974.13550.python-checkins@python.org> https://github.com/python/cpython/commit/15ffcf76e1b6bdd14aff0875beb2a8f2afdaf374 commit: 15ffcf76e1b6bdd14aff0875beb2a8f2afdaf374 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-07T05:06:06Z summary: [3.11] gh-104018: remove unused format "z" handling in string formatfloat() (GH-104107) (#104260) gh-104018: remove unused format "z" handling in string formatfloat() (GH-104107) This is a cleanup overlooked in PR GH-104033. (cherry picked from commit 69621d1b09c996e43a1e13d2fa4c317d3dd4d738) Co-authored-by: John Belmonte <john at neggie.net> files: M Include/internal/pycore_format.h M Objects/bytesobject.c M Objects/unicodeobject.c M Python/ast_opt.c diff --git a/Include/internal/pycore_format.h b/Include/internal/pycore_format.h index 1899609e77ef..1b8d57539ca5 100644 --- a/Include/internal/pycore_format.h +++ b/Include/internal/pycore_format.h @@ -14,14 +14,12 @@ extern "C" { * F_BLANK ' ' * F_ALT '#' * F_ZERO '0' - * F_NO_NEG_0 'z' */ #define F_LJUST (1<<0) #define F_SIGN (1<<1) #define F_BLANK (1<<2) #define F_ALT (1<<3) #define F_ZERO (1<<4) -#define F_NO_NEG_0 (1<<5) #ifdef __cplusplus } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 61cde0ef34bf..3b0ff9a19d97 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -430,9 +430,6 @@ formatfloat(PyObject *v, int flags, int prec, int type, if (flags & F_ALT) { dtoa_flags |= Py_DTSF_ALT; } - if (flags & F_NO_NEG_0) { - dtoa_flags |= Py_DTSF_NO_NEG_0; - } p = PyOS_double_to_string(x, type, prec, dtoa_flags, NULL); if (p == NULL) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 84d17f000b41..4bdc89316a86 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14385,8 +14385,6 @@ formatfloat(PyObject *v, struct unicode_format_arg_t *arg, if (arg->flags & F_ALT) dtoa_flags |= Py_DTSF_ALT; - if (arg->flags & F_NO_NEG_0) - dtoa_flags |= Py_DTSF_NO_NEG_0; p = PyOS_double_to_string(x, arg->ch, prec, dtoa_flags, NULL); if (p == NULL) return -1; diff --git a/Python/ast_opt.c b/Python/ast_opt.c index b1d807bcf10a..77ed29d0cddd 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -310,7 +310,6 @@ simple_format_arg_parse(PyObject *fmt, Py_ssize_t *ppos, case ' ': *flags |= F_BLANK; continue; case '#': *flags |= F_ALT; continue; case '0': *flags |= F_ZERO; continue; - case 'z': *flags |= F_NO_NEG_0; continue; } break; } From webhook-mailer at python.org Sun May 7 01:11:07 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 07 May 2023 05:11:07 -0000 Subject: [Python-checkins] [3.11] Re-enable commented-out test in test_generators.py (GH-104130) (#104261) Message-ID: <mailman.219.1683436267.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c5dafeaa6d2dddd1d9e611424d8abf3a934880c6 commit: c5dafeaa6d2dddd1d9e611424d8abf3a934880c6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-07T05:11:00Z summary: [3.11] Re-enable commented-out test in test_generators.py (GH-104130) (#104261) Re-enable commented-out test in test_generators.py (GH-104130) (cherry picked from commit 472938316a85c706c06ad1b3727a205d5bffcb1f) Co-authored-by: ymki4360 <132453923+ymki4360 at users.noreply.github.com> files: M Lib/test/test_generators.py diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 353073dbfce0..04c44c8b4ac5 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -2097,11 +2097,10 @@ def printsolution(self, x): ... SyntaxError: 'yield' outside function -# Pegen does not produce this error message yet -# >>> def f(): x = yield = y -# Traceback (most recent call last): -# ... -# SyntaxError: assignment to yield expression not possible +>>> def f(): x = yield = y +Traceback (most recent call last): + ... +SyntaxError: assignment to yield expression not possible >>> def f(): (yield bar) = y Traceback (most recent call last): From webhook-mailer at python.org Sun May 7 05:20:40 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 07 May 2023 09:20:40 -0000 Subject: [Python-checkins] gh-101819: Port _io.PyIncrementalNewlineDecoder_Type to heap type (#104249) Message-ID: <mailman.220.1683451241.13550.python-checkins@python.org> https://github.com/python/cpython/commit/39523796554c41f16e74961f7a90dfc30b0eed64 commit: 39523796554c41f16e74961f7a90dfc30b0eed64 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-07T11:20:34+02:00 summary: gh-101819: Port _io.PyIncrementalNewlineDecoder_Type to heap type (#104249) files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/textio.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 99b8a8e09ecf..ce9fcca971f9 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -660,7 +660,6 @@ struct PyModuleDef _PyIO_Module = { static PyTypeObject* static_types[] = { // Base classes &PyIOBase_Type, - &PyIncrementalNewlineDecoder_Type, // PyIOBase_Type subclasses &PyBufferedIOBase_Type, @@ -757,7 +756,7 @@ PyInit__io(void) } // Base classes - state->PyIncrementalNewlineDecoder_Type = (PyTypeObject *)Py_NewRef(&PyIncrementalNewlineDecoder_Type); + ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); // PyIOBase_Type subclasses state->PyRawIOBase_Type = (PyTypeObject *)Py_NewRef(&PyRawIOBase_Type); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index c971c987cf5f..f191cea7fcc4 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -14,9 +14,6 @@ extern PyTypeObject PyRawIOBase_Type; extern PyTypeObject PyBufferedIOBase_Type; extern PyTypeObject PyTextIOBase_Type; -/* Concrete classes */ -extern PyTypeObject PyIncrementalNewlineDecoder_Type; - /* Type specs */ extern PyType_Spec bufferedrandom_spec; extern PyType_Spec bufferedreader_spec; @@ -24,6 +21,7 @@ extern PyType_Spec bufferedrwpair_spec; extern PyType_Spec bufferedwriter_spec; extern PyType_Spec bytesio_spec; extern PyType_Spec fileio_spec; +extern PyType_Spec nldecoder_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiowrapper_spec; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 2dba382f4f8f..070687a83d1b 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -248,12 +248,32 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self, return 0; } -static void -incrementalnewlinedecoder_dealloc(nldecoder_object *self) +static int +incrementalnewlinedecoder_traverse(nldecoder_object *self, visitproc visit, + void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->decoder); + Py_VISIT(self->errors); + return 0; +} + +static int +incrementalnewlinedecoder_clear(nldecoder_object *self) { Py_CLEAR(self->decoder); Py_CLEAR(self->errors); - Py_TYPE(self)->tp_free((PyObject *)self); + return 0; +} + +static void +incrementalnewlinedecoder_dealloc(nldecoder_object *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + (void)incrementalnewlinedecoder_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static int @@ -3176,45 +3196,23 @@ static PyGetSetDef incrementalnewlinedecoder_getset[] = { {NULL} }; -PyTypeObject PyIncrementalNewlineDecoder_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.IncrementalNewlineDecoder", /*tp_name*/ - sizeof(nldecoder_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)incrementalnewlinedecoder_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, /*tp_flags*/ - _io_IncrementalNewlineDecoder___init____doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /*tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - incrementalnewlinedecoder_methods, /* tp_methods */ - 0, /* tp_members */ - incrementalnewlinedecoder_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - _io_IncrementalNewlineDecoder___init__, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot nldecoder_slots[] = { + {Py_tp_dealloc, incrementalnewlinedecoder_dealloc}, + {Py_tp_doc, (void *)_io_IncrementalNewlineDecoder___init____doc__}, + {Py_tp_methods, incrementalnewlinedecoder_methods}, + {Py_tp_getset, incrementalnewlinedecoder_getset}, + {Py_tp_traverse, incrementalnewlinedecoder_traverse}, + {Py_tp_clear, incrementalnewlinedecoder_clear}, + {Py_tp_init, _io_IncrementalNewlineDecoder___init__}, + {0, NULL}, +}; + +PyType_Spec nldecoder_spec = { + .name = "_io.IncrementalNewlineDecoder", + .basicsize = sizeof(nldecoder_object), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = nldecoder_slots, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 165bd74587d7..b195dab9ccc8 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -321,7 +321,6 @@ Modules/_io/bufferedio.c - PyBufferedIOBase_Type - Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - -Modules/_io/textio.c - PyIncrementalNewlineDecoder_Type - Modules/_io/textio.c - PyTextIOBase_Type - Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - From webhook-mailer at python.org Sun May 7 05:23:18 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 07 May 2023 09:23:18 -0000 Subject: [Python-checkins] gh-101819: Adapt _io.PyWindowsConsoleIO_Type to heap type (#104197) Message-ID: <mailman.221.1683451398.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cab1298a6022ddf12ddcdadd74bb8741650d8e9f commit: cab1298a6022ddf12ddcdadd74bb8741650d8e9f branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-07T11:23:11+02:00 summary: gh-101819: Adapt _io.PyWindowsConsoleIO_Type to heap type (#104197) files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/winconsoleio.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ce9fcca971f9..b72b847c6634 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -321,7 +321,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, #ifdef HAVE_WINDOWS_CONSOLE_IO const PyConfig *config = _Py_GetConfig(); if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') { - RawIO_class = (PyObject *)&PyWindowsConsoleIO_Type; + RawIO_class = (PyObject *)state->PyWindowsConsoleIO_Type; encoding = "utf-8"; } #endif @@ -595,6 +595,9 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { Py_VISIT(state->PyStringIO_Type); Py_VISIT(state->PyTextIOBase_Type); Py_VISIT(state->PyTextIOWrapper_Type); +#ifdef HAVE_WINDOWS_CONSOLE_IO + Py_VISIT(state->PyWindowsConsoleIO_Type); +#endif return 0; } @@ -619,6 +622,9 @@ iomodule_clear(PyObject *mod) { Py_CLEAR(state->PyStringIO_Type); Py_CLEAR(state->PyTextIOBase_Type); Py_CLEAR(state->PyTextIOWrapper_Type); +#ifdef HAVE_WINDOWS_CONSOLE_IO + Py_CLEAR(state->PyWindowsConsoleIO_Type); +#endif return 0; } @@ -668,22 +674,12 @@ static PyTypeObject* static_types[] = { // PyRawIOBase_Type(PyIOBase_Type) subclasses &_PyBytesIOBuffer_Type, -#ifdef HAVE_WINDOWS_CONSOLE_IO - &PyWindowsConsoleIO_Type, -#endif }; PyStatus _PyIO_InitTypes(PyInterpreterState *interp) { -#ifdef HAVE_WINDOWS_CONSOLE_IO - if (_Py_IsMainInterpreter(interp)) { - // Set type base classes - PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; - } -#endif - for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; if (_PyStaticType_InitBuiltin(interp, type) < 0) { @@ -777,6 +773,10 @@ PyInit__io(void) // PyRawIOBase_Type(PyIOBase_Type) subclasses state->PyBytesIOBuffer_Type = (PyTypeObject *)Py_NewRef(&_PyBytesIOBuffer_Type); ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); +#ifdef MS_WINDOWS + ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, + state->PyRawIOBase_Type); +#endif // PyTextIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, state->PyTextIOBase_Type); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index f191cea7fcc4..00e6a19db2b8 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -26,8 +26,8 @@ extern PyType_Spec stringio_spec; extern PyType_Spec textiowrapper_spec; #ifdef HAVE_WINDOWS_CONSOLE_IO -extern PyTypeObject PyWindowsConsoleIO_Type; -#endif /* HAVE_WINDOWS_CONSOLE_IO */ +extern PyType_Spec winconsoleio_spec; +#endif /* These functions are used as METH_NOARGS methods, are normally called * with args=NULL, and return a new reference. @@ -157,6 +157,9 @@ typedef struct { PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; +#ifdef MS_WINDOWS + PyTypeObject *PyWindowsConsoleIO_Type; +#endif } _PyIO_State; #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index f836e2302430..fdb57cff7c04 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -137,9 +137,9 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { /*[clinic input] module _io -class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" +class _io._WindowsConsoleIO "winconsoleio *" "clinic_state()->PyWindowsConsoleIO_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e897fdc1fba4e131]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=05526e723011ab36]*/ typedef struct { PyObject_HEAD @@ -156,8 +156,6 @@ typedef struct { wchar_t wbuf; } winconsoleio; -PyTypeObject PyWindowsConsoleIO_Type; - int _PyWindowsConsoleIO_closed(PyObject *self) { @@ -265,7 +263,10 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, int fd_is_own = 0; HANDLE handle = NULL; - assert(PyObject_TypeCheck(self, (PyTypeObject *)&PyWindowsConsoleIO_Type)); +#ifdef Py_DEBUG + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + assert(PyObject_TypeCheck(self, state->PyWindowsConsoleIO_Type)); +#endif if (self->fd >= 0) { if (self->closefd) { /* Have to close the existing file first. */ @@ -417,6 +418,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, static int winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } @@ -431,6 +433,7 @@ winconsoleio_clear(winconsoleio *self) static void winconsoleio_dealloc(winconsoleio *self) { + PyTypeObject *tp = Py_TYPE(self); self->finalizing = 1; if (_PyIOBase_finalize((PyObject *) self) < 0) return; @@ -438,7 +441,8 @@ winconsoleio_dealloc(winconsoleio *self) if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); Py_CLEAR(self->dict); - Py_TYPE(self)->tp_free((PyObject *)self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -1078,7 +1082,9 @@ _io__WindowsConsoleIO_isatty_impl(winconsoleio *self) Py_RETURN_TRUE; } +#define clinic_state() (IO_STATE()) #include "clinic/winconsoleio.c.h" +#undef clinic_state static PyMethodDef winconsoleio_methods[] = { _IO__WINDOWSCONSOLEIO_READ_METHODDEF @@ -1124,59 +1130,32 @@ static PyGetSetDef winconsoleio_getsetlist[] = { static PyMemberDef winconsoleio_members[] = { {"_blksize", T_UINT, offsetof(winconsoleio, blksize), 0}, {"_finalizing", T_BOOL, offsetof(winconsoleio, finalizing), 0}, + {"__weaklistoffset__", T_PYSSIZET, offsetof(winconsoleio, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(winconsoleio, dict), READONLY}, {NULL} }; -PyTypeObject PyWindowsConsoleIO_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._WindowsConsoleIO", - sizeof(winconsoleio), - 0, - (destructor)winconsoleio_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)winconsoleio_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 - | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - _io__WindowsConsoleIO___init____doc__, /* tp_doc */ - (traverseproc)winconsoleio_traverse, /* tp_traverse */ - (inquiry)winconsoleio_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(winconsoleio, weakreflist), /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - winconsoleio_methods, /* tp_methods */ - winconsoleio_members, /* tp_members */ - winconsoleio_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(winconsoleio, dict), /* tp_dictoffset */ - _io__WindowsConsoleIO___init__, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - winconsoleio_new, /* tp_new */ - PyObject_GC_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 */ - 0, /* tp_finalize */ +static PyType_Slot winconsoleio_slots[] = { + {Py_tp_dealloc, winconsoleio_dealloc}, + {Py_tp_repr, winconsoleio_repr}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)_io__WindowsConsoleIO___init____doc__}, + {Py_tp_traverse, winconsoleio_traverse}, + {Py_tp_clear, winconsoleio_clear}, + {Py_tp_methods, winconsoleio_methods}, + {Py_tp_members, winconsoleio_members}, + {Py_tp_getset, winconsoleio_getsetlist}, + {Py_tp_init, _io__WindowsConsoleIO___init__}, + {Py_tp_new, winconsoleio_new}, + {0, NULL}, +}; + +PyType_Spec winconsoleio_spec = { + .name = "_io._WindowsConsoleIO", + .basicsize = sizeof(winconsoleio), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = winconsoleio_slots, }; #endif /* HAVE_WINDOWS_CONSOLE_IO */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index b195dab9ccc8..ffe15152448a 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -322,7 +322,6 @@ Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_io/textio.c - PyTextIOBase_Type - -Modules/_io/winconsoleio.c - PyWindowsConsoleIO_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type - From webhook-mailer at python.org Sun May 7 06:12:11 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 07 May 2023 10:12:11 -0000 Subject: [Python-checkins] [3.11] gh-96670: Raise SyntaxError when parsing NULL bytes (GH-97594) (#104195) Message-ID: <mailman.222.1683454331.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a09d3901a5329fd58a29f730ae5f48fb38f66320 commit: a09d3901a5329fd58a29f730ae5f48fb38f66320 branch: 3.11 author: Lysandros Nikolaou <lisandrosnik at gmail.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-07T11:12:04+01:00 summary: [3.11] gh-96670: Raise SyntaxError when parsing NULL bytes (GH-97594) (#104195) files: A Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst M Include/cpython/fileobject.h M Lib/test/test_ast.py M Lib/test/test_builtin.py M Lib/test/test_cmd_line_script.py M Lib/test/test_compile.py M Objects/fileobject.c M Parser/tokenizer.c M Python/pythonrun.c diff --git a/Include/cpython/fileobject.h b/Include/cpython/fileobject.h index cff2243d625e..b70ec318986d 100644 --- a/Include/cpython/fileobject.h +++ b/Include/cpython/fileobject.h @@ -3,6 +3,7 @@ #endif PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); +PyAPI_FUNC(char *) _Py_UniversalNewlineFgetsWithSize(char *, int, FILE*, PyObject *, size_t*); /* The std printer acts as a preliminary sys.stderr until the new io infrastructure is in place. */ diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index b4ec1fef5ade..7d9d0c431a66 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -857,6 +857,10 @@ def check_limit(prefix, repeated): check_limit("a", "[0]") check_limit("a", "*a") + def test_null_bytes(self): + with self.assertRaises(SyntaxError, + msg="source code string cannot contain null bytes"): + ast.parse("a\0b") class ASTHelpers_Test(unittest.TestCase): maxDiff = None diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 0f6d2db0ecb6..9078c409cc44 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -334,11 +334,10 @@ def test_compile(self): self.assertRaises(TypeError, compile) self.assertRaises(ValueError, compile, 'print(42)\n', '<string>', 'badmode') self.assertRaises(ValueError, compile, 'print(42)\n', '<string>', 'single', 0xff) - self.assertRaises(ValueError, compile, chr(0), 'f', 'exec') self.assertRaises(TypeError, compile, 'pass', '?', 'exec', mode='eval', source='0', filename='tmp') compile('print("\xe5")\n', '', 'exec') - self.assertRaises(ValueError, compile, chr(0), 'f', 'exec') + self.assertRaises(SyntaxError, compile, chr(0), 'f', 'exec') self.assertRaises(ValueError, compile, str('a = 1'), 'f', 'bad') # test the optimize argument diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 4dadbc0b64bd..d10012759c37 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -657,6 +657,31 @@ def test_syntaxerror_invalid_escape_sequence_multi_line(self): ], ) + def test_syntaxerror_null_bytes(self): + script = "x = '\0' nothing to see here\n';import os;os.system('echo pwnd')\n" + with os_helper.temp_dir() as script_dir: + script_name = _make_test_script(script_dir, 'script', script) + exitcode, stdout, stderr = assert_python_failure(script_name) + self.assertEqual( + stderr.splitlines()[-2:], + [ b" x = '", + b'SyntaxError: source code cannot contain null bytes' + ], + ) + + def test_syntaxerror_null_bytes_in_multiline_string(self): + scripts = ["\n'''\nmultilinestring\0\n'''", "\nf'''\nmultilinestring\0\n'''"] # Both normal and f-strings + with os_helper.temp_dir() as script_dir: + for script in scripts: + script_name = _make_test_script(script_dir, 'script', script) + _, _, stderr = assert_python_failure(script_name) + self.assertEqual( + stderr.splitlines()[-2:], + [ b" multilinestring", + b'SyntaxError: source code cannot contain null bytes' + ] + ) + def test_consistent_sys_path_for_direct_execution(self): # This test case ensures that the following all give the same # sys.path configuration: diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 54e90663ab51..c96ae4375df8 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -542,7 +542,7 @@ def test_particularly_evil_undecodable(self): with open(fn, "wb") as fp: fp.write(src) res = script_helper.run_python_until_end(fn)[0] - self.assertIn(b"Non-UTF-8", res.err) + self.assertIn(b"source code cannot contain null bytes", res.err) def test_yet_more_evil_still_undecodable(self): # Issue #25388 @@ -552,7 +552,7 @@ def test_yet_more_evil_still_undecodable(self): with open(fn, "wb") as fp: fp.write(src) res = script_helper.run_python_until_end(fn)[0] - self.assertIn(b"Non-UTF-8", res.err) + self.assertIn(b"source code cannot contain null bytes", res.err) @support.cpython_only def test_compiler_recursion_limit(self): @@ -588,9 +588,9 @@ def check_limit(prefix, repeated, mode="single"): def test_null_terminated(self): # The source code is null-terminated internally, but bytes-like # objects are accepted, which could be not terminated. - with self.assertRaisesRegex(ValueError, "cannot contain null"): + with self.assertRaisesRegex(SyntaxError, "cannot contain null"): compile("123\x00", "<dummy>", "eval") - with self.assertRaisesRegex(ValueError, "cannot contain null"): + with self.assertRaisesRegex(SyntaxError, "cannot contain null"): compile(memoryview(b"123\x00"), "<dummy>", "eval") code = compile(memoryview(b"123\x00")[1:-1], "<dummy>", "eval") self.assertEqual(eval(code), 23) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst b/Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst new file mode 100644 index 000000000000..eea90e76ee99 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-09-27-11-59-13.gh-issue-96670.XrBBit.rst @@ -0,0 +1,2 @@ +The parser now raises :exc:`SyntaxError` when parsing source code containing +null bytes. Backported from ``aab01e3``. Patch by Pablo Galindo diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 8dba5b9aea6d..ffe55eb7c373 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -230,16 +230,8 @@ _PyLong_FileDescriptor_Converter(PyObject *o, void *ptr) return 1; } -/* -** Py_UniversalNewlineFgets is an fgets variation that understands -** all of \r, \n and \r\n conventions. -** The stream should be opened in binary mode. -** The fobj parameter exists solely for legacy reasons and must be NULL. -** Note that we need no error handling: fgets() treats error and eof -** identically. -*/ char * -Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) +_Py_UniversalNewlineFgetsWithSize(char *buf, int n, FILE *stream, PyObject *fobj, size_t* size) { char *p = buf; int c; @@ -265,11 +257,28 @@ Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) } FUNLOCKFILE(stream); *p = '\0'; - if (p == buf) + if (p == buf) { return NULL; + } + *size = p - buf; return buf; } +/* +** Py_UniversalNewlineFgets is an fgets variation that understands +** all of \r, \n and \r\n conventions. +** The stream should be opened in binary mode. +** The fobj parameter exists solely for legacy reasons and must be NULL. +** Note that we need no error handling: fgets() treats error and eof +** identically. +*/ + +char * +Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) { + size_t size; + return _Py_UniversalNewlineFgetsWithSize(buf, n, stream, fobj, &size); +} + /* **************************** std printer **************************** * The stdprinter is used during the boot strapping phase as a preliminary * file like object for sys.stderr. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index ca11c7bebb4e..b552b4171888 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -376,6 +376,11 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size) return 1; } +static inline int +contains_null_bytes(const char* str, size_t size) { + return memchr(str, 0, size) != NULL; +} + static int tok_readline_recode(struct tok_state *tok) { PyObject *line; @@ -831,9 +836,9 @@ tok_readline_raw(struct tok_state *tok) if (!tok_reserve_buf(tok, BUFSIZ)) { return 0; } - char *line = Py_UniversalNewlineFgets(tok->inp, - (int)(tok->end - tok->inp), - tok->fp, NULL); + int n_chars = (int)(tok->end - tok->inp); + size_t line_size = 0; + char *line = _Py_UniversalNewlineFgetsWithSize(tok->inp, n_chars, tok->fp, NULL, &line_size); if (line == NULL) { return 1; } @@ -841,7 +846,7 @@ tok_readline_raw(struct tok_state *tok) tok_concatenate_interactive_new_line(tok, line) == -1) { return 0; } - tok->inp = strchr(tok->inp, '\0'); + tok->inp += line_size; if (tok->inp == tok->buf) { return 0; } @@ -1078,6 +1083,12 @@ tok_nextc(struct tok_state *tok) return EOF; } tok->line_start = tok->cur; + + if (contains_null_bytes(tok->line_start, tok->inp - tok->line_start)) { + syntaxerror(tok, "source code cannot contain null bytes"); + tok->cur = tok->inp; + return EOF; + } } Py_UNREACHABLE(); } @@ -1987,8 +1998,12 @@ tok_get(struct tok_state *tok, const char **p_start, const char **p_end) /* Get rest of string */ while (end_quote_size != quote_size) { c = tok_nextc(tok); - if (tok->done == E_DECODE) + if (tok->done == E_ERROR) { + return ERRORTOKEN; + } + if (tok->done == E_DECODE) { break; + } if (c == EOF || (quote_size == 1 && c == '\n')) { assert(tok->multi_line_start != NULL); // shift the tok_state's location into diff --git a/Python/pythonrun.c b/Python/pythonrun.c index f12b9f6e9539..efa22b07256c 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1859,7 +1859,7 @@ _Py_SourceAsString(PyObject *cmd, const char *funcname, const char *what, PyComp } if (strlen(str) != (size_t)size) { - PyErr_SetString(PyExc_ValueError, + PyErr_SetString(PyExc_SyntaxError, "source code string cannot contain null bytes"); Py_CLEAR(*cmd_copy); return NULL; From webhook-mailer at python.org Sun May 7 06:55:38 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 07 May 2023 10:55:38 -0000 Subject: [Python-checkins] gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bit builds (#103902) Message-ID: <mailman.223.1683456939.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a05bad3254e2ae5fdf558dfdb65899a2298d8ded commit: a05bad3254e2ae5fdf558dfdb65899a2298d8ded branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-07T12:55:31+02:00 summary: gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bit builds (#103902) files: A Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst M Lib/test/test_sqlite3/test_dbapi.py M Modules/_sqlite/clinic/connection.c.h M Modules/_sqlite/connection.c diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 1bb0e13e356e..328b0467e7fa 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1495,6 +1495,14 @@ def test_blob_closed_db_read(self): "Cannot operate on a closed database", blob.read) + def test_blob_32bit_rowid(self): + # gh-100370: we should not get an OverflowError for 32-bit rowids + with memory_database() as cx: + rowid = 2**32 + cx.execute("create table t(t blob)") + cx.execute("insert into t(rowid, t) values (?, zeroblob(1))", (rowid,)) + cx.blobopen('t', 't', rowid) + @threading_helper.requires_working_threading() class ThreadTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst new file mode 100644 index 000000000000..9022d55c48cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst @@ -0,0 +1,2 @@ +Fix potential :exc:`OverflowError` in :meth:`sqlite3.Connection.blobopen` +for 32-bit builds. Patch by Erlend E. Aasland. diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index 182754cca36d..417abcc46261 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -228,7 +228,7 @@ PyDoc_STRVAR(blobopen__doc__, static PyObject * blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, - int row, int readonly, const char *name); + sqlite3_int64 row, int readonly, const char *name); static PyObject * blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -263,7 +263,7 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; const char *table; const char *col; - int row; + sqlite3_int64 row; int readonly = 0; const char *name = "main"; @@ -297,8 +297,7 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - row = _PyLong_AsInt(args[2]); - if (row == -1 && PyErr_Occurred()) { + if (!sqlite3_int64_converter(args[2], &row)) { goto exit; } if (!noptargs) { @@ -1666,4 +1665,4 @@ getconfig(pysqlite_Connection *self, PyObject *arg) #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=8b03149c115ee6da input=a9049054013a1b77]*/ +/*[clinic end generated code: output=834a99827555bf1a input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index aec3aa8bbf4e..7bbb462ed54d 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -118,6 +118,20 @@ autocommit_converter(PyObject *val, enum autocommit_mode *result) return 0; } +static int +sqlite3_int64_converter(PyObject *obj, sqlite3_int64 *result) +{ + if (!PyLong_Check(obj)) { + PyErr_SetString(PyExc_TypeError, "expected 'int'"); + return 0; + } + *result = _pysqlite_long_as_int64(obj); + if (PyErr_Occurred()) { + return 0; + } + return 1; +} + #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self))) #include "clinic/connection.c.h" #undef clinic_state @@ -188,8 +202,12 @@ class Autocommit_converter(CConverter): type = "enum autocommit_mode" converter = "autocommit_converter" +class sqlite3_int64_converter(CConverter): + type = "sqlite3_int64" + converter = "sqlite3_int64_converter" + [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=bc2aa6c7ba0c5f8f]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=dff8760fb1eba6a1]*/ // NB: This needs to be in sync with the sqlite3.connect docstring /*[clinic input] @@ -483,7 +501,7 @@ _sqlite3.Connection.blobopen as blobopen Table name. column as col: str Column name. - row: int + row: sqlite3_int64 Row index. / * @@ -497,8 +515,8 @@ Open and return a BLOB object. static PyObject * blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, - int row, int readonly, const char *name) -/*[clinic end generated code: output=0c8e2e58516d0b5c input=fa73c83aa7a7ddee]*/ + sqlite3_int64 row, int readonly, const char *name) +/*[clinic end generated code: output=6a02d43efb885d1c input=23576bd1108d8774]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; From webhook-mailer at python.org Sun May 7 07:22:20 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 07 May 2023 11:22:20 -0000 Subject: [Python-checkins] [3.11] gh-103225: Fixed zero lineno issue for pdb (#103265) (#104262) Message-ID: <mailman.224.1683458541.13550.python-checkins@python.org> https://github.com/python/cpython/commit/19abf691fe1d59a58882c09e9624fb1ffb910e57 commit: 19abf691fe1d59a58882c09e9624fb1ffb910e57 branch: 3.11 author: Tian Gao <gaogaotiantian at hotmail.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-07T12:21:57+01:00 summary: [3.11] gh-103225: Fixed zero lineno issue for pdb (#103265) (#104262) gh-103225: Fixed zero lineno issue for pdb (#103265) Co-authored-by: Artem Mukhin <ortem00 at gmail.com> 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 f9c5bee4c06c..d3824e19fa82 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1348,7 +1348,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 @@ -1364,7 +1364,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 @@ -1643,6 +1643,16 @@ def _run(self, target: Union[_ModuleTarget, _ScriptTarget]): self.run(target.code) + 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 9328ccaf3bce..4f4a56922803 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1673,6 +1673,32 @@ def test_pdb_issue_gh_101517(): (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 + > <doctest test.test_pdb.test_pdb_issue_gh_103225[0]>(7)<module>() + -> 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): def tearDown(self): 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 Sun May 7 10:01:34 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 07 May 2023 14:01:34 -0000 Subject: [Python-checkins] gh-101819: Port _io.PyBytesIOBuffer_Type to heap type (#104264) Message-ID: <mailman.225.1683468096.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7a7eaff95c7a400449822bbabd94524b8f87299c commit: 7a7eaff95c7a400449822bbabd94524b8f87299c branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-07T14:01:27Z summary: gh-101819: Port _io.PyBytesIOBuffer_Type to heap type (#104264) files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/bytesio.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index b72b847c6634..c05407b5d618 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -671,9 +671,6 @@ static PyTypeObject* static_types[] = { &PyBufferedIOBase_Type, &PyRawIOBase_Type, &PyTextIOBase_Type, - - // PyRawIOBase_Type(PyIOBase_Type) subclasses - &_PyBytesIOBuffer_Type, }; @@ -753,6 +750,7 @@ PyInit__io(void) // Base classes ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); + ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); // PyIOBase_Type subclasses state->PyRawIOBase_Type = (PyTypeObject *)Py_NewRef(&PyRawIOBase_Type); @@ -771,7 +769,6 @@ PyInit__io(void) state->PyBufferedIOBase_Type); // PyRawIOBase_Type(PyIOBase_Type) subclasses - state->PyBytesIOBuffer_Type = (PyTypeObject *)Py_NewRef(&_PyBytesIOBuffer_Type); ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); #ifdef MS_WINDOWS ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 00e6a19db2b8..1bf301c9cf0a 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -20,6 +20,7 @@ extern PyType_Spec bufferedreader_spec; extern PyType_Spec bufferedrwpair_spec; extern PyType_Spec bufferedwriter_spec; extern PyType_Spec bytesio_spec; +extern PyType_Spec bytesiobuf_spec; extern PyType_Spec fileio_spec; extern PyType_Spec nldecoder_spec; extern PyType_Spec stringio_spec; @@ -194,5 +195,3 @@ extern _PyIO_State *_PyIO_get_module_state(void); #ifdef HAVE_WINDOWS_CONSOLE_IO extern char _PyIO_get_console_type(PyObject *); #endif - -extern Py_EXPORTED_SYMBOL PyTypeObject _PyBytesIOBuffer_Type; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 9c7a28357987..3fddfc2ed0bc 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1090,9 +1090,17 @@ bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view) b->exports--; } +static int +bytesiobuf_clear(bytesiobuf *self) +{ + Py_CLEAR(self->source); + return 0; +} + static int bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->source); return 0; } @@ -1100,54 +1108,29 @@ bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg) static void bytesiobuf_dealloc(bytesiobuf *self) { + PyTypeObject *tp = Py_TYPE(self); /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(self); - Py_CLEAR(self->source); - Py_TYPE(self)->tp_free(self); + (void)bytesiobuf_clear(self); + tp->tp_free(self); + Py_DECREF(tp); } -static PyBufferProcs bytesiobuf_as_buffer = { - (getbufferproc) bytesiobuf_getbuffer, - (releasebufferproc) bytesiobuf_releasebuffer, +static PyType_Slot bytesiobuf_slots[] = { + {Py_tp_dealloc, bytesiobuf_dealloc}, + {Py_tp_traverse, bytesiobuf_traverse}, + {Py_tp_clear, bytesiobuf_clear}, + + // Buffer protocol + {Py_bf_getbuffer, bytesiobuf_getbuffer}, + {Py_bf_releasebuffer, bytesiobuf_releasebuffer}, + {0, NULL}, }; -Py_EXPORTED_SYMBOL PyTypeObject _PyBytesIOBuffer_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._BytesIOBuffer", /*tp_name*/ - sizeof(bytesiobuf), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)bytesiobuf_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*/ - &bytesiobuf_as_buffer, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - (traverseproc)bytesiobuf_traverse, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*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*/ - 0, /*tp_new*/ +PyType_Spec bytesiobuf_spec = { + .name = "_io._BytesIOBuffer", + .basicsize = sizeof(bytesiobuf), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), + .slots = bytesiobuf_slots, }; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index ffe15152448a..453f63ec3f1c 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -318,7 +318,6 @@ Python/instrumentation.c - _PyInstrumentation_MISSING - ## static types Modules/_io/bufferedio.c - PyBufferedIOBase_Type - -Modules/_io/bytesio.c - _PyBytesIOBuffer_Type - Modules/_io/iobase.c - PyIOBase_Type - Modules/_io/iobase.c - PyRawIOBase_Type - Modules/_io/textio.c - PyTextIOBase_Type - From webhook-mailer at python.org Sun May 7 12:54:47 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 07 May 2023 16:54:47 -0000 Subject: [Python-checkins] GH-100479: Fix pathlib test failure on WASI (#104215) Message-ID: <mailman.226.1683478487.13550.python-checkins@python.org> https://github.com/python/cpython/commit/60f588478f0a3d88e86b97acecbcb569142f4636 commit: 60f588478f0a3d88e86b97acecbcb569142f4636 branch: main author: Barney Gale <barney.gale at gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-07T17:54:40+01:00 summary: GH-100479: Fix pathlib test failure on WASI (#104215) files: M Lib/test/test_pathlib.py diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 7586610833b0..e25c77f2ba8a 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1655,7 +1655,8 @@ class P(_BasePurePathSubclass, self.cls): p = P(BASE, session_id=42) self.assertEqual(42, p.absolute().session_id) self.assertEqual(42, p.resolve().session_id) - self.assertEqual(42, p.with_segments('~').expanduser().session_id) + if not is_wasi: # WASI has no user accounts. + self.assertEqual(42, p.with_segments('~').expanduser().session_id) self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id) self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id) if os_helper.can_symlink(): From webhook-mailer at python.org Sun May 7 13:45:19 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 07 May 2023 17:45:19 -0000 Subject: [Python-checkins] gh-103193: cache calls to `inspect._shadowed_dict` in `inspect.getattr_static` (#104267) Message-ID: <mailman.227.1683481520.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1b19bd1a88e6c410fc9cd08db48e0d35cfa8bb5a commit: 1b19bd1a88e6c410fc9cd08db48e0d35cfa8bb5a branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-07T18:45:09+01:00 summary: gh-103193: cache calls to `inspect._shadowed_dict` in `inspect.getattr_static` (#104267) Co-authored-by: Carl Meyer <carl at oddbird.net> files: M Doc/whatsnew/3.12.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ec04178238b6..65b3e9ffb807 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -342,8 +342,9 @@ inspect (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`.) + improved. Most calls to the function should be at least 2x faster than they + were in Python 3.11, and some may be 6x faster or more. (Contributed by Alex + Waygood in :gh:`103193`.) pathlib ------- @@ -597,7 +598,7 @@ typing :func:`runtime-checkable protocols <typing.runtime_checkable>` 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 + faster or more. However, ``isinstance()`` checks against protocols with fourteen or more members may be slower than in Python 3.11. (Contributed by Alex Waygood in :gh:`74690` and :gh:`103193`.) diff --git a/Lib/inspect.py b/Lib/inspect.py index 95da7fb71a39..a64e85e4fd67 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1794,8 +1794,9 @@ def _check_class(klass, attr): return entry.__dict__[attr] return _sentinel -def _shadowed_dict(klass): - for entry in _static_getmro(klass): + at functools.lru_cache() +def _shadowed_dict_from_mro_tuple(mro): + for entry in mro: dunder_dict = _get_dunder_dict_of_class(entry) if '__dict__' in dunder_dict: class_dict = dunder_dict['__dict__'] @@ -1805,6 +1806,9 @@ def _shadowed_dict(klass): return class_dict return _sentinel +def _shadowed_dict(klass): + return _shadowed_dict_from_mro_tuple(_static_getmro(klass)) + def getattr_static(obj, attr, default=_sentinel): """Retrieve attributes without triggering dynamic lookup via the descriptor protocol, __getattr__ or __getattribute__. diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 42e3d709bd68..dd0325a43e0f 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2111,6 +2111,28 @@ def __dict__(self): self.assertEqual(inspect.getattr_static(foo, 'a'), 3) self.assertFalse(test.called) + def test_mutated_mro(self): + test = self + test.called = False + + class Foo(dict): + a = 3 + @property + def __dict__(self): + test.called = True + return {} + + class Bar(dict): + a = 4 + + class Baz(Bar): pass + + baz = Baz() + self.assertEqual(inspect.getattr_static(baz, 'a'), 4) + Baz.__bases__ = (Foo,) + self.assertEqual(inspect.getattr_static(baz, 'a'), 3) + self.assertFalse(test.called) + def test_custom_object_dict(self): test = self test.called = False From webhook-mailer at python.org Sun May 7 13:47:35 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 07 May 2023 17:47:35 -0000 Subject: [Python-checkins] gh-104240: make _PyCompile_CodeGen support different compilation modes (#104241) Message-ID: <mailman.228.1683481655.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2c2dc61e8d01f44e5b7e63dd99196460a80905f1 commit: 2c2dc61e8d01f44e5b7e63dd99196460a80905f1 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-07T18:47:28+01:00 summary: gh-104240: make _PyCompile_CodeGen support different compilation modes (#104241) files: M Include/internal/pycore_compile.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/test/test_compiler_codegen.py M Modules/_testinternalcapi.c M Modules/clinic/_testinternalcapi.c.h M Python/compile.c diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 4bd4ef57238f..d2b12c91fe7a 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -97,7 +97,8 @@ PyAPI_FUNC(PyObject*) _PyCompile_CodeGen( PyObject *ast, PyObject *filename, PyCompilerFlags *flags, - int optimize); + int optimize, + int compile_mode); PyAPI_FUNC(PyObject*) _PyCompile_OptimizeCfg( PyObject *instructions, diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 9377fd8526e3..7e495817981f 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -847,6 +847,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(code)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(command)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(comment_factory)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(compile_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(consts)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(context)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cookie)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index ed9b2bb44ddf..8ebfee85c87c 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -335,6 +335,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(code) STRUCT_FOR_ID(command) STRUCT_FOR_ID(comment_factory) + STRUCT_FOR_ID(compile_mode) STRUCT_FOR_ID(consts) STRUCT_FOR_ID(context) STRUCT_FOR_ID(cookie) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 6ade8fb6eade..7b9c73dd1edf 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -841,6 +841,7 @@ extern "C" { INIT_ID(code), \ INIT_ID(command), \ INIT_ID(comment_factory), \ + INIT_ID(compile_mode), \ INIT_ID(consts), \ INIT_ID(context), \ INIT_ID(cookie), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 0b33ea187e60..8e086edbdf81 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -858,6 +858,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(comment_factory); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(compile_mode); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(consts); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py index 022753e0c994..ea57df9cd240 100644 --- a/Lib/test/test_compiler_codegen.py +++ b/Lib/test/test_compiler_codegen.py @@ -25,6 +25,8 @@ def test_if_expression(self): ('LOAD_CONST', 2, 1), exit_lbl, ('POP_TOP', None), + ('LOAD_CONST', 3), + ('RETURN_VALUE', None), ] self.codegen_test(snippet, expected) @@ -46,5 +48,7 @@ def test_for_loop(self): ('JUMP', loop_lbl), exit_lbl, ('END_FOR', None), + ('LOAD_CONST', 0), + ('RETURN_VALUE', None), ] self.codegen_test(snippet, expected) diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index f35e3b48df93..40ad6f88868d 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -593,17 +593,19 @@ _testinternalcapi.compiler_codegen -> object ast: object filename: object optimize: int + compile_mode: int = 0 Apply compiler code generation to an AST. [clinic start generated code]*/ static PyObject * _testinternalcapi_compiler_codegen_impl(PyObject *module, PyObject *ast, - PyObject *filename, int optimize) -/*[clinic end generated code: output=fbbbbfb34700c804 input=e9fbe6562f7f75e4]*/ + PyObject *filename, int optimize, + int compile_mode) +/*[clinic end generated code: output=40a68f6e13951cc8 input=a0e00784f1517cd7]*/ { PyCompilerFlags *flags = NULL; - return _PyCompile_CodeGen(ast, filename, flags, optimize); + return _PyCompile_CodeGen(ast, filename, flags, optimize, compile_mode); } diff --git a/Modules/clinic/_testinternalcapi.c.h b/Modules/clinic/_testinternalcapi.c.h index 895732225725..41dd50437956 100644 --- a/Modules/clinic/_testinternalcapi.c.h +++ b/Modules/clinic/_testinternalcapi.c.h @@ -9,7 +9,7 @@ preserve PyDoc_STRVAR(_testinternalcapi_compiler_codegen__doc__, -"compiler_codegen($module, /, ast, filename, optimize)\n" +"compiler_codegen($module, /, ast, filename, optimize, compile_mode=0)\n" "--\n" "\n" "Apply compiler code generation to an AST."); @@ -19,7 +19,8 @@ PyDoc_STRVAR(_testinternalcapi_compiler_codegen__doc__, static PyObject * _testinternalcapi_compiler_codegen_impl(PyObject *module, PyObject *ast, - PyObject *filename, int optimize); + PyObject *filename, int optimize, + int compile_mode); static PyObject * _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -27,14 +28,14 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 3 + #define NUM_KEYWORDS 4 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(ast), &_Py_ID(filename), &_Py_ID(optimize), }, + .ob_item = { &_Py_ID(ast), &_Py_ID(filename), &_Py_ID(optimize), &_Py_ID(compile_mode), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -43,19 +44,21 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"ast", "filename", "optimize", NULL}; + static const char * const _keywords[] = {"ast", "filename", "optimize", "compile_mode", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "compiler_codegen", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[3]; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; PyObject *ast; PyObject *filename; int optimize; + int compile_mode = 0; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 4, 0, argsbuf); if (!args) { goto exit; } @@ -65,7 +68,15 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s if (optimize == -1 && PyErr_Occurred()) { goto exit; } - return_value = _testinternalcapi_compiler_codegen_impl(module, ast, filename, optimize); + if (!noptargs) { + goto skip_optional_pos; + } + compile_mode = _PyLong_AsInt(args[3]); + if (compile_mode == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_pos: + return_value = _testinternalcapi_compiler_codegen_impl(module, ast, filename, optimize, compile_mode); exit: return return_value; @@ -190,4 +201,4 @@ _testinternalcapi_assemble_code_object(PyObject *module, PyObject *const *args, exit: return return_value; } -/*[clinic end generated code: output=d5e08c9d67f9721f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ab661d56a14b1a1c input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index cbe5403aafbc..f875e4e17e0a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7258,7 +7258,7 @@ cfg_to_instructions(cfg_builder *g) PyObject * _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, - int optimize) + int optimize, int compile_mode) { PyObject *res = NULL; @@ -7272,7 +7272,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, return NULL; } - mod_ty mod = PyAST_obj2mod(ast, arena, 0 /* exec */); + mod_ty mod = PyAST_obj2mod(ast, arena, compile_mode); if (mod == NULL || !_PyAST_Validate(mod)) { _PyArena_Free(arena); return NULL; @@ -7287,6 +7287,10 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, if (compiler_codegen(c, mod) < 0) { goto finally; } + int addNone = mod->kind != Expression_kind; + if (add_return_at_end(c, addNone) < 0) { + return NULL; + } res = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); From webhook-mailer at python.org Sun May 7 15:07:47 2023 From: webhook-mailer at python.org (barneygale) Date: Sun, 07 May 2023 19:07:47 -0000 Subject: [Python-checkins] GH-89812: Churn `pathlib.Path` methods (GH-104243) Message-ID: <mailman.229.1683486468.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e8d77b03e08a4c7e7dde0830c5a12a0b41ff7c33 commit: e8d77b03e08a4c7e7dde0830c5a12a0b41ff7c33 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-07T20:07:07+01:00 summary: GH-89812: Churn `pathlib.Path` methods (GH-104243) Re-arrange `pathlib.Path` methods in source code. No other changes. The methods are arranged as follows: 1. `stat()` and dependants (`exists()`, `is_dir()`, etc) 2. `open()` and dependants (`read_text()`, `write_bytes()`, etc) 3. `iterdir()` and dependants (`glob()`, `walk()`, etc) 4. All other `Path` methods This patch prepares the ground for a new `_AbstractPath` class, which will support the methods in groups 1, 2 and 3 above. By churning the methods here, subsequent patches will be easier to review and less likely to break things. files: M Lib/pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 480c354ce8b6..68255aa3e511 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -740,68 +740,164 @@ class Path(PurePath): """ __slots__ = () - 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 stat(self, *, follow_symlinks=True): + """ + Return the result of the stat() system call on this path, like + os.stat() does. + """ + return os.stat(self, follow_symlinks=follow_symlinks) - def __new__(cls, *args, **kwargs): - if cls is Path: - cls = WindowsPath if os.name == 'nt' else PosixPath - return object.__new__(cls) + def lstat(self): + """ + Like stat(), except if the path points to a symlink, the symlink's + status information is returned, rather than its target's. + """ + return self.stat(follow_symlinks=False) - 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 = self.with_segments(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 - # closed; subsequent attempts to perform I/O would raise an IOError. - # This functionality was never documented, and had the effect of - # making Path objects mutable, contrary to PEP 428. - # In Python 3.9 __exit__() was made a no-op. - # In Python 3.11 __enter__() began emitting DeprecationWarning. - # In Python 3.13 __enter__() and __exit__() should be removed. - warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " - "for removal in Python 3.13; Path objects as a context " - "manager is a no-op", - DeprecationWarning, stacklevel=2) - return self + # Convenience functions for querying the stat results - def __exit__(self, t, v, tb): - pass + def exists(self, *, follow_symlinks=True): + """ + Whether this path exists. - # Public API + This method normally follows symlinks; to check whether a symlink exists, + add the argument follow_symlinks=False. + """ + try: + self.stat(follow_symlinks=follow_symlinks) + except OSError as e: + if not _ignore_error(e): + raise + return False + except ValueError: + # Non-encodable path + return False + return True - @classmethod - def cwd(cls): - """Return a new path pointing to the current working directory.""" - # We call 'absolute()' rather than using 'os.getcwd()' directly to - # enable users to replace the implementation of 'absolute()' in a - # subclass and benefit from the new behaviour here. This works because - # os.path.abspath('.') == os.getcwd(). - return cls().absolute() + def is_dir(self): + """ + Whether this path is a directory. + """ + try: + return S_ISDIR(self.stat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist or is a broken symlink + # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) + return False + except ValueError: + # Non-encodable path + return False - @classmethod - def home(cls): - """Return a new path pointing to the user's home directory (as - returned by os.path.expanduser('~')). + def is_file(self): """ - return cls("~").expanduser() + Whether this path is a regular file (also True for symlinks pointing + to regular files). + """ + try: + return S_ISREG(self.stat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist or is a broken symlink + # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) + return False + except ValueError: + # Non-encodable path + return False + + def is_mount(self): + """ + Check if this path is a mount point + """ + return self._flavour.ismount(self) + + def is_symlink(self): + """ + Whether this path is a symbolic link. + """ + try: + return S_ISLNK(self.lstat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist + return False + except ValueError: + # Non-encodable path + return False + + def is_junction(self): + """ + Whether this path is a junction. + """ + return self._flavour.isjunction(self) + + def is_block_device(self): + """ + Whether this path is a block device. + """ + try: + return S_ISBLK(self.stat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist or is a broken symlink + # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) + return False + except ValueError: + # Non-encodable path + return False + + def is_char_device(self): + """ + Whether this path is a character device. + """ + try: + return S_ISCHR(self.stat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist or is a broken symlink + # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) + return False + except ValueError: + # Non-encodable path + return False + + def is_fifo(self): + """ + Whether this path is a FIFO. + """ + try: + return S_ISFIFO(self.stat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist or is a broken symlink + # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) + return False + except ValueError: + # Non-encodable path + return False + + def is_socket(self): + """ + Whether this path is a socket. + """ + try: + return S_ISSOCK(self.stat().st_mode) + except OSError as e: + if not _ignore_error(e): + raise + # Path doesn't exist or is a broken symlink + # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) + return False + except ValueError: + # Non-encodable path + return False def samefile(self, other_path): """Return whether other_path is the same or not as this file @@ -814,6 +910,51 @@ def samefile(self, other_path): other_st = self.with_segments(other_path).stat() return self._flavour.samestat(st, other_st) + def open(self, mode='r', buffering=-1, encoding=None, + errors=None, newline=None): + """ + Open the file pointed by this path and return a file object, as + the built-in open() function does. + """ + if "b" not in mode: + encoding = io.text_encoding(encoding) + return io.open(self, mode, buffering, encoding, errors, newline) + + def read_bytes(self): + """ + Open the file in bytes mode, read it, and close the file. + """ + with self.open(mode='rb') as f: + return f.read() + + def read_text(self, encoding=None, errors=None): + """ + Open the file in text mode, read it, and close the file. + """ + encoding = io.text_encoding(encoding) + with self.open(mode='r', encoding=encoding, errors=errors) as f: + return f.read() + + def write_bytes(self, data): + """ + Open the file in bytes mode, write to it, and close the file. + """ + # type-check for the buffer interface before truncating the file + view = memoryview(data) + with self.open(mode='wb') as f: + return f.write(view) + + def write_text(self, data, encoding=None, errors=None, newline=None): + """ + Open the file in text mode, write to it, and close the file. + """ + if not isinstance(data, str): + raise TypeError('data must be str, not %s' % + data.__class__.__name__) + encoding = io.text_encoding(encoding) + with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: + return f.write(data) + def iterdir(self): """Yield path objects of the directory contents. @@ -829,6 +970,22 @@ def _scandir(self): # includes scandir(), which is used to implement glob(). return os.scandir(self) + 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 = self.with_segments(path_str) + path._str = path_str + path._drv = self.drive + path._root = self.root + path._tail_cached = tail + [name] + return path + def glob(self, pattern, *, case_sensitive=None): """Iterate over this subtree and yield all existing files (of any kind, including directories) matching the given relative pattern. @@ -860,6 +1017,98 @@ def rglob(self, pattern, *, case_sensitive=None): for p in selector.select_from(self): yield p + def walk(self, top_down=True, on_error=None, follow_symlinks=False): + """Walk the directory tree from this directory, similar to os.walk().""" + sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) + paths = [self] + + while paths: + path = paths.pop() + if isinstance(path, tuple): + yield path + continue + + # We may not have read permission for self, in which case we can't + # get a list of the files the directory contains. os.walk() + # always suppressed the exception in that instance, rather than + # blow up for a minor reason when (say) a thousand readable + # directories are still left to visit. That logic is copied here. + try: + scandir_it = path._scandir() + except OSError as error: + if on_error is not None: + on_error(error) + continue + + with scandir_it: + dirnames = [] + filenames = [] + for entry in scandir_it: + try: + is_dir = entry.is_dir(follow_symlinks=follow_symlinks) + except OSError: + # Carried over from os.path.isdir(). + is_dir = False + + if is_dir: + dirnames.append(entry.name) + else: + filenames.append(entry.name) + + if top_down: + yield path, dirnames, filenames + else: + paths.append((path, dirnames, filenames)) + + paths += [path._make_child_relpath(d) for d in reversed(dirnames)] + + 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 object.__new__(cls) + + def __enter__(self): + # In previous versions of pathlib, __exit__() marked this path as + # closed; subsequent attempts to perform I/O would raise an IOError. + # This functionality was never documented, and had the effect of + # making Path objects mutable, contrary to PEP 428. + # In Python 3.9 __exit__() was made a no-op. + # In Python 3.11 __enter__() began emitting DeprecationWarning. + # In Python 3.13 __enter__() and __exit__() should be removed. + warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " + "for removal in Python 3.13; Path objects as a context " + "manager is a no-op", + DeprecationWarning, stacklevel=2) + return self + + def __exit__(self, t, v, tb): + pass + + # Public API + + @classmethod + def cwd(cls): + """Return a new path pointing to the current working directory.""" + # We call 'absolute()' rather than using 'os.getcwd()' directly to + # enable users to replace the implementation of 'absolute()' in a + # subclass and benefit from the new behaviour here. This works because + # os.path.abspath('.') == os.getcwd(). + return cls().absolute() + + @classmethod + def home(cls): + """Return a new path pointing to the user's home directory (as + returned by os.path.expanduser('~')). + """ + return cls("~").expanduser() + def absolute(self): """Return an absolute version of this path by prepending the current working directory. No normalization or symlink resolution is performed. @@ -911,13 +1160,6 @@ def check_eloop(e): check_eloop(e) return p - def stat(self, *, follow_symlinks=True): - """ - Return the result of the stat() system call on this path, like - os.stat() does. - """ - return os.stat(self, follow_symlinks=follow_symlinks) - def owner(self): """ Return the login name of the file owner. @@ -939,51 +1181,6 @@ def group(self): except ImportError: raise NotImplementedError("Path.group() is unsupported on this system") - def open(self, mode='r', buffering=-1, encoding=None, - errors=None, newline=None): - """ - Open the file pointed by this path and return a file object, as - the built-in open() function does. - """ - if "b" not in mode: - encoding = io.text_encoding(encoding) - return io.open(self, mode, buffering, encoding, errors, newline) - - def read_bytes(self): - """ - Open the file in bytes mode, read it, and close the file. - """ - with self.open(mode='rb') as f: - return f.read() - - def read_text(self, encoding=None, errors=None): - """ - Open the file in text mode, read it, and close the file. - """ - encoding = io.text_encoding(encoding) - with self.open(mode='r', encoding=encoding, errors=errors) as f: - return f.read() - - def write_bytes(self, data): - """ - Open the file in bytes mode, write to it, and close the file. - """ - # type-check for the buffer interface before truncating the file - view = memoryview(data) - with self.open(mode='wb') as f: - return f.write(view) - - def write_text(self, data, encoding=None, errors=None, newline=None): - """ - Open the file in text mode, write to it, and close the file. - """ - if not isinstance(data, str): - raise TypeError('data must be str, not %s' % - data.__class__.__name__) - encoding = io.text_encoding(encoding) - with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f: - return f.write(data) - def readlink(self): """ Return the path to which the symbolic link points. @@ -1061,13 +1258,6 @@ def rmdir(self): """ os.rmdir(self) - def lstat(self): - """ - Like stat(), except if the path points to a symlink, the symlink's - status information is returned, rather than its target's. - """ - return self.stat(follow_symlinks=False) - def rename(self, target): """ Rename this path to the target path. @@ -1113,151 +1303,6 @@ def hardlink_to(self, target): raise NotImplementedError("os.link() not available on this system") os.link(target, self) - - # Convenience functions for querying the stat results - - def exists(self, *, follow_symlinks=True): - """ - Whether this path exists. - - This method normally follows symlinks; to check whether a symlink exists, - add the argument follow_symlinks=False. - """ - try: - self.stat(follow_symlinks=follow_symlinks) - except OSError as e: - if not _ignore_error(e): - raise - return False - except ValueError: - # Non-encodable path - return False - return True - - def is_dir(self): - """ - Whether this path is a directory. - """ - try: - return S_ISDIR(self.stat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist or is a broken symlink - # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) - return False - except ValueError: - # Non-encodable path - return False - - def is_file(self): - """ - Whether this path is a regular file (also True for symlinks pointing - to regular files). - """ - try: - return S_ISREG(self.stat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist or is a broken symlink - # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) - return False - except ValueError: - # Non-encodable path - return False - - def is_mount(self): - """ - Check if this path is a mount point - """ - return self._flavour.ismount(self) - - def is_symlink(self): - """ - Whether this path is a symbolic link. - """ - try: - return S_ISLNK(self.lstat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist - return False - except ValueError: - # Non-encodable path - return False - - def is_junction(self): - """ - Whether this path is a junction. - """ - return self._flavour.isjunction(self) - - def is_block_device(self): - """ - Whether this path is a block device. - """ - try: - return S_ISBLK(self.stat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist or is a broken symlink - # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) - return False - except ValueError: - # Non-encodable path - return False - - def is_char_device(self): - """ - Whether this path is a character device. - """ - try: - return S_ISCHR(self.stat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist or is a broken symlink - # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) - return False - except ValueError: - # Non-encodable path - return False - - def is_fifo(self): - """ - Whether this path is a FIFO. - """ - try: - return S_ISFIFO(self.stat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist or is a broken symlink - # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) - return False - except ValueError: - # Non-encodable path - return False - - def is_socket(self): - """ - Whether this path is a socket. - """ - try: - return S_ISSOCK(self.stat().st_mode) - except OSError as e: - if not _ignore_error(e): - raise - # Path doesn't exist or is a broken symlink - # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ ) - return False - except ValueError: - # Non-encodable path - return False - def expanduser(self): """ Return a new path with expanded ~ and ~user constructs (as returned by os.path.expanduser) @@ -1272,51 +1317,6 @@ def expanduser(self): return self - def walk(self, top_down=True, on_error=None, follow_symlinks=False): - """Walk the directory tree from this directory, similar to os.walk().""" - sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) - paths = [self] - - while paths: - path = paths.pop() - if isinstance(path, tuple): - yield path - continue - - # We may not have read permission for self, in which case we can't - # get a list of the files the directory contains. os.walk() - # always suppressed the exception in that instance, rather than - # blow up for a minor reason when (say) a thousand readable - # directories are still left to visit. That logic is copied here. - try: - scandir_it = path._scandir() - except OSError as error: - if on_error is not None: - on_error(error) - continue - - with scandir_it: - dirnames = [] - filenames = [] - for entry in scandir_it: - try: - is_dir = entry.is_dir(follow_symlinks=follow_symlinks) - except OSError: - # Carried over from os.path.isdir(). - is_dir = False - - if is_dir: - dirnames.append(entry.name) - else: - filenames.append(entry.name) - - if top_down: - yield path, dirnames, filenames - else: - paths.append((path, dirnames, filenames)) - - paths += [path._make_child_relpath(d) for d in reversed(dirnames)] - class PosixPath(Path, PurePosixPath): """Path subclass for non-Windows systems. From webhook-mailer at python.org Sun May 7 15:42:50 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 07 May 2023 19:42:50 -0000 Subject: [Python-checkins] gh-103650: Fix perf maps address format (#103651) Message-ID: <mailman.230.1683488571.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8d95012c95988dc517db6e09348aab996868699c commit: 8d95012c95988dc517db6e09348aab996868699c branch: main author: Arthur Pastel <arthur.pastel at gmail.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-07T20:42:26+01:00 summary: gh-103650: Fix perf maps address format (#103651) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst M Lib/test/test_perf_profiler.py M Python/perf_trampoline.c diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 2b977d78d393..5418f9f35485 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -1,4 +1,5 @@ import unittest +import string import subprocess import sys import sysconfig @@ -70,9 +71,14 @@ def baz(): perf_file = pathlib.Path(f"/tmp/perf-{process.pid}.map") self.assertTrue(perf_file.exists()) perf_file_contents = perf_file.read_text() - self.assertIn(f"py::foo:{script}", perf_file_contents) - self.assertIn(f"py::bar:{script}", perf_file_contents) - self.assertIn(f"py::baz:{script}", perf_file_contents) + perf_lines = perf_file_contents.splitlines(); + expected_symbols = [f"py::foo:{script}", f"py::bar:{script}", f"py::baz:{script}"] + for expected_symbol in expected_symbols: + perf_line = next((line for line in perf_lines if expected_symbol in line), None) + self.assertIsNotNone(perf_line, f"Could not find {expected_symbol} in perf file") + perf_addr = perf_line.split(" ")[0] + self.assertFalse(perf_addr.startswith("0x"), "Address should not be prefixed with 0x") + self.assertTrue(set(perf_addr).issubset(string.hexdigits), "Address should contain only hex characters") def test_trampoline_works_with_forks(self): code = """if 1: diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst new file mode 100644 index 000000000000..5434660e9d6f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst @@ -0,0 +1 @@ +Change the perf map format to remove the '0x' prefix from the addresses diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 1957ab82c339..3b183280e1f2 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -253,7 +253,7 @@ perf_map_write_entry(void *state, const void *code_addr, NULL); return; } - fprintf(method_file, "%p %x py::%s:%s\n", code_addr, code_size, entry, + fprintf(method_file, "%" PRIxPTR " %x py::%s:%s\n", (uintptr_t) code_addr, code_size, entry, filename); fflush(method_file); } From webhook-mailer at python.org Sun May 7 17:12:56 2023 From: webhook-mailer at python.org (barneygale) Date: Sun, 07 May 2023 21:12:56 -0000 Subject: [Python-checkins] GH-102613: Improve performance of `pathlib.Path.rglob()` (GH-104244) Message-ID: <mailman.231.1683493977.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c0ece3dc9791694e960952ba74070efaaa79a676 commit: c0ece3dc9791694e960952ba74070efaaa79a676 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-07T22:12:50+01:00 summary: GH-102613: Improve performance of `pathlib.Path.rglob()` (GH-104244) Stop de-duplicating results in `_RecursiveWildcardSelector`. A new `_DoubleRecursiveWildcardSelector` class is introduced which performs de-duplication, but this is used _only_ for patterns with multiple non-adjacent `**` segments, such as `path.glob('**/foo/**')`. By avoiding the use of a set, `PurePath.__hash__()` is not called, and so paths do not need to be stringified and case-normalised. Also merge adjacent '**' segments in patterns. files: A Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 68255aa3e511..20ec1ce9d803 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -64,17 +64,25 @@ def _is_case_sensitive(flavour): @functools.lru_cache() def _make_selector(pattern_parts, flavour, case_sensitive): pat = pattern_parts[0] - child_parts = pattern_parts[1:] if not pat: return _TerminatingSelector() if pat == '**': - cls = _RecursiveWildcardSelector - elif pat == '..': - cls = _ParentSelector - elif '**' in pat: - raise ValueError("Invalid pattern: '**' can only be an entire path component") + child_parts_idx = 1 + while child_parts_idx < len(pattern_parts) and pattern_parts[child_parts_idx] == '**': + child_parts_idx += 1 + child_parts = pattern_parts[child_parts_idx:] + if '**' in child_parts: + cls = _DoubleRecursiveWildcardSelector + else: + cls = _RecursiveWildcardSelector else: - cls = _WildcardSelector + child_parts = pattern_parts[1:] + if pat == '..': + cls = _ParentSelector + elif '**' in pat: + raise ValueError("Invalid pattern: '**' can only be an entire path component") + else: + cls = _WildcardSelector return cls(pat, child_parts, flavour, case_sensitive) @@ -183,20 +191,32 @@ def _iterate_directories(self, parent_path, scandir): def _select_from(self, parent_path, scandir): try: - yielded = set() - try: - successor_select = self.successor._select_from - for starting_point in self._iterate_directories(parent_path, scandir): - for p in successor_select(starting_point, scandir): - if p not in yielded: - yield p - yielded.add(p) - finally: - yielded.clear() + successor_select = self.successor._select_from + for starting_point in self._iterate_directories(parent_path, scandir): + for p in successor_select(starting_point, scandir): + yield p except PermissionError: return +class _DoubleRecursiveWildcardSelector(_RecursiveWildcardSelector): + """ + Like _RecursiveWildcardSelector, but also de-duplicates results from + successive selectors. This is necessary if the pattern contains + multiple non-adjacent '**' segments. + """ + + def _select_from(self, parent_path, scandir): + yielded = set() + try: + for p in super()._select_from(parent_path, scandir): + if p not in yielded: + yield p + yielded.add(p) + finally: + yielded.clear() + + # # Public API # diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index e25c77f2ba8a..ee0ef9a34c38 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1853,13 +1853,14 @@ def _check(path, pattern, case_sensitive, expected): def test_rglob_common(self): def _check(glob, expected): - self.assertEqual(set(glob), { P(BASE, q) for q in expected }) + self.assertEqual(sorted(glob), sorted(P(BASE, q) for q in expected)) P = self.cls p = P(BASE) it = p.rglob("fileA") self.assertIsInstance(it, collections.abc.Iterator) _check(it, ["fileA"]) _check(p.rglob("fileB"), ["dirB/fileB"]) + _check(p.rglob("**/fileB"), ["dirB/fileB"]) _check(p.rglob("*/fileA"), []) if not os_helper.can_symlink(): _check(p.rglob("*/fileB"), ["dirB/fileB"]) @@ -1883,9 +1884,12 @@ def _check(glob, expected): _check(p.rglob("*"), ["dirC/fileC", "dirC/novel.txt", "dirC/dirD", "dirC/dirD/fileD"]) _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"]) + _check(p.rglob("**/file*"), ["dirC/fileC", "dirC/dirD/fileD"]) + _check(p.rglob("dir*/**"), ["dirC/dirD"]) _check(p.rglob("*/*"), ["dirC/dirD/fileD"]) _check(p.rglob("*/"), ["dirC/dirD"]) _check(p.rglob(""), ["dirC", "dirC/dirD"]) + _check(p.rglob("**"), ["dirC", "dirC/dirD"]) # gh-91616, a re module regression _check(p.rglob("*.txt"), ["dirC/novel.txt"]) _check(p.rglob("*.*"), ["dirC/novel.txt"]) diff --git a/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst b/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst new file mode 100644 index 000000000000..01f8b948d2cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst @@ -0,0 +1,3 @@ +Improve performance of :meth:`pathlib.Path.glob` when expanding recursive +wildcards ("``**``") by merging adjacent wildcards and de-duplicating +results only when necessary. From webhook-mailer at python.org Sun May 7 17:15:51 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 07 May 2023 21:15:51 -0000 Subject: [Python-checkins] gh-104265 Disallow instantiation of `_csv.Reader` and `_csv.Writer` (#104266) Message-ID: <mailman.232.1683494152.13550.python-checkins@python.org> https://github.com/python/cpython/commit/06c2a4858b8806abc700a0471434067910db54ec commit: 06c2a4858b8806abc700a0471434067910db54ec branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-07T21:15:44Z summary: gh-104265 Disallow instantiation of `_csv.Reader` and `_csv.Writer` (#104266) files: A Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 8fb97bc0c1a1..de7ac97d72cb 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -10,7 +10,7 @@ import gc import pickle from test import support -from test.support import warnings_helper +from test.support import warnings_helper, import_helper, check_disallow_instantiation from itertools import permutations from textwrap import dedent from collections import OrderedDict @@ -1430,5 +1430,12 @@ def test_subclassable(self): # issue 44089 class Foo(csv.Error): ... + @support.cpython_only + def test_disallow_instantiation(self): + _csv = import_helper.import_module("_csv") + for tp in _csv.Reader, _csv.Writer: + with self.subTest(tp=tp): + check_disallow_instantiation(self, tp) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst new file mode 100644 index 000000000000..9c582844bf90 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst @@ -0,0 +1,4 @@ +Prevent possible crash by disallowing instantiation of the +:class:`!_csv.Reader` and :class:`!_csv.Writer` types. +The regression was introduced in 3.10.0a4 with PR 23224 (:issue:`14935`). +Patch by Radislav Chugunov. diff --git a/Modules/_csv.c b/Modules/_csv.c index 0cde5c5a8bdc..9ab2ad266c27 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -1000,7 +1000,7 @@ PyType_Spec Reader_Type_spec = { .name = "_csv.reader", .basicsize = sizeof(ReaderObj), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = Reader_Type_slots }; @@ -1431,7 +1431,7 @@ PyType_Spec Writer_Type_spec = { .name = "_csv.writer", .basicsize = sizeof(WriterObj), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = Writer_Type_slots, }; From webhook-mailer at python.org Sun May 7 17:55:44 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 07 May 2023 21:55:44 -0000 Subject: [Python-checkins] gh-64660: Don't hardcode Argument Clinic return converter result variable name (#104200) Message-ID: <mailman.233.1683496545.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ac020624b32820e8e6e272122b94883f8e75ac61 commit: ac020624b32820e8e6e272122b94883f8e75ac61 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-07T21:55:37Z summary: gh-64660: Don't hardcode Argument Clinic return converter result variable name (#104200) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 704325670bc9..a6f330d1502d 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -356,6 +356,7 @@ def __init__(self): # you should check the _return_value for errors, and # "goto exit" if there are any. self.return_conversion = [] + self.converter_retval = "_return_value" # The C statements required to do some operations # after the end of parsing but before cleaning up. @@ -3893,15 +3894,15 @@ def __init__(self, *, py_default=None, **kwargs): def return_converter_init(self): pass - def declare(self, data, name="_return_value"): + def declare(self, data): line = [] add = line.append add(self.type) if not self.type.endswith('*'): add(' ') - add(name + ';') + add(data.converter_retval + ';') data.declarations.append(''.join(line)) - data.return_value = name + data.return_value = data.converter_retval def err_occurred_if(self, expr, data): data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr)) @@ -3923,8 +3924,10 @@ class bool_return_converter(CReturnConverter): def render(self, function, data): self.declare(data) - self.err_occurred_if("_return_value == -1", data) - data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n') + self.err_occurred_if(f"{data.converter_retval} == -1", data) + data.return_conversion.append( + f'return_value = PyBool_FromLong((long){data.converter_retval});\n' + ) class long_return_converter(CReturnConverter): type = 'long' @@ -3934,9 +3937,10 @@ class long_return_converter(CReturnConverter): def render(self, function, data): self.declare(data) - self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data) + self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data) data.return_conversion.append( - ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n'))) + f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n' + ) class int_return_converter(long_return_converter): type = 'int' @@ -3978,9 +3982,10 @@ class double_return_converter(CReturnConverter): def render(self, function, data): self.declare(data) - self.err_occurred_if("_return_value == -1.0", data) + self.err_occurred_if(f"{data.converter_retval} == -1.0", data) data.return_conversion.append( - 'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n') + f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n' + ) class float_return_converter(double_return_converter): type = 'float' From webhook-mailer at python.org Sun May 7 19:44:25 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 07 May 2023 23:44:25 -0000 Subject: [Python-checkins] gh-104273: Remove redundant len() calls in argparse function (#104274) Message-ID: <mailman.234.1683503066.13550.python-checkins@python.org> https://github.com/python/cpython/commit/01cc9c1ff79bf18fe34c05c6cd573e79ff9487c3 commit: 01cc9c1ff79bf18fe34c05c6cd573e79ff9487c3 branch: main author: Burak Saler <59198732+buraksaler at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-07T19:43:50-04:00 summary: gh-104273: Remove redundant len() calls in argparse function (#104274) files: M Lib/argparse.py diff --git a/Lib/argparse.py b/Lib/argparse.py index 68089a5c1e80..f5f44ff02c0d 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -345,21 +345,22 @@ def _format_usage(self, usage, actions, groups, prefix): def get_lines(parts, indent, prefix=None): lines = [] line = [] + indent_length = len(indent) if prefix is not None: line_len = len(prefix) - 1 else: - line_len = len(indent) - 1 + line_len = indent_length - 1 for part in parts: if line_len + 1 + len(part) > text_width and line: lines.append(indent + ' '.join(line)) line = [] - line_len = len(indent) - 1 + line_len = indent_length - 1 line.append(part) line_len += len(part) + 1 if line: lines.append(indent + ' '.join(line)) if prefix is not None: - lines[0] = lines[0][len(indent):] + lines[0] = lines[0][indent_length:] return lines # if prog is short, follow it with optionals or positionals From webhook-mailer at python.org Sun May 7 23:50:12 2023 From: webhook-mailer at python.org (gpshead) Date: Mon, 08 May 2023 03:50:12 -0000 Subject: [Python-checkins] gh-99108: Replace SHA3 implementation HACL* version (#103597) Message-ID: <mailman.235.1683517812.13550.python-checkins@python.org> https://github.com/python/cpython/commit/15665d896bae9c3d8b60bd7210ac1b7dc533b093 commit: 15665d896bae9c3d8b60bd7210ac1b7dc533b093 branch: main author: Jonathan Protzenko <protz at microsoft.com> committer: gpshead <greg at krypto.org> date: 2023-05-07T20:50:04-07:00 summary: gh-99108: Replace SHA3 implementation HACL* version (#103597) Replaces our built-in SHA3 implementation with a verified one from the HACL* project. This implementation is used when OpenSSL does not provide SHA3 or is not present. 3.11 shiped with a very slow tiny sha3 implementation to get off of the <=3.10 reference implementation that wound up having serious bugs. This brings us back to a reasonably performing built-in implementation consistent with what we've just replaced our other guaranteed available standard hash algorithms with: code from the HACL* project. --------- Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst A Modules/_hacl/Hacl_Hash_SHA3.c A Modules/_hacl/Hacl_Hash_SHA3.h A Modules/_hacl/internal/Hacl_Hash_SHA3.h A Modules/clinic/sha3module.c.h A Modules/sha3module.c D Modules/_sha3/LICENSE D Modules/_sha3/README.txt D Modules/_sha3/clinic/sha3module.c.h D Modules/_sha3/sha3.c D Modules/_sha3/sha3.h D Modules/_sha3/sha3module.c M Makefile.pre.in M Modules/Setup M Modules/Setup.stdlib.in M Modules/_hacl/Hacl_Streaming_Types.h M Modules/_hacl/include/krml/internal/target.h M Modules/_hacl/include/krml/lowstar_endianness.h M Modules/_hacl/python_hacl_namespaces.h M Modules/_hacl/refresh.sh M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Tools/c-analyzer/cpython/_parser.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 736a520d0e8f..329466580b9c 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2698,7 +2698,7 @@ MODULE__IO_DEPS=$(srcdir)/Modules/_io/_iomodule.h MODULE__MD5_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_MD5.h Modules/_hacl/Hacl_Hash_MD5.c MODULE__SHA1_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_SHA1.h Modules/_hacl/Hacl_Hash_SHA1.c MODULE__SHA2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA2_HEADERS) $(LIBHACL_SHA2_A) -MODULE__SHA3_DEPS=$(srcdir)/Modules/_sha3/sha3.c $(srcdir)/Modules/_sha3/sha3.h $(srcdir)/Modules/hashlib.h +MODULE__SHA3_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_SHA3.h Modules/_hacl/Hacl_Hash_SHA3.c MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c $(srcdir)/Modules/getnameinfo.c 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 diff --git a/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst b/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst new file mode 100644 index 000000000000..f259acf75383 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst @@ -0,0 +1,2 @@ +Upgrade built-in :mod:`hashlib` SHA3 implementation to a verified implementation +from the ``HACL*`` project. Used when OpenSSL is not present or lacks SHA3. diff --git a/Modules/Setup b/Modules/Setup index 1c6f2f7ea518..e5bc078af62c 100644 --- a/Modules/Setup +++ b/Modules/Setup @@ -166,7 +166,7 @@ PYTHONPATH=$(COREPYTHONPATH) #_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE #_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE #_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a -#_sha3 _sha3/sha3module.c +#_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_sha3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE # text encodings and unicode #_codecs_cn cjkcodecs/_codecs_cn.c diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index a7803cf7c00e..8e66576b5c5f 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -80,7 +80,7 @@ @MODULE__MD5_TRUE at _md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE @MODULE__SHA1_TRUE at _sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE @MODULE__SHA2_TRUE at _sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a - at MODULE__SHA3_TRUE@_sha3 _sha3/sha3module.c + at MODULE__SHA3_TRUE@_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE @MODULE__BLAKE2_TRUE at _blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c ############################################################################ diff --git a/Modules/_hacl/Hacl_Hash_SHA3.c b/Modules/_hacl/Hacl_Hash_SHA3.c new file mode 100644 index 000000000000..100afe7c2c6d --- /dev/null +++ b/Modules/_hacl/Hacl_Hash_SHA3.c @@ -0,0 +1,826 @@ +/* MIT License + * + * Copyright (c) 2016-2022 INRIA, CMU and Microsoft Corporation + * Copyright (c) 2022-2023 HACL* Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "internal/Hacl_Hash_SHA3.h" + +static uint32_t block_len(Spec_Hash_Definitions_hash_alg a) +{ + switch (a) + { + case Spec_Hash_Definitions_SHA3_224: + { + return (uint32_t)144U; + } + case Spec_Hash_Definitions_SHA3_256: + { + return (uint32_t)136U; + } + case Spec_Hash_Definitions_SHA3_384: + { + return (uint32_t)104U; + } + case Spec_Hash_Definitions_SHA3_512: + { + return (uint32_t)72U; + } + case Spec_Hash_Definitions_Shake128: + { + return (uint32_t)168U; + } + case Spec_Hash_Definitions_Shake256: + { + return (uint32_t)136U; + } + default: + { + KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); + KRML_HOST_EXIT(253U); + } + } +} + +static uint32_t hash_len(Spec_Hash_Definitions_hash_alg a) +{ + switch (a) + { + case Spec_Hash_Definitions_SHA3_224: + { + return (uint32_t)28U; + } + case Spec_Hash_Definitions_SHA3_256: + { + return (uint32_t)32U; + } + case Spec_Hash_Definitions_SHA3_384: + { + return (uint32_t)48U; + } + case Spec_Hash_Definitions_SHA3_512: + { + return (uint32_t)64U; + } + default: + { + KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); + KRML_HOST_EXIT(253U); + } + } +} + +void +Hacl_Hash_SHA3_update_multi_sha3( + Spec_Hash_Definitions_hash_alg a, + uint64_t *s, + uint8_t *blocks, + uint32_t n_blocks +) +{ + for (uint32_t i = (uint32_t)0U; i < n_blocks; i++) + { + uint8_t *block = blocks + i * block_len(a); + Hacl_Impl_SHA3_absorb_inner(block_len(a), block, s); + } +} + +void +Hacl_Hash_SHA3_update_last_sha3( + Spec_Hash_Definitions_hash_alg a, + uint64_t *s, + uint8_t *input, + uint32_t input_len +) +{ + uint8_t suffix; + if (a == Spec_Hash_Definitions_Shake128 || a == Spec_Hash_Definitions_Shake256) + { + suffix = (uint8_t)0x1fU; + } + else + { + suffix = (uint8_t)0x06U; + } + uint32_t len = block_len(a); + if (input_len == len) + { + Hacl_Impl_SHA3_absorb_inner(len, input, s); + uint8_t *uu____0 = input + input_len; + uint8_t lastBlock_[200U] = { 0U }; + uint8_t *lastBlock = lastBlock_; + memcpy(lastBlock, uu____0, (uint32_t)0U * sizeof (uint8_t)); + lastBlock[0U] = suffix; + Hacl_Impl_SHA3_loadState(len, lastBlock, s); + if (!((suffix & (uint8_t)0x80U) == (uint8_t)0U) && (uint32_t)0U == len - (uint32_t)1U) + { + Hacl_Impl_SHA3_state_permute(s); + } + uint8_t nextBlock_[200U] = { 0U }; + uint8_t *nextBlock = nextBlock_; + nextBlock[len - (uint32_t)1U] = (uint8_t)0x80U; + Hacl_Impl_SHA3_loadState(len, nextBlock, s); + Hacl_Impl_SHA3_state_permute(s); + return; + } + uint8_t lastBlock_[200U] = { 0U }; + uint8_t *lastBlock = lastBlock_; + memcpy(lastBlock, input, input_len * sizeof (uint8_t)); + lastBlock[input_len] = suffix; + Hacl_Impl_SHA3_loadState(len, lastBlock, s); + if (!((suffix & (uint8_t)0x80U) == (uint8_t)0U) && input_len == len - (uint32_t)1U) + { + Hacl_Impl_SHA3_state_permute(s); + } + uint8_t nextBlock_[200U] = { 0U }; + uint8_t *nextBlock = nextBlock_; + nextBlock[len - (uint32_t)1U] = (uint8_t)0x80U; + Hacl_Impl_SHA3_loadState(len, nextBlock, s); + Hacl_Impl_SHA3_state_permute(s); +} + +typedef struct hash_buf2_s +{ + Hacl_Streaming_Keccak_hash_buf fst; + Hacl_Streaming_Keccak_hash_buf snd; +} +hash_buf2; + +Spec_Hash_Definitions_hash_alg Hacl_Streaming_Keccak_get_alg(Hacl_Streaming_Keccak_state *s) +{ + Hacl_Streaming_Keccak_state scrut = *s; + Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state; + return block_state.fst; +} + +Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_hash_alg a) +{ + KRML_CHECK_SIZE(sizeof (uint8_t), block_len(a)); + uint8_t *buf0 = (uint8_t *)KRML_HOST_CALLOC(block_len(a), sizeof (uint8_t)); + uint64_t *buf = (uint64_t *)KRML_HOST_CALLOC((uint32_t)25U, sizeof (uint64_t)); + Hacl_Streaming_Keccak_hash_buf block_state = { .fst = a, .snd = buf }; + Hacl_Streaming_Keccak_state + s = { .block_state = block_state, .buf = buf0, .total_len = (uint64_t)(uint32_t)0U }; + Hacl_Streaming_Keccak_state + *p = (Hacl_Streaming_Keccak_state *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_Keccak_state)); + p[0U] = s; + uint64_t *s1 = block_state.snd; + for (uint32_t _i = 0U; _i < (uint32_t)25U; ++_i) + ((void **)s1)[_i] = (void *)(uint64_t)0U; + return p; +} + +void Hacl_Streaming_Keccak_free(Hacl_Streaming_Keccak_state *s) +{ + Hacl_Streaming_Keccak_state scrut = *s; + uint8_t *buf = scrut.buf; + Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state; + uint64_t *s1 = block_state.snd; + KRML_HOST_FREE(s1); + KRML_HOST_FREE(buf); + KRML_HOST_FREE(s); +} + +Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_copy(Hacl_Streaming_Keccak_state *s0) +{ + Hacl_Streaming_Keccak_state scrut0 = *s0; + Hacl_Streaming_Keccak_hash_buf block_state0 = scrut0.block_state; + uint8_t *buf0 = scrut0.buf; + uint64_t total_len0 = scrut0.total_len; + Spec_Hash_Definitions_hash_alg i = block_state0.fst; + KRML_CHECK_SIZE(sizeof (uint8_t), block_len(i)); + uint8_t *buf1 = (uint8_t *)KRML_HOST_CALLOC(block_len(i), sizeof (uint8_t)); + memcpy(buf1, buf0, block_len(i) * sizeof (uint8_t)); + uint64_t *buf = (uint64_t *)KRML_HOST_CALLOC((uint32_t)25U, sizeof (uint64_t)); + Hacl_Streaming_Keccak_hash_buf block_state = { .fst = i, .snd = buf }; + hash_buf2 scrut = { .fst = block_state0, .snd = block_state }; + uint64_t *s_dst = scrut.snd.snd; + uint64_t *s_src = scrut.fst.snd; + memcpy(s_dst, s_src, (uint32_t)25U * sizeof (uint64_t)); + Hacl_Streaming_Keccak_state + s = { .block_state = block_state, .buf = buf1, .total_len = total_len0 }; + Hacl_Streaming_Keccak_state + *p = (Hacl_Streaming_Keccak_state *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_Keccak_state)); + p[0U] = s; + return p; +} + +void Hacl_Streaming_Keccak_reset(Hacl_Streaming_Keccak_state *s) +{ + Hacl_Streaming_Keccak_state scrut = *s; + uint8_t *buf = scrut.buf; + Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state; + uint64_t *s1 = block_state.snd; + for (uint32_t _i = 0U; _i < (uint32_t)25U; ++_i) + ((void **)s1)[_i] = (void *)(uint64_t)0U; + Hacl_Streaming_Keccak_state + tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)(uint32_t)0U }; + s[0U] = tmp; +} + +uint32_t +Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint32_t len) +{ + Hacl_Streaming_Keccak_state s = *p; + Hacl_Streaming_Keccak_hash_buf block_state = s.block_state; + uint64_t total_len = s.total_len; + Spec_Hash_Definitions_hash_alg i = block_state.fst; + if ((uint64_t)len > (uint64_t)0xffffffffU - total_len) + { + return (uint32_t)1U; + } + uint32_t sz; + if (total_len % (uint64_t)block_len(i) == (uint64_t)0U && total_len > (uint64_t)0U) + { + sz = block_len(i); + } + else + { + sz = (uint32_t)(total_len % (uint64_t)block_len(i)); + } + if (len <= block_len(i) - sz) + { + Hacl_Streaming_Keccak_state s1 = *p; + Hacl_Streaming_Keccak_hash_buf block_state1 = s1.block_state; + uint8_t *buf = s1.buf; + uint64_t total_len1 = s1.total_len; + uint32_t sz1; + if (total_len1 % (uint64_t)block_len(i) == (uint64_t)0U && total_len1 > (uint64_t)0U) + { + sz1 = block_len(i); + } + else + { + sz1 = (uint32_t)(total_len1 % (uint64_t)block_len(i)); + } + uint8_t *buf2 = buf + sz1; + memcpy(buf2, data, len * sizeof (uint8_t)); + uint64_t total_len2 = total_len1 + (uint64_t)len; + *p + = + ( + (Hacl_Streaming_Keccak_state){ + .block_state = block_state1, + .buf = buf, + .total_len = total_len2 + } + ); + } + else if (sz == (uint32_t)0U) + { + Hacl_Streaming_Keccak_state s1 = *p; + Hacl_Streaming_Keccak_hash_buf block_state1 = s1.block_state; + uint8_t *buf = s1.buf; + uint64_t total_len1 = s1.total_len; + uint32_t sz1; + if (total_len1 % (uint64_t)block_len(i) == (uint64_t)0U && total_len1 > (uint64_t)0U) + { + sz1 = block_len(i); + } + else + { + sz1 = (uint32_t)(total_len1 % (uint64_t)block_len(i)); + } + if (!(sz1 == (uint32_t)0U)) + { + Spec_Hash_Definitions_hash_alg a1 = block_state1.fst; + uint64_t *s2 = block_state1.snd; + Hacl_Hash_SHA3_update_multi_sha3(a1, s2, buf, block_len(i) / block_len(a1)); + } + uint32_t ite; + if ((uint64_t)len % (uint64_t)block_len(i) == (uint64_t)0U && (uint64_t)len > (uint64_t)0U) + { + ite = block_len(i); + } + else + { + ite = (uint32_t)((uint64_t)len % (uint64_t)block_len(i)); + } + uint32_t n_blocks = (len - ite) / block_len(i); + uint32_t data1_len = n_blocks * block_len(i); + uint32_t data2_len = len - data1_len; + uint8_t *data1 = data; + uint8_t *data2 = data + data1_len; + Spec_Hash_Definitions_hash_alg a1 = block_state1.fst; + uint64_t *s2 = block_state1.snd; + Hacl_Hash_SHA3_update_multi_sha3(a1, s2, data1, data1_len / block_len(a1)); + uint8_t *dst = buf; + memcpy(dst, data2, data2_len * sizeof (uint8_t)); + *p + = + ( + (Hacl_Streaming_Keccak_state){ + .block_state = block_state1, + .buf = buf, + .total_len = total_len1 + (uint64_t)len + } + ); + } + else + { + uint32_t diff = block_len(i) - sz; + uint8_t *data1 = data; + uint8_t *data2 = data + diff; + Hacl_Streaming_Keccak_state s1 = *p; + Hacl_Streaming_Keccak_hash_buf block_state10 = s1.block_state; + uint8_t *buf0 = s1.buf; + uint64_t total_len10 = s1.total_len; + uint32_t sz10; + if (total_len10 % (uint64_t)block_len(i) == (uint64_t)0U && total_len10 > (uint64_t)0U) + { + sz10 = block_len(i); + } + else + { + sz10 = (uint32_t)(total_len10 % (uint64_t)block_len(i)); + } + uint8_t *buf2 = buf0 + sz10; + memcpy(buf2, data1, diff * sizeof (uint8_t)); + uint64_t total_len2 = total_len10 + (uint64_t)diff; + *p + = + ( + (Hacl_Streaming_Keccak_state){ + .block_state = block_state10, + .buf = buf0, + .total_len = total_len2 + } + ); + Hacl_Streaming_Keccak_state s10 = *p; + Hacl_Streaming_Keccak_hash_buf block_state1 = s10.block_state; + uint8_t *buf = s10.buf; + uint64_t total_len1 = s10.total_len; + uint32_t sz1; + if (total_len1 % (uint64_t)block_len(i) == (uint64_t)0U && total_len1 > (uint64_t)0U) + { + sz1 = block_len(i); + } + else + { + sz1 = (uint32_t)(total_len1 % (uint64_t)block_len(i)); + } + if (!(sz1 == (uint32_t)0U)) + { + Spec_Hash_Definitions_hash_alg a1 = block_state1.fst; + uint64_t *s2 = block_state1.snd; + Hacl_Hash_SHA3_update_multi_sha3(a1, s2, buf, block_len(i) / block_len(a1)); + } + uint32_t ite; + if + ( + (uint64_t)(len - diff) + % (uint64_t)block_len(i) + == (uint64_t)0U + && (uint64_t)(len - diff) > (uint64_t)0U + ) + { + ite = block_len(i); + } + else + { + ite = (uint32_t)((uint64_t)(len - diff) % (uint64_t)block_len(i)); + } + uint32_t n_blocks = (len - diff - ite) / block_len(i); + uint32_t data1_len = n_blocks * block_len(i); + uint32_t data2_len = len - diff - data1_len; + uint8_t *data11 = data2; + uint8_t *data21 = data2 + data1_len; + Spec_Hash_Definitions_hash_alg a1 = block_state1.fst; + uint64_t *s2 = block_state1.snd; + Hacl_Hash_SHA3_update_multi_sha3(a1, s2, data11, data1_len / block_len(a1)); + uint8_t *dst = buf; + memcpy(dst, data21, data2_len * sizeof (uint8_t)); + *p + = + ( + (Hacl_Streaming_Keccak_state){ + .block_state = block_state1, + .buf = buf, + .total_len = total_len1 + (uint64_t)(len - diff) + } + ); + } + return (uint32_t)0U; +} + +static void +finish_( + Spec_Hash_Definitions_hash_alg a, + Hacl_Streaming_Keccak_state *p, + uint8_t *dst, + uint32_t l +) +{ + Hacl_Streaming_Keccak_state scrut0 = *p; + Hacl_Streaming_Keccak_hash_buf block_state = scrut0.block_state; + uint8_t *buf_ = scrut0.buf; + uint64_t total_len = scrut0.total_len; + uint32_t r; + if (total_len % (uint64_t)block_len(a) == (uint64_t)0U && total_len > (uint64_t)0U) + { + r = block_len(a); + } + else + { + r = (uint32_t)(total_len % (uint64_t)block_len(a)); + } + uint8_t *buf_1 = buf_; + uint64_t buf[25U] = { 0U }; + Hacl_Streaming_Keccak_hash_buf tmp_block_state = { .fst = a, .snd = buf }; + hash_buf2 scrut = { .fst = block_state, .snd = tmp_block_state }; + uint64_t *s_dst = scrut.snd.snd; + uint64_t *s_src = scrut.fst.snd; + memcpy(s_dst, s_src, (uint32_t)25U * sizeof (uint64_t)); + uint32_t ite0; + if (r % block_len(a) == (uint32_t)0U && r > (uint32_t)0U) + { + ite0 = block_len(a); + } + else + { + ite0 = r % block_len(a); + } + uint8_t *buf_last = buf_1 + r - ite0; + uint8_t *buf_multi = buf_1; + Spec_Hash_Definitions_hash_alg a1 = tmp_block_state.fst; + uint64_t *s0 = tmp_block_state.snd; + Hacl_Hash_SHA3_update_multi_sha3(a1, s0, buf_multi, (uint32_t)0U / block_len(a1)); + Spec_Hash_Definitions_hash_alg a10 = tmp_block_state.fst; + uint64_t *s1 = tmp_block_state.snd; + Hacl_Hash_SHA3_update_last_sha3(a10, s1, buf_last, r); + Spec_Hash_Definitions_hash_alg a11 = tmp_block_state.fst; + uint64_t *s = tmp_block_state.snd; + if (a11 == Spec_Hash_Definitions_Shake128 || a11 == Spec_Hash_Definitions_Shake256) + { + uint32_t ite; + if (a11 == Spec_Hash_Definitions_Shake128 || a11 == Spec_Hash_Definitions_Shake256) + { + ite = l; + } + else + { + ite = hash_len(a11); + } + Hacl_Impl_SHA3_squeeze(s, block_len(a11), ite, dst); + return; + } + Hacl_Impl_SHA3_squeeze(s, block_len(a11), hash_len(a11), dst); +} + +Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Keccak_finish(Hacl_Streaming_Keccak_state *s, uint8_t *dst) +{ + Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s); + if (a1 == Spec_Hash_Definitions_Shake128 || a1 == Spec_Hash_Definitions_Shake256) + { + return Hacl_Streaming_Keccak_InvalidAlgorithm; + } + finish_(a1, s, dst, hash_len(a1)); + return Hacl_Streaming_Keccak_Success; +} + +Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Keccak_squeeze(Hacl_Streaming_Keccak_state *s, uint8_t *dst, uint32_t l) +{ + Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s); + if (!(a1 == Spec_Hash_Definitions_Shake128 || a1 == Spec_Hash_Definitions_Shake256)) + { + return Hacl_Streaming_Keccak_InvalidAlgorithm; + } + if (l == (uint32_t)0U) + { + return Hacl_Streaming_Keccak_InvalidLength; + } + finish_(a1, s, dst, l); + return Hacl_Streaming_Keccak_Success; +} + +uint32_t Hacl_Streaming_Keccak_block_len(Hacl_Streaming_Keccak_state *s) +{ + Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s); + return block_len(a1); +} + +uint32_t Hacl_Streaming_Keccak_hash_len(Hacl_Streaming_Keccak_state *s) +{ + Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s); + return hash_len(a1); +} + +bool Hacl_Streaming_Keccak_is_shake(Hacl_Streaming_Keccak_state *s) +{ + Spec_Hash_Definitions_hash_alg uu____0 = Hacl_Streaming_Keccak_get_alg(s); + return uu____0 == Spec_Hash_Definitions_Shake128 || uu____0 == Spec_Hash_Definitions_Shake256; +} + +void +Hacl_SHA3_shake128_hacl( + uint32_t inputByteLen, + uint8_t *input, + uint32_t outputByteLen, + uint8_t *output +) +{ + Hacl_Impl_SHA3_keccak((uint32_t)1344U, + (uint32_t)256U, + inputByteLen, + input, + (uint8_t)0x1FU, + outputByteLen, + output); +} + +void +Hacl_SHA3_shake256_hacl( + uint32_t inputByteLen, + uint8_t *input, + uint32_t outputByteLen, + uint8_t *output +) +{ + Hacl_Impl_SHA3_keccak((uint32_t)1088U, + (uint32_t)512U, + inputByteLen, + input, + (uint8_t)0x1FU, + outputByteLen, + output); +} + +void Hacl_SHA3_sha3_224(uint32_t inputByteLen, uint8_t *input, uint8_t *output) +{ + Hacl_Impl_SHA3_keccak((uint32_t)1152U, + (uint32_t)448U, + inputByteLen, + input, + (uint8_t)0x06U, + (uint32_t)28U, + output); +} + +void Hacl_SHA3_sha3_256(uint32_t inputByteLen, uint8_t *input, uint8_t *output) +{ + Hacl_Impl_SHA3_keccak((uint32_t)1088U, + (uint32_t)512U, + inputByteLen, + input, + (uint8_t)0x06U, + (uint32_t)32U, + output); +} + +void Hacl_SHA3_sha3_384(uint32_t inputByteLen, uint8_t *input, uint8_t *output) +{ + Hacl_Impl_SHA3_keccak((uint32_t)832U, + (uint32_t)768U, + inputByteLen, + input, + (uint8_t)0x06U, + (uint32_t)48U, + output); +} + +void Hacl_SHA3_sha3_512(uint32_t inputByteLen, uint8_t *input, uint8_t *output) +{ + Hacl_Impl_SHA3_keccak((uint32_t)576U, + (uint32_t)1024U, + inputByteLen, + input, + (uint8_t)0x06U, + (uint32_t)64U, + output); +} + +static const +uint32_t +keccak_rotc[24U] = + { + (uint32_t)1U, (uint32_t)3U, (uint32_t)6U, (uint32_t)10U, (uint32_t)15U, (uint32_t)21U, + (uint32_t)28U, (uint32_t)36U, (uint32_t)45U, (uint32_t)55U, (uint32_t)2U, (uint32_t)14U, + (uint32_t)27U, (uint32_t)41U, (uint32_t)56U, (uint32_t)8U, (uint32_t)25U, (uint32_t)43U, + (uint32_t)62U, (uint32_t)18U, (uint32_t)39U, (uint32_t)61U, (uint32_t)20U, (uint32_t)44U + }; + +static const +uint32_t +keccak_piln[24U] = + { + (uint32_t)10U, (uint32_t)7U, (uint32_t)11U, (uint32_t)17U, (uint32_t)18U, (uint32_t)3U, + (uint32_t)5U, (uint32_t)16U, (uint32_t)8U, (uint32_t)21U, (uint32_t)24U, (uint32_t)4U, + (uint32_t)15U, (uint32_t)23U, (uint32_t)19U, (uint32_t)13U, (uint32_t)12U, (uint32_t)2U, + (uint32_t)20U, (uint32_t)14U, (uint32_t)22U, (uint32_t)9U, (uint32_t)6U, (uint32_t)1U + }; + +static const +uint64_t +keccak_rndc[24U] = + { + (uint64_t)0x0000000000000001U, (uint64_t)0x0000000000008082U, (uint64_t)0x800000000000808aU, + (uint64_t)0x8000000080008000U, (uint64_t)0x000000000000808bU, (uint64_t)0x0000000080000001U, + (uint64_t)0x8000000080008081U, (uint64_t)0x8000000000008009U, (uint64_t)0x000000000000008aU, + (uint64_t)0x0000000000000088U, (uint64_t)0x0000000080008009U, (uint64_t)0x000000008000000aU, + (uint64_t)0x000000008000808bU, (uint64_t)0x800000000000008bU, (uint64_t)0x8000000000008089U, + (uint64_t)0x8000000000008003U, (uint64_t)0x8000000000008002U, (uint64_t)0x8000000000000080U, + (uint64_t)0x000000000000800aU, (uint64_t)0x800000008000000aU, (uint64_t)0x8000000080008081U, + (uint64_t)0x8000000000008080U, (uint64_t)0x0000000080000001U, (uint64_t)0x8000000080008008U + }; + +void Hacl_Impl_SHA3_state_permute(uint64_t *s) +{ + for (uint32_t i0 = (uint32_t)0U; i0 < (uint32_t)24U; i0++) + { + uint64_t _C[5U] = { 0U }; + KRML_MAYBE_FOR5(i, + (uint32_t)0U, + (uint32_t)5U, + (uint32_t)1U, + _C[i] = + s[i + + (uint32_t)0U] + ^ + (s[i + + (uint32_t)5U] + ^ (s[i + (uint32_t)10U] ^ (s[i + (uint32_t)15U] ^ s[i + (uint32_t)20U])));); + KRML_MAYBE_FOR5(i1, + (uint32_t)0U, + (uint32_t)5U, + (uint32_t)1U, + uint64_t uu____0 = _C[(i1 + (uint32_t)1U) % (uint32_t)5U]; + uint64_t + _D = + _C[(i1 + (uint32_t)4U) + % (uint32_t)5U] + ^ (uu____0 << (uint32_t)1U | uu____0 >> (uint32_t)63U); + KRML_MAYBE_FOR5(i, + (uint32_t)0U, + (uint32_t)5U, + (uint32_t)1U, + s[i1 + (uint32_t)5U * i] = s[i1 + (uint32_t)5U * i] ^ _D;);); + uint64_t x = s[1U]; + uint64_t current = x; + for (uint32_t i = (uint32_t)0U; i < (uint32_t)24U; i++) + { + uint32_t _Y = keccak_piln[i]; + uint32_t r = keccak_rotc[i]; + uint64_t temp = s[_Y]; + uint64_t uu____1 = current; + s[_Y] = uu____1 << r | uu____1 >> ((uint32_t)64U - r); + current = temp; + } + KRML_MAYBE_FOR5(i, + (uint32_t)0U, + (uint32_t)5U, + (uint32_t)1U, + uint64_t + v0 = + s[(uint32_t)0U + + (uint32_t)5U * i] + ^ (~s[(uint32_t)1U + (uint32_t)5U * i] & s[(uint32_t)2U + (uint32_t)5U * i]); + uint64_t + v1 = + s[(uint32_t)1U + + (uint32_t)5U * i] + ^ (~s[(uint32_t)2U + (uint32_t)5U * i] & s[(uint32_t)3U + (uint32_t)5U * i]); + uint64_t + v2 = + s[(uint32_t)2U + + (uint32_t)5U * i] + ^ (~s[(uint32_t)3U + (uint32_t)5U * i] & s[(uint32_t)4U + (uint32_t)5U * i]); + uint64_t + v3 = + s[(uint32_t)3U + + (uint32_t)5U * i] + ^ (~s[(uint32_t)4U + (uint32_t)5U * i] & s[(uint32_t)0U + (uint32_t)5U * i]); + uint64_t + v4 = + s[(uint32_t)4U + + (uint32_t)5U * i] + ^ (~s[(uint32_t)0U + (uint32_t)5U * i] & s[(uint32_t)1U + (uint32_t)5U * i]); + s[(uint32_t)0U + (uint32_t)5U * i] = v0; + s[(uint32_t)1U + (uint32_t)5U * i] = v1; + s[(uint32_t)2U + (uint32_t)5U * i] = v2; + s[(uint32_t)3U + (uint32_t)5U * i] = v3; + s[(uint32_t)4U + (uint32_t)5U * i] = v4;); + uint64_t c = keccak_rndc[i0]; + s[0U] = s[0U] ^ c; + } +} + +void Hacl_Impl_SHA3_loadState(uint32_t rateInBytes, uint8_t *input, uint64_t *s) +{ + uint8_t block[200U] = { 0U }; + memcpy(block, input, rateInBytes * sizeof (uint8_t)); + for (uint32_t i = (uint32_t)0U; i < (uint32_t)25U; i++) + { + uint64_t u = load64_le(block + i * (uint32_t)8U); + uint64_t x = u; + s[i] = s[i] ^ x; + } +} + +static void storeState(uint32_t rateInBytes, uint64_t *s, uint8_t *res) +{ + uint8_t block[200U] = { 0U }; + for (uint32_t i = (uint32_t)0U; i < (uint32_t)25U; i++) + { + uint64_t sj = s[i]; + store64_le(block + i * (uint32_t)8U, sj); + } + memcpy(res, block, rateInBytes * sizeof (uint8_t)); +} + +void Hacl_Impl_SHA3_absorb_inner(uint32_t rateInBytes, uint8_t *block, uint64_t *s) +{ + Hacl_Impl_SHA3_loadState(rateInBytes, block, s); + Hacl_Impl_SHA3_state_permute(s); +} + +static void +absorb( + uint64_t *s, + uint32_t rateInBytes, + uint32_t inputByteLen, + uint8_t *input, + uint8_t delimitedSuffix +) +{ + uint32_t n_blocks = inputByteLen / rateInBytes; + uint32_t rem = inputByteLen % rateInBytes; + for (uint32_t i = (uint32_t)0U; i < n_blocks; i++) + { + uint8_t *block = input + i * rateInBytes; + Hacl_Impl_SHA3_absorb_inner(rateInBytes, block, s); + } + uint8_t *last = input + n_blocks * rateInBytes; + uint8_t lastBlock_[200U] = { 0U }; + uint8_t *lastBlock = lastBlock_; + memcpy(lastBlock, last, rem * sizeof (uint8_t)); + lastBlock[rem] = delimitedSuffix; + Hacl_Impl_SHA3_loadState(rateInBytes, lastBlock, s); + if (!((delimitedSuffix & (uint8_t)0x80U) == (uint8_t)0U) && rem == rateInBytes - (uint32_t)1U) + { + Hacl_Impl_SHA3_state_permute(s); + } + uint8_t nextBlock_[200U] = { 0U }; + uint8_t *nextBlock = nextBlock_; + nextBlock[rateInBytes - (uint32_t)1U] = (uint8_t)0x80U; + Hacl_Impl_SHA3_loadState(rateInBytes, nextBlock, s); + Hacl_Impl_SHA3_state_permute(s); +} + +void +Hacl_Impl_SHA3_squeeze( + uint64_t *s, + uint32_t rateInBytes, + uint32_t outputByteLen, + uint8_t *output +) +{ + uint32_t outBlocks = outputByteLen / rateInBytes; + uint32_t remOut = outputByteLen % rateInBytes; + uint8_t *last = output + outputByteLen - remOut; + uint8_t *blocks = output; + for (uint32_t i = (uint32_t)0U; i < outBlocks; i++) + { + storeState(rateInBytes, s, blocks + i * rateInBytes); + Hacl_Impl_SHA3_state_permute(s); + } + storeState(remOut, s, last); +} + +void +Hacl_Impl_SHA3_keccak( + uint32_t rate, + uint32_t capacity, + uint32_t inputByteLen, + uint8_t *input, + uint8_t delimitedSuffix, + uint32_t outputByteLen, + uint8_t *output +) +{ + uint32_t rateInBytes = rate / (uint32_t)8U; + uint64_t s[25U] = { 0U }; + absorb(s, rateInBytes, inputByteLen, input, delimitedSuffix); + Hacl_Impl_SHA3_squeeze(s, rateInBytes, outputByteLen, output); +} + diff --git a/Modules/_hacl/Hacl_Hash_SHA3.h b/Modules/_hacl/Hacl_Hash_SHA3.h new file mode 100644 index 000000000000..2a5cf4b1844b --- /dev/null +++ b/Modules/_hacl/Hacl_Hash_SHA3.h @@ -0,0 +1,136 @@ +/* MIT License + * + * Copyright (c) 2016-2022 INRIA, CMU and Microsoft Corporation + * Copyright (c) 2022-2023 HACL* Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef __Hacl_Hash_SHA3_H +#define __Hacl_Hash_SHA3_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include <string.h> +#include "krml/types.h" +#include "krml/lowstar_endianness.h" +#include "krml/internal/target.h" + +#include "Hacl_Streaming_Types.h" + +typedef struct Hacl_Streaming_Keccak_hash_buf_s +{ + Spec_Hash_Definitions_hash_alg fst; + uint64_t *snd; +} +Hacl_Streaming_Keccak_hash_buf; + +typedef struct Hacl_Streaming_Keccak_state_s +{ + Hacl_Streaming_Keccak_hash_buf block_state; + uint8_t *buf; + uint64_t total_len; +} +Hacl_Streaming_Keccak_state; + +Spec_Hash_Definitions_hash_alg Hacl_Streaming_Keccak_get_alg(Hacl_Streaming_Keccak_state *s); + +Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_hash_alg a); + +void Hacl_Streaming_Keccak_free(Hacl_Streaming_Keccak_state *s); + +Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_copy(Hacl_Streaming_Keccak_state *s0); + +void Hacl_Streaming_Keccak_reset(Hacl_Streaming_Keccak_state *s); + +uint32_t +Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint32_t len); + +#define Hacl_Streaming_Keccak_Success 0 +#define Hacl_Streaming_Keccak_InvalidAlgorithm 1 +#define Hacl_Streaming_Keccak_InvalidLength 2 + +typedef uint8_t Hacl_Streaming_Keccak_error_code; + +Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Keccak_finish(Hacl_Streaming_Keccak_state *s, uint8_t *dst); + +Hacl_Streaming_Keccak_error_code +Hacl_Streaming_Keccak_squeeze(Hacl_Streaming_Keccak_state *s, uint8_t *dst, uint32_t l); + +uint32_t Hacl_Streaming_Keccak_block_len(Hacl_Streaming_Keccak_state *s); + +uint32_t Hacl_Streaming_Keccak_hash_len(Hacl_Streaming_Keccak_state *s); + +bool Hacl_Streaming_Keccak_is_shake(Hacl_Streaming_Keccak_state *s); + +void +Hacl_SHA3_shake128_hacl( + uint32_t inputByteLen, + uint8_t *input, + uint32_t outputByteLen, + uint8_t *output +); + +void +Hacl_SHA3_shake256_hacl( + uint32_t inputByteLen, + uint8_t *input, + uint32_t outputByteLen, + uint8_t *output +); + +void Hacl_SHA3_sha3_224(uint32_t inputByteLen, uint8_t *input, uint8_t *output); + +void Hacl_SHA3_sha3_256(uint32_t inputByteLen, uint8_t *input, uint8_t *output); + +void Hacl_SHA3_sha3_384(uint32_t inputByteLen, uint8_t *input, uint8_t *output); + +void Hacl_SHA3_sha3_512(uint32_t inputByteLen, uint8_t *input, uint8_t *output); + +void Hacl_Impl_SHA3_absorb_inner(uint32_t rateInBytes, uint8_t *block, uint64_t *s); + +void +Hacl_Impl_SHA3_squeeze( + uint64_t *s, + uint32_t rateInBytes, + uint32_t outputByteLen, + uint8_t *output +); + +void +Hacl_Impl_SHA3_keccak( + uint32_t rate, + uint32_t capacity, + uint32_t inputByteLen, + uint8_t *input, + uint8_t delimitedSuffix, + uint32_t outputByteLen, + uint8_t *output +); + +#if defined(__cplusplus) +} +#endif + +#define __Hacl_Hash_SHA3_H_DEFINED +#endif diff --git a/Modules/_hacl/Hacl_Streaming_Types.h b/Modules/_hacl/Hacl_Streaming_Types.h index 51057611ca97..8a60b707bc49 100644 --- a/Modules/_hacl/Hacl_Streaming_Types.h +++ b/Modules/_hacl/Hacl_Streaming_Types.h @@ -35,6 +35,23 @@ extern "C" { #include "krml/lowstar_endianness.h" #include "krml/internal/target.h" +#define Spec_Hash_Definitions_SHA2_224 0 +#define Spec_Hash_Definitions_SHA2_256 1 +#define Spec_Hash_Definitions_SHA2_384 2 +#define Spec_Hash_Definitions_SHA2_512 3 +#define Spec_Hash_Definitions_SHA1 4 +#define Spec_Hash_Definitions_MD5 5 +#define Spec_Hash_Definitions_Blake2S 6 +#define Spec_Hash_Definitions_Blake2B 7 +#define Spec_Hash_Definitions_SHA3_256 8 +#define Spec_Hash_Definitions_SHA3_224 9 +#define Spec_Hash_Definitions_SHA3_384 10 +#define Spec_Hash_Definitions_SHA3_512 11 +#define Spec_Hash_Definitions_Shake128 12 +#define Spec_Hash_Definitions_Shake256 13 + +typedef uint8_t Spec_Hash_Definitions_hash_alg; + typedef struct Hacl_Streaming_MD_state_32_s { uint32_t *block_state; diff --git a/Modules/_hacl/include/krml/internal/target.h b/Modules/_hacl/include/krml/internal/target.h index dcbe7007b17b..5a2f94eb2ec8 100644 --- a/Modules/_hacl/include/krml/internal/target.h +++ b/Modules/_hacl/include/krml/internal/target.h @@ -19,6 +19,28 @@ # define inline __inline__ #endif +/******************************************************************************/ +/* Macros that KaRaMeL will generate. */ +/******************************************************************************/ + +/* For "bare" targets that do not have a C stdlib, the user might want to use + * [-add-early-include '"mydefinitions.h"'] and override these. */ +#ifndef KRML_HOST_PRINTF +# define KRML_HOST_PRINTF printf +#endif + +#if ( \ + (defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + (!(defined KRML_HOST_EPRINTF))) +# define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__) +#elif !(defined KRML_HOST_EPRINTF) && defined(_MSC_VER) +# define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__) +#endif + +#ifndef KRML_HOST_EXIT +# define KRML_HOST_EXIT exit +#endif + #ifndef KRML_HOST_MALLOC # define KRML_HOST_MALLOC malloc #endif @@ -35,6 +57,28 @@ # define KRML_HOST_IGNORE(x) (void)(x) #endif +/* In FStar.Buffer.fst, the size of arrays is uint32_t, but it's a number of + * *elements*. Do an ugly, run-time check (some of which KaRaMeL can eliminate). + */ +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)) +# define _KRML_CHECK_SIZE_PRAGMA \ + _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") +#else +# define _KRML_CHECK_SIZE_PRAGMA +#endif + +#define KRML_CHECK_SIZE(size_elt, sz) \ + do { \ + _KRML_CHECK_SIZE_PRAGMA \ + if (((size_t)(sz)) > ((size_t)(SIZE_MAX / (size_elt)))) { \ + KRML_HOST_PRINTF( \ + "Maximum allocatable size exceeded, aborting before overflow at " \ + "%s:%d\n", \ + __FILE__, __LINE__); \ + KRML_HOST_EXIT(253); \ + } \ + } while (0) + /* Macros for prettier unrolling of loops */ #define KRML_LOOP1(i, n, x) { \ x \ diff --git a/Modules/_hacl/include/krml/lowstar_endianness.h b/Modules/_hacl/include/krml/lowstar_endianness.h index 32a7391e817e..1aa2ccd644c0 100644 --- a/Modules/_hacl/include/krml/lowstar_endianness.h +++ b/Modules/_hacl/include/krml/lowstar_endianness.h @@ -77,7 +77,7 @@ # define le64toh(x) (x) /* ... for Windows (GCC-like, e.g. mingw or clang) */ -#elif (defined(_WIN32) || defined(_WIN64)) && \ +#elif (defined(_WIN32) || defined(_WIN64) || defined(__EMSCRIPTEN__)) && \ (defined(__GNUC__) || defined(__clang__)) # define htobe16(x) __builtin_bswap16(x) @@ -96,7 +96,8 @@ # define le64toh(x) (x) /* ... generic big-endian fallback code */ -#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +/* ... AIX doesn't have __BYTE_ORDER__ (with XLC compiler) & is always big-endian */ +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(_AIX) /* byte swapping code inspired by: * https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h diff --git a/Modules/_hacl/internal/Hacl_Hash_SHA3.h b/Modules/_hacl/internal/Hacl_Hash_SHA3.h new file mode 100644 index 000000000000..1c9808b8dd49 --- /dev/null +++ b/Modules/_hacl/internal/Hacl_Hash_SHA3.h @@ -0,0 +1,65 @@ +/* MIT License + * + * Copyright (c) 2016-2022 INRIA, CMU and Microsoft Corporation + * Copyright (c) 2022-2023 HACL* Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#ifndef __internal_Hacl_Hash_SHA3_H +#define __internal_Hacl_Hash_SHA3_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include <string.h> +#include "krml/types.h" +#include "krml/lowstar_endianness.h" +#include "krml/internal/target.h" + +#include "../Hacl_Hash_SHA3.h" + +void +Hacl_Hash_SHA3_update_multi_sha3( + Spec_Hash_Definitions_hash_alg a, + uint64_t *s, + uint8_t *blocks, + uint32_t n_blocks +); + +void +Hacl_Hash_SHA3_update_last_sha3( + Spec_Hash_Definitions_hash_alg a, + uint64_t *s, + uint8_t *input, + uint32_t input_len +); + +void Hacl_Impl_SHA3_state_permute(uint64_t *s); + +void Hacl_Impl_SHA3_loadState(uint32_t rateInBytes, uint8_t *input, uint64_t *s); + +#if defined(__cplusplus) +} +#endif + +#define __internal_Hacl_Hash_SHA3_H_DEFINED +#endif diff --git a/Modules/_hacl/python_hacl_namespaces.h b/Modules/_hacl/python_hacl_namespaces.h index ee28f244266b..0df236282ac5 100644 --- a/Modules/_hacl/python_hacl_namespaces.h +++ b/Modules/_hacl/python_hacl_namespaces.h @@ -59,5 +59,28 @@ #define Hacl_Streaming_SHA1_legacy_copy python_hashlib_Hacl_Streaming_SHA1_legacy_copy #define Hacl_Streaming_SHA1_legacy_hash python_hashlib_Hacl_Streaming_SHA1_legacy_hash +#define Hacl_Hash_SHA3_update_last_sha3 python_hashlib_Hacl_Hash_SHA3_update_last_sha3 +#define Hacl_Hash_SHA3_update_multi_sha3 python_hashlib_Hacl_Hash_SHA3_update_multi_sha3 +#define Hacl_Impl_SHA3_absorb_inner python_hashlib_Hacl_Impl_SHA3_absorb_inner +#define Hacl_Impl_SHA3_keccak python_hashlib_Hacl_Impl_SHA3_keccak +#define Hacl_Impl_SHA3_loadState python_hashlib_Hacl_Impl_SHA3_loadState +#define Hacl_Impl_SHA3_squeeze python_hashlib_Hacl_Impl_SHA3_squeeze +#define Hacl_Impl_SHA3_state_permute python_hashlib_Hacl_Impl_SHA3_state_permute +#define Hacl_SHA3_sha3_224 python_hashlib_Hacl_SHA3_sha3_224 +#define Hacl_SHA3_sha3_256 python_hashlib_Hacl_SHA3_sha3_256 +#define Hacl_SHA3_sha3_384 python_hashlib_Hacl_SHA3_sha3_384 +#define Hacl_SHA3_sha3_512 python_hashlib_Hacl_SHA3_sha3_512 +#define Hacl_SHA3_shake128_hacl python_hashlib_Hacl_SHA3_shake128_hacl +#define Hacl_SHA3_shake256_hacl python_hashlib_Hacl_SHA3_shake256_hacl +#define Hacl_Streaming_Keccak_block_len python_hashlib_Hacl_Streaming_Keccak_block_len +#define Hacl_Streaming_Keccak_copy python_hashlib_Hacl_Streaming_Keccak_copy +#define Hacl_Streaming_Keccak_finish python_hashlib_Hacl_Streaming_Keccak_finish +#define Hacl_Streaming_Keccak_free python_hashlib_Hacl_Streaming_Keccak_free +#define Hacl_Streaming_Keccak_get_alg python_hashlib_Hacl_Streaming_Keccak_get_alg +#define Hacl_Streaming_Keccak_hash_len python_hashlib_Hacl_Streaming_Keccak_hash_len +#define Hacl_Streaming_Keccak_is_shake python_hashlib_Hacl_Streaming_Keccak_is_shake +#define Hacl_Streaming_Keccak_malloc python_hashlib_Hacl_Streaming_Keccak_malloc +#define Hacl_Streaming_Keccak_reset python_hashlib_Hacl_Streaming_Keccak_reset +#define Hacl_Streaming_Keccak_update python_hashlib_Hacl_Streaming_Keccak_update #endif // _PYTHON_HACL_NAMESPACES_H diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh index 76b92ec45991..220ebbe55613 100755 --- a/Modules/_hacl/refresh.sh +++ b/Modules/_hacl/refresh.sh @@ -22,7 +22,7 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. -expected_hacl_star_rev=13e0c6721ac9206c4249ecc1dc04ed617ad1e262 +expected_hacl_star_rev=363eae2c2eb60e46f182ddd4bd1cd3f1d00b35c9 hacl_dir="$(realpath "$1")" cd "$(dirname "$0")" @@ -45,11 +45,14 @@ dist_files=( Hacl_Hash_SHA1.h internal/Hacl_Hash_SHA1.h Hacl_Hash_MD5.h + Hacl_Hash_SHA3.h internal/Hacl_Hash_MD5.h + internal/Hacl_Hash_SHA3.h internal/Hacl_SHA2_Generic.h Hacl_Streaming_SHA2.c Hacl_Hash_SHA1.c Hacl_Hash_MD5.c + Hacl_Hash_SHA3.c ) declare -a include_files @@ -134,9 +137,9 @@ $sed -i -z 's!#include <string.h>\n!#include <string.h>\n#include "python_hacl_n # Finally, we remove a bunch of ifdefs from target.h that are, again, useful in # the general case, but not exercised by the subset of HACL* that we vendor. -$sed -z -i 's!#ifndef KRML_\(HOST_PRINTF\|HOST_EXIT\|PRE_ALIGN\|POST_ALIGN\|ALIGNED_MALLOC\|ALIGNED_FREE\|HOST_TIME\)\n\(\n\|# [^\n]*\n\|[^#][^\n]*\n\)*#endif\n\n!!g' include/krml/internal/target.h -$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#define KRML_\(EABORT\|EXIT\|CHECK_SIZE\)[^\n]*\(\n [^\n]*\)*!!g' include/krml/internal/target.h +$sed -z -i 's!#ifndef KRML_\(PRE_ALIGN\|POST_ALIGN\|ALIGNED_MALLOC\|ALIGNED_FREE\|HOST_TIME\)\n\(\n\|# [^\n]*\n\|[^#][^\n]*\n\)*#endif\n\n!!g' include/krml/internal/target.h +$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#define KRML_\(EABORT\|EXIT\)[^\n]*\(\n [^\n]*\)*!!g' include/krml/internal/target.h $sed -z -i 's!\n\n\([^#][^\n]*\n\)*#if [^\n]*\n\( [^\n]*\n\)*#define KRML_\(EABORT\|EXIT\|CHECK_SIZE\)[^\n]*\(\n [^\n]*\)*!!g' include/krml/internal/target.h -$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#if [^\n]*\n\( [^\n]*\n\)*# define _\?KRML_\(DEPRECATED\|CHECK_SIZE_PRAGMA\|HOST_EPRINTF\|HOST_SNPRINTF\)[^\n]*\n\([^#][^\n]*\n\|#el[^\n]*\n\|# [^\n]*\n\)*#endif!!g' include/krml/internal/target.h +$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#if [^\n]*\n\( [^\n]*\n\)*# define _\?KRML_\(DEPRECATED\|HOST_SNPRINTF\)[^\n]*\n\([^#][^\n]*\n\|#el[^\n]*\n\|# [^\n]*\n\)*#endif!!g' include/krml/internal/target.h echo "Updated; verify all is okay using git diff and git status." diff --git a/Modules/_sha3/LICENSE b/Modules/_sha3/LICENSE deleted file mode 100644 index d2d484d8820d..000000000000 --- a/Modules/_sha3/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Markku-Juhani O. Saarinen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/Modules/_sha3/README.txt b/Modules/_sha3/README.txt deleted file mode 100644 index b35919b01677..000000000000 --- a/Modules/_sha3/README.txt +++ /dev/null @@ -1,8 +0,0 @@ -tiny_sha3 -========= - -https://github.com/mjosaarinen/tiny_sha3 -commit dcbb3192047c2a721f5f851db591871d428036a9 - -- All functions have been converted to static functions. -- sha3() function is commented out. diff --git a/Modules/_sha3/sha3.c b/Modules/_sha3/sha3.c deleted file mode 100644 index e2d3fd7b8ad8..000000000000 --- a/Modules/_sha3/sha3.c +++ /dev/null @@ -1,193 +0,0 @@ -// sha3.c -// 19-Nov-11 Markku-Juhani O. Saarinen <mjos at iki.fi> - -// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3" -// Revised 03-Sep-15 for portability + OpenSSL - style API - -#include "sha3.h" - -// update the state with given number of rounds - -static void sha3_keccakf(uint64_t st[25]) -{ - // constants - const uint64_t keccakf_rndc[24] = { - 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, - 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 - }; - const int keccakf_rotc[24] = { - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 - }; - const int keccakf_piln[24] = { - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 - }; - - // variables - int i, j, r; - uint64_t t, bc[5]; - -#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ - uint8_t *v; - - // endianess conversion. this is redundant on little-endian targets - for (i = 0; i < 25; i++) { - v = (uint8_t *) &st[i]; - st[i] = ((uint64_t) v[0]) | (((uint64_t) v[1]) << 8) | - (((uint64_t) v[2]) << 16) | (((uint64_t) v[3]) << 24) | - (((uint64_t) v[4]) << 32) | (((uint64_t) v[5]) << 40) | - (((uint64_t) v[6]) << 48) | (((uint64_t) v[7]) << 56); - } -#endif - - // actual iteration - for (r = 0; r < KECCAKF_ROUNDS; r++) { - - // Theta - for (i = 0; i < 5; i++) - bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; - - for (i = 0; i < 5; i++) { - t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); - for (j = 0; j < 25; j += 5) - st[j + i] ^= t; - } - - // Rho Pi - t = st[1]; - for (i = 0; i < 24; i++) { - j = keccakf_piln[i]; - bc[0] = st[j]; - st[j] = ROTL64(t, keccakf_rotc[i]); - t = bc[0]; - } - - // Chi - for (j = 0; j < 25; j += 5) { - for (i = 0; i < 5; i++) - bc[i] = st[j + i]; - for (i = 0; i < 5; i++) - st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; - } - - // Iota - st[0] ^= keccakf_rndc[r]; - } - -#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ - // endianess conversion. this is redundant on little-endian targets - for (i = 0; i < 25; i++) { - v = (uint8_t *) &st[i]; - t = st[i]; - v[0] = t & 0xFF; - v[1] = (t >> 8) & 0xFF; - v[2] = (t >> 16) & 0xFF; - v[3] = (t >> 24) & 0xFF; - v[4] = (t >> 32) & 0xFF; - v[5] = (t >> 40) & 0xFF; - v[6] = (t >> 48) & 0xFF; - v[7] = (t >> 56) & 0xFF; - } -#endif -} - -// Initialize the context for SHA3 - -static int sha3_init(sha3_ctx_t *c, int mdlen) -{ - int i; - - for (i = 0; i < 25; i++) - c->st.q[i] = 0; - c->mdlen = mdlen; - c->rsiz = 200 - 2 * mdlen; - c->pt = 0; - - return 1; -} - -// update state with more data - -static int sha3_update(sha3_ctx_t *c, const void *data, size_t len) -{ - size_t i; - int j; - - j = c->pt; - for (i = 0; i < len; i++) { - c->st.b[j++] ^= ((const uint8_t *) data)[i]; - if (j >= c->rsiz) { - sha3_keccakf(c->st.q); - j = 0; - } - } - c->pt = j; - - return 1; -} - -// finalize and output a hash - -static int sha3_final(void *md, sha3_ctx_t *c) -{ - int i; - - c->st.b[c->pt] ^= 0x06; - c->st.b[c->rsiz - 1] ^= 0x80; - sha3_keccakf(c->st.q); - - for (i = 0; i < c->mdlen; i++) { - ((uint8_t *) md)[i] = c->st.b[i]; - } - - return 1; -} - -#if 0 -// compute a SHA-3 hash (md) of given byte length from "in" - -void *sha3(const void *in, size_t inlen, void *md, int mdlen) -{ - sha3_ctx_t sha3; - - sha3_init(&sha3, mdlen); - sha3_update(&sha3, in, inlen); - sha3_final(md, &sha3); - - return md; -} -#endif - -// SHAKE128 and SHAKE256 extensible-output functionality - -static void shake_xof(sha3_ctx_t *c) -{ - c->st.b[c->pt] ^= 0x1F; - c->st.b[c->rsiz - 1] ^= 0x80; - sha3_keccakf(c->st.q); - c->pt = 0; -} - -static void shake_out(sha3_ctx_t *c, void *out, size_t len) -{ - size_t i; - int j; - - j = c->pt; - for (i = 0; i < len; i++) { - if (j >= c->rsiz) { - sha3_keccakf(c->st.q); - j = 0; - } - ((uint8_t *) out)[i] = c->st.b[j++]; - } - c->pt = j; -} - diff --git a/Modules/_sha3/sha3.h b/Modules/_sha3/sha3.h deleted file mode 100644 index f973d6733ec2..000000000000 --- a/Modules/_sha3/sha3.h +++ /dev/null @@ -1,49 +0,0 @@ -// sha3.h -// 19-Nov-11 Markku-Juhani O. Saarinen <mjos at iki.fi> - -#ifndef SHA3_H -#define SHA3_H - -#include <stddef.h> -#include <stdint.h> - -#ifndef KECCAKF_ROUNDS -#define KECCAKF_ROUNDS 24 -#endif - -#ifndef ROTL64 -#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) -#endif - -// state context -typedef struct { - union { // state: - uint8_t b[200]; // 8-bit bytes - uint64_t q[25]; // 64-bit words - } st; - int pt, rsiz, mdlen; // these don't overflow -} sha3_ctx_t; - -// Compression function. -static void sha3_keccakf(uint64_t st[25]); - -// OpenSSL - like interfece -static int sha3_init(sha3_ctx_t *c, int mdlen); // mdlen = hash output in bytes -static int sha3_update(sha3_ctx_t *c, const void *data, size_t len); -static int sha3_final(void *md, sha3_ctx_t *c); // digest goes to md - -// compute a sha3 hash (md) of given byte length from "in" -#if 0 -static void *sha3(const void *in, size_t inlen, void *md, int mdlen); -#endif - -// SHAKE128 and SHAKE256 extensible-output functions -#define shake128_init(c) sha3_init(c, 16) -#define shake256_init(c) sha3_init(c, 32) -#define shake_update sha3_update - -static void shake_xof(sha3_ctx_t *c); -static void shake_out(sha3_ctx_t *c, void *out, size_t len); - -#endif - diff --git a/Modules/_sha3/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h similarity index 98% rename from Modules/_sha3/clinic/sha3module.c.h rename to Modules/clinic/sha3module.c.h index a0c7c1c043e5..299803a3420b 100644 --- a/Modules/_sha3/clinic/sha3module.c.h +++ b/Modules/clinic/sha3module.c.h @@ -12,7 +12,7 @@ PyDoc_STRVAR(py_sha3_new__doc__, "sha3_224(data=b\'\', /, *, usedforsecurity=True)\n" "--\n" "\n" -"Return a new BLAKE2b hash object."); +"Return a new SHA3 hash object."); static PyObject * py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity); @@ -193,4 +193,4 @@ _sha3_shake_128_hexdigest(SHA3object *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=747c3f34ddd14063 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=907cb475f3dc9ee0 input=a9049054013a1b77]*/ diff --git a/Modules/_sha3/sha3module.c b/Modules/sha3module.c similarity index 75% rename from Modules/_sha3/sha3module.c rename to Modules/sha3module.c index 93abc3b2710e..f05187498a19 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/sha3module.c @@ -22,23 +22,9 @@ #include "Python.h" #include "pycore_strhex.h" // _Py_strhex() #include "pycore_typeobject.h" // _PyType_GetModuleState() -#include "../hashlib.h" - -#include "sha3.c" +#include "hashlib.h" #define SHA3_MAX_DIGESTSIZE 64 /* 64 Bytes (512 Bits) for 224 to 512 */ -#define SHA3_LANESIZE 0 -#define SHA3_state sha3_ctx_t -#define SHA3_init sha3_init -#define SHA3_process sha3_update -#define SHA3_done(state, digest) sha3_final(digest, state) -#define SHA3_squeeze(state, out, len) shake_xof(state), shake_out(state, out, len) -#define SHA3_copystate(dest, src) memcpy(&(dest), &(src), sizeof(SHA3_state)) - -// no optimization -#define KeccakOpt 0 - -typedef enum { SUCCESS = 1, FAIL = 0, BAD_HASHLEN = 2 } HashReturn; typedef struct { PyTypeObject *sha3_224_type; @@ -70,10 +56,11 @@ class _sha3.shake_256 "SHA3object *" "&SHAKE256type" /* The structure for storing SHA3 info */ +#include "_hacl/Hacl_Hash_SHA3.h" + typedef struct { PyObject_HEAD - SHA3_state hash_state; - PyThread_type_lock lock; + Hacl_Streaming_Keccak_state *hash_state; } SHA3object; #include "clinic/sha3module.c.h" @@ -86,10 +73,23 @@ newSHA3object(PyTypeObject *type) if (newobj == NULL) { return NULL; } - newobj->lock = NULL; return newobj; } +static void sha3_update(Hacl_Streaming_Keccak_state *state, uint8_t *buf, Py_ssize_t len) { + /* Note: we explicitly ignore the error code on the basis that it would take > + * 1 billion years to hash more than 2^64 bytes. */ +#if PY_SSIZE_T_MAX > UINT32_MAX + while (len > UINT32_MAX) { + Hacl_Streaming_Keccak_update(state, buf, UINT32_MAX); + len -= UINT32_MAX; + buf += UINT32_MAX; + } +#endif + /* Cast to uint32_t is safe: len <= UINT32_MAX at this point. */ + Hacl_Streaming_Keccak_update(state, buf, (uint32_t) len); +} + /*[clinic input] @classmethod _sha3.sha3_224.__new__ as py_sha3_new @@ -98,14 +98,13 @@ _sha3.sha3_224.__new__ as py_sha3_new * usedforsecurity: bool = True -Return a new BLAKE2b hash object. +Return a new SHA3 hash object. [clinic start generated code]*/ static PyObject * py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) -/*[clinic end generated code: output=90409addc5d5e8b0 input=bcfcdf2e4368347a]*/ +/*[clinic end generated code: output=90409addc5d5e8b0 input=637e5f8f6a93982a]*/ { - HashReturn res; Py_buffer buf = {NULL, NULL}; SHA3State *state = _PyType_GetModuleState(type); SHA3object *self = newSHA3object(type); @@ -116,49 +115,29 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) assert(state != NULL); if (type == state->sha3_224_type) { - res = sha3_init(&self->hash_state, 28); + self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_224); } else if (type == state->sha3_256_type) { - res = sha3_init(&self->hash_state, 32); + self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_256); } else if (type == state->sha3_384_type) { - res = sha3_init(&self->hash_state, 48); + self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_384); } else if (type == state->sha3_512_type) { - res = sha3_init(&self->hash_state, 64); + self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_512); } else if (type == state->shake_128_type) { - res = sha3_init(&self->hash_state, 16); + self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_Shake128); } else if (type == state->shake_256_type) { - res = sha3_init(&self->hash_state, 32); + self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_Shake256); } else { PyErr_BadInternalCall(); goto error; } - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, - "internal error in SHA3 initialize()"); - goto error; - } - if (data) { GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error); - if (buf.len >= HASHLIB_GIL_MINSIZE) { - /* invariant: New objects can't be accessed by other code yet, - * thus it's safe to release the GIL without locking the object. - */ - Py_BEGIN_ALLOW_THREADS - res = SHA3_process(&self->hash_state, buf.buf, buf.len); - Py_END_ALLOW_THREADS - } - else { - res = SHA3_process(&self->hash_state, buf.buf, buf.len); - } - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, - "internal error in SHA3 Update()"); - goto error; - } - PyBuffer_Release(&buf); + sha3_update(self->hash_state, buf.buf, buf.len); } + PyBuffer_Release(&buf); + return (PyObject *)self; error: @@ -177,10 +156,7 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) static void SHA3_dealloc(SHA3object *self) { - if (self->lock) { - PyThread_free_lock(self->lock); - } - + Hacl_Streaming_Keccak_free(self->hash_state); PyTypeObject *tp = Py_TYPE(self); PyObject_Free(self); Py_DECREF(tp); @@ -205,9 +181,7 @@ _sha3_sha3_224_copy_impl(SHA3object *self) if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) { return NULL; } - ENTER_HASHLIB(self); - SHA3_copystate(newobj->hash_state, self->hash_state); - LEAVE_HASHLIB(self); + newobj->hash_state = Hacl_Streaming_Keccak_copy(self->hash_state); return (PyObject *)newobj; } @@ -222,20 +196,12 @@ static PyObject * _sha3_sha3_224_digest_impl(SHA3object *self) /*[clinic end generated code: output=fd531842e20b2d5b input=5b2a659536bbd248]*/ { - unsigned char digest[SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE]; - SHA3_state temp; - HashReturn res; - - ENTER_HASHLIB(self); - SHA3_copystate(temp, self->hash_state); - LEAVE_HASHLIB(self); - res = SHA3_done(&temp, digest); - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, "internal error in SHA3 Final()"); - return NULL; - } + unsigned char digest[SHA3_MAX_DIGESTSIZE]; + // This function errors out if the algorithm is Shake. Here, we know this + // not to be the case, and therefore do not perform error checking. + Hacl_Streaming_Keccak_finish(self->hash_state, digest); return PyBytes_FromStringAndSize((const char *)digest, - self->hash_state.mdlen); + Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -249,21 +215,10 @@ static PyObject * _sha3_sha3_224_hexdigest_impl(SHA3object *self) /*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/ { - unsigned char digest[SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE]; - SHA3_state temp; - HashReturn res; - - /* Get the raw (binary) digest value */ - ENTER_HASHLIB(self); - SHA3_copystate(temp, self->hash_state); - LEAVE_HASHLIB(self); - res = SHA3_done(&temp, digest); - if (res != SUCCESS) { - PyErr_SetString(PyExc_RuntimeError, "internal error in SHA3 Final()"); - return NULL; - } + unsigned char digest[SHA3_MAX_DIGESTSIZE]; + Hacl_Streaming_Keccak_finish(self->hash_state, digest); return _Py_strhex((const char *)digest, - self->hash_state.mdlen); + Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -281,36 +236,8 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data) /*[clinic end generated code: output=d3223352286ed357 input=a887f54dcc4ae227]*/ { Py_buffer buf; - HashReturn res; - GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - - /* add new data, the function takes the length in bits not bytes */ - if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { - self->lock = PyThread_allocate_lock(); - } - /* Once a lock exists all code paths must be synchronized. We have to - * release the GIL even for small buffers as acquiring the lock may take - * an unlimited amount of time when another thread updates this object - * with lots of data. */ - if (self->lock) { - Py_BEGIN_ALLOW_THREADS - PyThread_acquire_lock(self->lock, 1); - res = SHA3_process(&self->hash_state, buf.buf, buf.len); - PyThread_release_lock(self->lock); - Py_END_ALLOW_THREADS - } - else { - res = SHA3_process(&self->hash_state, buf.buf, buf.len); - } - - if (res != SUCCESS) { - PyBuffer_Release(&buf); - PyErr_SetString(PyExc_RuntimeError, - "internal error in SHA3 Update()"); - return NULL; - } - + sha3_update(self->hash_state, buf.buf, buf.len); PyBuffer_Release(&buf); Py_RETURN_NONE; } @@ -328,7 +255,7 @@ static PyMethodDef SHA3_methods[] = { static PyObject * SHA3_get_block_size(SHA3object *self, void *closure) { - int rate = self->hash_state.rsiz; + uint32_t rate = Hacl_Streaming_Keccak_block_len(self->hash_state); return PyLong_FromLong(rate); } @@ -363,14 +290,19 @@ SHA3_get_name(SHA3object *self, void *closure) static PyObject * SHA3_get_digest_size(SHA3object *self, void *closure) { - return PyLong_FromLong(self->hash_state.mdlen); + // Preserving previous behavior: variable-length algorithms return 0 + if (Hacl_Streaming_Keccak_is_shake(self->hash_state)) + return PyLong_FromLong(0); + else + return PyLong_FromLong(Hacl_Streaming_Keccak_hash_len(self->hash_state)); } static PyObject * SHA3_get_capacity_bits(SHA3object *self, void *closure) { - int capacity = 1600 - self->hash_state.rsiz * 8; + uint32_t rate = Hacl_Streaming_Keccak_block_len(self->hash_state) * 8; + int capacity = 1600 - rate; return PyLong_FromLong(capacity); } @@ -378,7 +310,7 @@ SHA3_get_capacity_bits(SHA3object *self, void *closure) static PyObject * SHA3_get_rate_bits(SHA3object *self, void *closure) { - unsigned int rate = self->hash_state.rsiz * 8; + uint32_t rate = Hacl_Streaming_Keccak_block_len(self->hash_state) * 8; return PyLong_FromLong(rate); } @@ -455,28 +387,26 @@ static PyObject * _SHAKE_digest(SHA3object *self, unsigned long digestlen, int hex) { unsigned char *digest = NULL; - SHA3_state temp; PyObject *result = NULL; if (digestlen >= (1 << 29)) { PyErr_SetString(PyExc_ValueError, "length is too large"); return NULL; } - /* ExtractLane needs at least SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE and - * SHA3_LANESIZE extra space. - */ - digest = (unsigned char*)PyMem_Malloc(digestlen + SHA3_LANESIZE); + digest = (unsigned char*)PyMem_Malloc(digestlen); if (digest == NULL) { return PyErr_NoMemory(); } - /* Get the raw (binary) digest value */ - ENTER_HASHLIB(self); - SHA3_copystate(temp, self->hash_state); - LEAVE_HASHLIB(self); - SHA3_squeeze(&temp, digest, digestlen); + /* Get the raw (binary) digest value. The HACL functions errors out if: + * - the algorith is not shake -- not the case here + * - the output length is zero -- we follow the existing behavior and return + * an empty digest, without raising an error */ + if (digestlen > 0) { + Hacl_Streaming_Keccak_squeeze(self->hash_state, digest, digestlen); + } if (hex) { - result = _Py_strhex((const char *)digest, digestlen); + result = _Py_strhex((const char *)digest, digestlen); } else { result = PyBytes_FromStringAndSize((const char *)digest, digestlen); @@ -628,11 +558,8 @@ _sha3_exec(PyObject *m) init_sha3type(shake_256_type, SHAKE256_spec); #undef init_sha3type - if (PyModule_AddIntConstant(m, "keccakopt", KeccakOpt) < 0) { - return -1; - } if (PyModule_AddStringConstant(m, "implementation", - "tiny_sha3") < 0) { + "HACL") < 0) { return -1; } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 8aafcb786a60..28b1517c6f6b 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -375,13 +375,16 @@ <ClCompile Include="..\Modules\_contextvarsmodule.c" /> <ClCompile Include="..\Modules\_csv.c" /> <ClCompile Include="..\Modules\_functoolsmodule.c" /> + <ClCompile Include="..\Modules\_hacl\Hacl_Hash_MD5.c" /> + <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c" /> + <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c" /> + <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA3.c" /> <ClCompile Include="..\Modules\_heapqmodule.c" /> <ClCompile Include="..\Modules\_json.c" /> <ClCompile Include="..\Modules\_localemodule.c" /> <ClCompile Include="..\Modules\_lsprof.c" /> <ClCompile Include="..\Modules\_pickle.c" /> <ClCompile Include="..\Modules\_randommodule.c" /> - <ClCompile Include="..\Modules\_sha3\sha3module.c" /> <ClCompile Include="..\Modules\_sre\sre.c" /> <ClInclude Include="..\Modules\_sre\sre.h" /> <ClInclude Include="..\Modules\_sre\sre_constants.h" /> @@ -404,17 +407,15 @@ <ClCompile Include="..\Modules\itertoolsmodule.c" /> <ClCompile Include="..\Modules\main.c" /> <ClCompile Include="..\Modules\mathmodule.c" /> - <ClCompile Include="..\Modules\_hacl\Hacl_Hash_MD5.c" /> <ClCompile Include="..\Modules\md5module.c" /> <ClCompile Include="..\Modules\mmapmodule.c" /> <ClCompile Include="..\Modules\_opcode.c" /> <ClCompile Include="..\Modules\_operator.c" /> <ClCompile Include="..\Modules\posixmodule.c" /> <ClCompile Include="..\Modules\rotatingtree.c" /> - <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c" /> <ClCompile Include="..\Modules\sha1module.c" /> - <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c" /> <ClCompile Include="..\Modules\sha2module.c" /> + <ClCompile Include="..\Modules\sha3module.c" /> <ClCompile Include="..\Modules\signalmodule.c" /> <ClCompile Include="..\Modules\_statisticsmodule.c" /> <ClCompile Include="..\Modules\symtablemodule.c" /> diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 07476f308333..75e6fbb13f98 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -776,6 +776,15 @@ <ClCompile Include="..\Modules\_functoolsmodule.c"> <Filter>Modules</Filter> </ClCompile> + <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c"> + <Filter>Modules</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c"> + <Filter>Modules</Filter> + </ClCompile> + <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA3.c"> + <Filter>Modules</Filter> + </ClCompile> <ClCompile Include="..\Modules\_heapqmodule.c"> <Filter>Modules</Filter> </ClCompile> @@ -794,9 +803,6 @@ <ClCompile Include="..\Modules\_randommodule.c"> <Filter>Modules</Filter> </ClCompile> - <ClCompile Include="..\Modules\_sha3\sha3module.c"> - <Filter>Modules</Filter> - </ClCompile> <ClCompile Include="..\Modules\_sre\sre.c"> <Filter>Modules</Filter> </ClCompile> @@ -875,16 +881,13 @@ <ClCompile Include="..\Modules\rotatingtree.c"> <Filter>Modules</Filter> </ClCompile> - <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c"> - <Filter>Modules</Filter> - </ClCompile> <ClCompile Include="..\Modules\sha1module.c"> <Filter>Modules</Filter> </ClCompile> - <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c"> + <ClCompile Include="..\Modules\sha2module.c"> <Filter>Modules</Filter> </ClCompile> - <ClCompile Include="..\Modules\sha2module.c"> + <ClCompile Include="..\Modules\sha3module.c"> <Filter>Modules</Filter> </ClCompile> <ClCompile Include="..\Modules\signalmodule.c"> diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 5924ab7860d8..9bd54db0f59c 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -114,6 +114,7 @@ def clean_lines(text): Modules/md5module.c Modules/_hacl/include Modules/sha1module.c Modules/_hacl/include Modules/sha2module.c Modules/_hacl/include +Modules/sha3module.c Modules/_hacl/include Objects/stringlib/*.h Objects # possible system-installed headers, just in case @@ -271,13 +272,6 @@ def clean_lines(text): Modules/expat/xmlparse.c XML_POOR_ENTROPY 1 Modules/_dbmmodule.c HAVE_GDBM_DASH_NDBM_H 1 -# from Modules/_sha3/sha3module.c -Modules/_sha3/kcp/KeccakP-1600-inplace32BI.c PLATFORM_BYTE_ORDER 4321 # force big-endian -Modules/_sha3/kcp/*.c KeccakOpt 64 -Modules/_sha3/kcp/*.c KeccakP200_excluded 1 -Modules/_sha3/kcp/*.c KeccakP400_excluded 1 -Modules/_sha3/kcp/*.c KeccakP800_excluded 1 - # others Modules/_sre/sre_lib.h LOCAL(type) static inline type Modules/_sre/sre_lib.h SRE(F) sre_ucs2_##F From webhook-mailer at python.org Mon May 8 04:42:19 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 08 May 2023 08:42:19 -0000 Subject: [Python-checkins] [3.11] gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bit builds (#103902) (#104285) Message-ID: <mailman.236.1683535341.13550.python-checkins@python.org> https://github.com/python/cpython/commit/681d5028bda41fb0755da443cea6be24bd2a0fdd commit: 681d5028bda41fb0755da443cea6be24bd2a0fdd branch: 3.11 author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-08T08:41:34Z summary: [3.11] gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bit builds (#103902) (#104285) files: A Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst M Lib/test/test_sqlite3/test_dbapi.py M Modules/_sqlite/clinic/connection.c.h M Modules/_sqlite/connection.c diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 9d94ddda95bd..899f5cfbd319 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -1461,6 +1461,14 @@ def test_blob_closed_db_read(self): "Cannot operate on a closed database", blob.read) + def test_blob_32bit_rowid(self): + # gh-100370: we should not get an OverflowError for 32-bit rowids + with memory_database() as cx: + rowid = 2**32 + cx.execute("create table t(t blob)") + cx.execute("insert into t(rowid, t) values (?, zeroblob(1))", (rowid,)) + cx.blobopen('t', 't', rowid) + @threading_helper.requires_working_threading() class ThreadTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst new file mode 100644 index 000000000000..9022d55c48cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst @@ -0,0 +1,2 @@ +Fix potential :exc:`OverflowError` in :meth:`sqlite3.Connection.blobopen` +for 32-bit builds. Patch by Erlend E. Aasland. diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index 62d31b787ad7..4bdf98b6933e 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -162,7 +162,7 @@ PyDoc_STRVAR(blobopen__doc__, static PyObject * blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, - int row, int readonly, const char *name); + sqlite3_int64 row, int readonly, const char *name); static PyObject * blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -174,7 +174,7 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; const char *table; const char *col; - int row; + sqlite3_int64 row; int readonly = 0; const char *name = "main"; @@ -208,8 +208,7 @@ blobopen(pysqlite_Connection *self, PyObject *const *args, Py_ssize_t nargs, PyO PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - row = _PyLong_AsInt(args[2]); - if (row == -1 && PyErr_Occurred()) { + if (!sqlite3_int64_converter(args[2], &row)) { goto exit; } if (!noptargs) { @@ -1237,4 +1236,4 @@ getlimit(pysqlite_Connection *self, PyObject *arg) #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=8818c1c3ec9425aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=67e5b3dbade4a15b input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 20982558840b..9c7eb85df3b7 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -92,6 +92,20 @@ isolation_level_converter(PyObject *str_or_none, const char **result) return 1; } +static int +sqlite3_int64_converter(PyObject *obj, sqlite3_int64 *result) +{ + if (!PyLong_Check(obj)) { + PyErr_SetString(PyExc_TypeError, "expected 'int'"); + return 0; + } + *result = _pysqlite_long_as_int64(obj); + if (PyErr_Occurred()) { + return 0; + } + return 1; +} + #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self))) #include "clinic/connection.c.h" #undef clinic_state @@ -137,8 +151,12 @@ class IsolationLevel_converter(CConverter): type = "const char *" converter = "isolation_level_converter" +class sqlite3_int64_converter(CConverter): + type = "sqlite3_int64" + converter = "sqlite3_int64_converter" + [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=cbcfe85b253061c2]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=e9bee126e0500e61]*/ // NB: This needs to be in sync with the sqlite3.connect docstring /*[clinic input] @@ -401,7 +419,7 @@ _sqlite3.Connection.blobopen as blobopen Table name. column as col: str Column name. - row: int + row: sqlite3_int64 Row index. / * @@ -415,8 +433,8 @@ Open and return a BLOB object. static PyObject * blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, - int row, int readonly, const char *name) -/*[clinic end generated code: output=0c8e2e58516d0b5c input=1e7052516acfc94d]*/ + sqlite3_int64 row, int readonly, const char *name) +/*[clinic end generated code: output=6a02d43efb885d1c input=4180b11a0591d80d]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; From webhook-mailer at python.org Mon May 8 07:59:41 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Mon, 08 May 2023 11:59:41 -0000 Subject: [Python-checkins] gh-97696: Improve and fix documentation for asyncio eager tasks (#104256) Message-ID: <mailman.237.1683547182.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c2683fc46d775d6c4afcb23658c0fd1e328e3c53 commit: c2683fc46d775d6c4afcb23658c0fd1e328e3c53 branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-08T17:29:34+05:30 summary: gh-97696: Improve and fix documentation for asyncio eager tasks (#104256) files: M Doc/library/asyncio-task.rst M Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index a46ebc1c3d25..b2d7362a9de2 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -560,6 +560,13 @@ Eager Task Factory using the provided *custom_task_constructor* when creating a new task instead of the default :class:`Task`. + *custom_task_constructor* must be a *callable* with the signature matching + the signature of :class:`Task.__init__ <Task>`. + The callable must return a :class:`asyncio.Task`-compatible object. + + This function returns a *callable* intended to be used as a task factory of an + event loop via :meth:`loop.set_task_factory(factory) <loop.set_task_factory>`). + .. versionadded:: 3.12 @@ -1014,7 +1021,7 @@ Introspection Task Object =========== -.. class:: Task(coro, *, loop=None, name=None, context=None) +.. class:: Task(coro, *, loop=None, name=None, context=None, eager_start=False) A :class:`Future-like <Future>` object that runs a Python :ref:`coroutine <coroutine>`. Not thread-safe. @@ -1054,6 +1061,13 @@ Task Object If no *context* is provided, the Task copies the current context and later runs its coroutine in the copied context. + An optional keyword-only *eager_start* argument allows eagerly starting + the execution of the :class:`asyncio.Task` at task creation time. + If set to ``True`` and the event loop is running, the task will start + executing the coroutine immediately, until the first time the coroutine + blocks. If the coroutine returns or raises without blocking, the task + will be finished eagerly and will skip scheduling to the event loop. + .. versionchanged:: 3.7 Added support for the :mod:`contextvars` module. @@ -1067,6 +1081,9 @@ Task Object .. versionchanged:: 3.11 Added the *context* parameter. + .. versionchanged:: 3.12 + Added the *eager_start* parameter. + .. method:: done() Return ``True`` if the Task is *done*. diff --git a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst index 59870de3e02e..ced3b7cea049 100644 --- a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst +++ b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst @@ -1 +1,2 @@ -Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`. Skip scheduling done callbacks when all tasks finish without blocking. +Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`. +Skip scheduling a done callback if a TaskGroup task completes eagerly. From webhook-mailer at python.org Mon May 8 08:04:50 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Mon, 08 May 2023 12:04:50 -0000 Subject: [Python-checkins] [3.11] gh-104265 Disallow instantiation of `_csv.Reader` and `_csv.Writer` (GH-104266) (#104278) Message-ID: <mailman.238.1683547491.13550.python-checkins@python.org> https://github.com/python/cpython/commit/065e2ae99a4ac81f9c8f56b73333349b0b4cc28a commit: 065e2ae99a4ac81f9c8f56b73333349b0b4cc28a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-08T17:34:43+05:30 summary: [3.11] gh-104265 Disallow instantiation of `_csv.Reader` and `_csv.Writer` (GH-104266) (#104278) gh-104265 Disallow instantiation of `_csv.Reader` and `_csv.Writer` (GH-104266) (cherry picked from commit 06c2a4858b8806abc700a0471434067910db54ec) Co-authored-by: chgnrdv <52372310+chgnrdv at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst M Lib/test/test_csv.py M Modules/_csv.c diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 834217bf6030..05653a268417 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -10,7 +10,7 @@ import gc import pickle from test import support -from test.support import warnings_helper +from test.support import warnings_helper, import_helper, check_disallow_instantiation from itertools import permutations from textwrap import dedent from collections import OrderedDict @@ -1390,5 +1390,12 @@ def test_subclassable(self): # issue 44089 class Foo(csv.Error): ... + @support.cpython_only + def test_disallow_instantiation(self): + _csv = import_helper.import_module("_csv") + for tp in _csv.Reader, _csv.Writer: + with self.subTest(tp=tp): + check_disallow_instantiation(self, tp) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst new file mode 100644 index 000000000000..9c582844bf90 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst @@ -0,0 +1,4 @@ +Prevent possible crash by disallowing instantiation of the +:class:`!_csv.Reader` and :class:`!_csv.Writer` types. +The regression was introduced in 3.10.0a4 with PR 23224 (:issue:`14935`). +Patch by Radislav Chugunov. diff --git a/Modules/_csv.c b/Modules/_csv.c index 7519da6807fe..7314d9c70537 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -1000,7 +1000,7 @@ PyType_Spec Reader_Type_spec = { .name = "_csv.reader", .basicsize = sizeof(ReaderObj), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = Reader_Type_slots }; @@ -1425,7 +1425,7 @@ PyType_Spec Writer_Type_spec = { .name = "_csv.writer", .basicsize = sizeof(WriterObj), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), .slots = Writer_Type_slots, }; From webhook-mailer at python.org Mon May 8 09:40:58 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 08 May 2023 13:40:58 -0000 Subject: [Python-checkins] gh-102500: Remove mention of bytes shorthand (#104281) Message-ID: <mailman.239.1683553259.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1f5679540ca4aa5c0eae06d3a2d5eda34b47e041 commit: 1f5679540ca4aa5c0eae06d3a2d5eda34b47e041 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-08T14:40:51+01:00 summary: gh-102500: Remove mention of bytes shorthand (#104281) The bytes shorthand was removed in PEP 688: https://peps.python.org/pep-0688/#no-special-meaning-for-bytes I also remove the reference to `collections.abc.ByteString`, since that object is deprecated (#91896) and has different semantics (#102092) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 162041fc7a84..ebab1389f07e 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2130,15 +2130,10 @@ Corresponding to collections in :mod:`collections.abc` .. class:: ByteString(Sequence[int]) - A generic version of :class:`collections.abc.ByteString`. - This type represents the types :class:`bytes`, :class:`bytearray`, and :class:`memoryview` of byte sequences. - As a shorthand for this type, :class:`bytes` can be used to - annotate arguments of any of the types mentioned above. - - .. deprecated:: 3.9 + .. deprecated-removed:: 3.9 3.14 Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) @@ -2977,6 +2972,8 @@ convenience. This is subject to change, and not all deprecations are listed. | ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | | collections | | | | +----------------------------------+---------------+-------------------+----------------+ +| ``typing.ByteString`` | 3.9 | 3.14 | :gh:`91896` | ++----------------------------------+---------------+-------------------+----------------+ | ``typing.Text`` | 3.11 | Undecided | :gh:`92332` | +----------------------------------+---------------+-------------------+----------------+ | ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | From webhook-mailer at python.org Mon May 8 10:04:02 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 08 May 2023 14:04:02 -0000 Subject: [Python-checkins] Trim trailing whitespace and test on CI (#104275) Message-ID: <mailman.240.1683554644.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d513ddee94a05783b98f2b55f8fc0a4efbb9be82 commit: d513ddee94a05783b98f2b55f8fc0a4efbb9be82 branch: main author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-08T17:03:52+03:00 summary: Trim trailing whitespace and test on CI (#104275) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: A .github/workflows/lint.yml A .pre-commit-config.yaml M .github/CODEOWNERS M Modules/_blake2/blake2module.h M Modules/_blake2/impl/blake2b-round.h M Modules/_blake2/impl/blake2s-load-xop.h M Modules/_blake2/impl/blake2s-round.h M Modules/_ctypes/_ctypes_test.c M Modules/_testcapi/immortal.c M Modules/termios.c M Parser/tokenizer.c M Tools/msi/bundle/bootstrap/pch.h M Tools/msi/bundle/bootstrap/resource.h diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3422ef835279..d40519e40d3c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,6 +7,9 @@ # GitHub .github/** @ezio-melotti @hugovk +# pre-commit +.pre-commit-config.yaml @hugovk @AlexWaygood + # Build system configure* @erlend-aasland @corona10 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000000..4481ea80bfd9 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,22 @@ +name: Lint + +on: [push, pull_request, workflow_dispatch] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout at v3 + - uses: actions/setup-python at v4 + with: + python-version: "3.x" + - uses: pre-commit/action at v3.0.0 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000000..808622f19a3d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-yaml + - id: trailing-whitespace + types_or: [c, python, rst] diff --git a/Modules/_blake2/blake2module.h b/Modules/_blake2/blake2module.h index aa8f281178ea..c8144ec9d48d 100644 --- a/Modules/_blake2/blake2module.h +++ b/Modules/_blake2/blake2module.h @@ -38,6 +38,6 @@ #endif // HAVE_LIBB2 // for secure_zero_memory(), store32(), store48(), and store64() -#include "impl/blake2-impl.h" +#include "impl/blake2-impl.h" #endif // Py_BLAKE2MODULE_H diff --git a/Modules/_blake2/impl/blake2b-round.h b/Modules/_blake2/impl/blake2b-round.h index cebc22550da4..5b452c4d63ba 100644 --- a/Modules/_blake2/impl/blake2b-round.h +++ b/Modules/_blake2/impl/blake2b-round.h @@ -62,7 +62,7 @@ \ row2l = _mm_roti_epi64(row2l, -24); \ row2h = _mm_roti_epi64(row2h, -24); \ - + #define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \ row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ @@ -81,7 +81,7 @@ \ row2l = _mm_roti_epi64(row2l, -63); \ row2h = _mm_roti_epi64(row2h, -63); \ - + #if defined(HAVE_SSSE3) #define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \ t0 = _mm_alignr_epi8(row2h, row2l, 8); \ diff --git a/Modules/_blake2/impl/blake2s-load-xop.h b/Modules/_blake2/impl/blake2s-load-xop.h index ac591a77d191..14d9e7f76406 100644 --- a/Modules/_blake2/impl/blake2s-load-xop.h +++ b/Modules/_blake2/impl/blake2s-load-xop.h @@ -166,7 +166,7 @@ buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(7)) ); #define LOAD_MSG_8_3(buf) \ t0 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(6),TOB(1),TOB(0),TOB(0)) ); \ buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(5),TOB(4)) ); \ - + #define LOAD_MSG_8_4(buf) \ buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(4),TOB(7),TOB(2)) ); diff --git a/Modules/_blake2/impl/blake2s-round.h b/Modules/_blake2/impl/blake2s-round.h index 1e2f2b7f59bd..3af4be35bee5 100644 --- a/Modules/_blake2/impl/blake2s-round.h +++ b/Modules/_blake2/impl/blake2s-round.h @@ -86,6 +86,6 @@ LOAD_MSG_ ##r ##_4(buf4); \ G2(row1,row2,row3,row4,buf4); \ UNDIAGONALIZE(row1,row2,row3,row4); \ - + #endif diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index ce652b362d5b..ddfb2c8a332a 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -1036,7 +1036,7 @@ EXPORT (HRESULT) KeepObject(IUnknown *punk) #ifdef MS_WIN32 -// i38748: c stub for testing stack corruption +// i38748: c stub for testing stack corruption // When executing a Python callback with a long and a long long typedef long(__stdcall *_test_i38748_funcType)(long, long long); diff --git a/Modules/_testcapi/immortal.c b/Modules/_testcapi/immortal.c index 10e1733d08a9..9f81389811c6 100644 --- a/Modules/_testcapi/immortal.c +++ b/Modules/_testcapi/immortal.c @@ -1,6 +1,6 @@ #include "parts.h" -int verify_immortality(PyObject *object) +int verify_immortality(PyObject *object) { assert(_Py_IsImmortal(object)); Py_ssize_t old_count = Py_REFCNT(object); diff --git a/Modules/termios.c b/Modules/termios.c index 169a36fc6477..6dc8200572bc 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -85,7 +85,7 @@ termios_tcgetattr_impl(PyObject *module, int fd) int r; Py_BEGIN_ALLOW_THREADS - r = tcgetattr(fd, &mode); + r = tcgetattr(fd, &mode); Py_END_ALLOW_THREADS if (r == -1) { return PyErr_SetFromErrno(state->TermiosError); @@ -372,7 +372,7 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) #if defined(TIOCGWINSZ) termiosmodulestate *state = PyModule_GetState(module); struct winsize w; - int r; + int r; Py_BEGIN_ALLOW_THREADS r = ioctl(fd, TIOCGWINSZ, &w); diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 52d0d9a534cb..91ffabac56c7 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -48,7 +48,7 @@ static inline tokenizer_mode* TOK_GET_MODE(struct tok_state* tok) { } static inline tokenizer_mode* TOK_NEXT_MODE(struct tok_state* tok) { assert(tok->tok_mode_stack_index >= 0); - assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL); + assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL); return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]); } #else diff --git a/Tools/msi/bundle/bootstrap/pch.h b/Tools/msi/bundle/bootstrap/pch.h index b0aa5111dabd..6d0974b34c61 100644 --- a/Tools/msi/bundle/bootstrap/pch.h +++ b/Tools/msi/bundle/bootstrap/pch.h @@ -5,7 +5,7 @@ // The license and further copyright text can be found in the file // LICENSE.TXT at the root directory of the distribution. // </copyright> -// +// // <summary> // Precompiled header for standard bootstrapper application. // </summary> diff --git a/Tools/msi/bundle/bootstrap/resource.h b/Tools/msi/bundle/bootstrap/resource.h index 53c03c319f09..d951e651f6d2 100644 --- a/Tools/msi/bundle/bootstrap/resource.h +++ b/Tools/msi/bundle/bootstrap/resource.h @@ -14,7 +14,7 @@ // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 From webhook-mailer at python.org Mon May 8 10:19:31 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 08 May 2023 14:19:31 -0000 Subject: [Python-checkins] gh-103193: Improve `getattr_static` test coverage (#104286) Message-ID: <mailman.241.1683555573.13550.python-checkins@python.org> https://github.com/python/cpython/commit/921185ed050efbca2f0adeab79f676b7f8cc3660 commit: 921185ed050efbca2f0adeab79f676b7f8cc3660 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-08T15:18:36+01:00 summary: gh-103193: Improve `getattr_static` test coverage (#104286) files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index dd0325a43e0f..d2b2f3171e78 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2187,6 +2187,35 @@ class Thing(metaclass=Meta): inspect.getattr_static(Thing, "spam") self.assertFalse(Thing.executed) + def test_custom___getattr__(self): + test = self + test.called = False + + class Foo: + def __getattr__(self, attr): + test.called = True + return {} + + with self.assertRaises(AttributeError): + inspect.getattr_static(Foo(), 'whatever') + + self.assertFalse(test.called) + + def test_custom___getattribute__(self): + test = self + test.called = False + + class Foo: + def __getattribute__(self, attr): + test.called = True + return {} + + with self.assertRaises(AttributeError): + inspect.getattr_static(Foo(), 'really_could_be_anything') + + self.assertFalse(test.called) + + class TestGetGeneratorState(unittest.TestCase): def setUp(self): From webhook-mailer at python.org Mon May 8 10:24:21 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 08 May 2023 14:24:21 -0000 Subject: [Python-checkins] [3.11] gh-102500: Remove mention of bytes shorthand (#104281) (#104288) Message-ID: <mailman.242.1683555862.13550.python-checkins@python.org> https://github.com/python/cpython/commit/499b79d0b950300e8b5fd3b5be76bfc144b14840 commit: 499b79d0b950300e8b5fd3b5be76bfc144b14840 branch: 3.11 author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-08T15:23:10+01:00 summary: [3.11] gh-102500: Remove mention of bytes shorthand (#104281) (#104288) gh-102500: Remove mention of bytes shorthand (#104281) The bytes shorthand was removed in PEP 688: https://peps.python.org/pep-0688/#no-special-meaning-for-bytes The reference to collections.abc.ByteString is also removed, since that object is deprecated (#91896) and has different semantics (#102092) Although PEP 688 is new in Python 3.12, type checkers are expected to implement the new semantics for type annotations even if users are using an older version of Python, so this docs PR is backported to Python 3.11. Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 00d74f7dc31e..de716b3f2227 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2090,17 +2090,11 @@ Corresponding to collections in :mod:`collections.abc` .. class:: ByteString(Sequence[int]) - A generic version of :class:`collections.abc.ByteString`. - This type represents the types :class:`bytes`, :class:`bytearray`, and :class:`memoryview` of byte sequences. - As a shorthand for this type, :class:`bytes` can be used to - annotate arguments of any of the types mentioned above. - - .. deprecated:: 3.9 - :class:`collections.abc.ByteString` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. deprecated-removed:: 3.9 3.14 + Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) @@ -2892,5 +2886,7 @@ convenience. This is subject to change, and not all deprecations are listed. | ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | | collections | | | | +----------------------------------+---------------+-------------------+----------------+ +| ``typing.ByteString`` | 3.9 | 3.14 | :gh:`91896` | ++----------------------------------+---------------+-------------------+----------------+ | ``typing.Text`` | 3.11 | Undecided | :gh:`92332` | +----------------------------------+---------------+-------------------+----------------+ From webhook-mailer at python.org Mon May 8 10:44:17 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 08 May 2023 14:44:17 -0000 Subject: [Python-checkins] [3.11] gh-103193: Improve `getattr_static` test coverage (GH-104286) (#104290) Message-ID: <mailman.243.1683557058.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d54f6441ceb17b48b047072dabca92ce4cd683b4 commit: d54f6441ceb17b48b047072dabca92ce4cd683b4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-08T14:44:10Z summary: [3.11] gh-103193: Improve `getattr_static` test coverage (GH-104286) (#104290) gh-103193: Improve `getattr_static` test coverage (GH-104286) (cherry picked from commit 921185ed050efbca2f0adeab79f676b7f8cc3660) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index efcbd63450b3..c44eed027e94 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2106,6 +2106,35 @@ class Thing(metaclass=Meta): inspect.getattr_static(Thing, "spam") self.assertFalse(Thing.executed) + def test_custom___getattr__(self): + test = self + test.called = False + + class Foo: + def __getattr__(self, attr): + test.called = True + return {} + + with self.assertRaises(AttributeError): + inspect.getattr_static(Foo(), 'whatever') + + self.assertFalse(test.called) + + def test_custom___getattribute__(self): + test = self + test.called = False + + class Foo: + def __getattribute__(self, attr): + test.called = True + return {} + + with self.assertRaises(AttributeError): + inspect.getattr_static(Foo(), 'really_could_be_anything') + + self.assertFalse(test.called) + + class TestGetGeneratorState(unittest.TestCase): def setUp(self): From webhook-mailer at python.org Mon May 8 12:32:26 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 08 May 2023 16:32:26 -0000 Subject: [Python-checkins] GH-104145: Use fully-qualified cross reference types for the bisect module (#104172) Message-ID: <mailman.244.1683563547.13550.python-checkins@python.org> https://github.com/python/cpython/commit/76eef552f3653179782afcc5063f10560a6e1a80 commit: 76eef552f3653179782afcc5063f10560a6e1a80 branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-08T17:32:18+01:00 summary: GH-104145: Use fully-qualified cross reference types for the bisect module (#104172) files: M Doc/library/bisect.rst diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst index e3c8c801904b..8022c596f0af 100644 --- a/Doc/library/bisect.rst +++ b/Doc/library/bisect.rst @@ -24,6 +24,8 @@ method to determine whether a value has been found. Instead, the functions only call the :meth:`__lt__` method and will return an insertion point between values in an array. +.. _bisect functions: + The following functions are provided: @@ -55,7 +57,7 @@ The following functions are provided: .. function:: bisect_right(a, x, lo=0, hi=len(a), *, key=None) bisect(a, x, lo=0, hi=len(a), *, key=None) - Similar to :func:`bisect_left`, but returns an insertion point which comes + Similar to :py:func:`~bisect.bisect_left`, but returns an insertion point which comes after (to the right of) any existing entries of *x* in *a*. The returned insertion point *ip* partitions the array *a* into two slices @@ -70,7 +72,7 @@ The following functions are provided: Insert *x* in *a* in sorted order. - This function first runs :func:`bisect_left` to locate an insertion point. + This function first runs :py:func:`~bisect.bisect_left` to locate an insertion point. Next, it runs the :meth:`insert` method on *a* to insert *x* at the appropriate position to maintain sort order. @@ -87,10 +89,10 @@ The following functions are provided: .. function:: insort_right(a, x, lo=0, hi=len(a), *, key=None) insort(a, x, lo=0, hi=len(a), *, key=None) - Similar to :func:`insort_left`, but inserting *x* in *a* after any existing + Similar to :py:func:`~bisect.insort_left`, but inserting *x* in *a* after any existing entries of *x*. - This function first runs :func:`bisect_right` to locate an insertion point. + This function first runs :py:func:`~bisect.bisect_right` to locate an insertion point. Next, it runs the :meth:`insert` method on *a* to insert *x* at the appropriate position to maintain sort order. @@ -120,7 +122,7 @@ thoughts in mind: they are used. Consequently, if the search functions are used in a loop, the key function may be called again and again on the same array elements. If the key function isn't fast, consider wrapping it with - :func:`functools.cache` to avoid duplicate computations. Alternatively, + :py:func:`functools.cache` to avoid duplicate computations. Alternatively, consider searching an array of precomputed keys to locate the insertion point (as shown in the examples section below). @@ -140,7 +142,7 @@ thoughts in mind: Searching Sorted Lists ---------------------- -The above :func:`bisect` functions are useful for finding insertion points but +The above `bisect functions`_ are useful for finding insertion points but can be tricky or awkward to use for common searching tasks. The following five functions show how to transform them into the standard lookups for sorted lists:: @@ -186,8 +188,8 @@ Examples .. _bisect-example: -The :func:`bisect` function can be useful for numeric table lookups. This -example uses :func:`bisect` to look up a letter grade for an exam score (say) +The :py:func:`~bisect.bisect` function can be useful for numeric table lookups. This +example uses :py:func:`~bisect.bisect` to look up a letter grade for an exam score (say) based on a set of ordered numeric breakpoints: 90 and up is an 'A', 80 to 89 is a 'B', and so on:: @@ -198,8 +200,8 @@ a 'B', and so on:: >>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]] ['F', 'A', 'C', 'C', 'B', 'A', 'A'] -The :func:`bisect` and :func:`insort` functions also work with lists of -tuples. The *key* argument can serve to extract the field used for ordering +The :py:func:`~bisect.bisect` and :py:func:`~bisect.insort` functions also work with +lists of tuples. The *key* argument can serve to extract the field used for ordering records in a table:: >>> from collections import namedtuple From webhook-mailer at python.org Mon May 8 12:41:27 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 08 May 2023 16:41:27 -0000 Subject: [Python-checkins] [3.11] GH-104145: Use fully-qualified cross reference types for the bisect module (GH-104172) (#104295) Message-ID: <mailman.245.1683564087.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8a6ff59e09af4626a2c08285b850673e7870c03b commit: 8a6ff59e09af4626a2c08285b850673e7870c03b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-08T17:41:20+01:00 summary: [3.11] GH-104145: Use fully-qualified cross reference types for the bisect module (GH-104172) (#104295) GH-104145: Use fully-qualified cross reference types for the bisect module (GH-104172) (cherry picked from commit 76eef552f3653179782afcc5063f10560a6e1a80) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/library/bisect.rst diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst index 19aeae0dc60e..d4abd7a6313d 100644 --- a/Doc/library/bisect.rst +++ b/Doc/library/bisect.rst @@ -18,6 +18,8 @@ approach. The module is called :mod:`bisect` because it uses a basic bisection algorithm to do its work. The source code may be most useful as a working example of the algorithm (the boundary conditions are already right!). +.. _bisect functions: + The following functions are provided: @@ -48,7 +50,7 @@ The following functions are provided: .. function:: bisect_right(a, x, lo=0, hi=len(a), *, key=None) bisect(a, x, lo=0, hi=len(a), *, key=None) - Similar to :func:`bisect_left`, but returns an insertion point which comes + Similar to :py:func:`~bisect.bisect_left`, but returns an insertion point which comes after (to the right of) any existing entries of *x* in *a*. The returned insertion point *i* partitions the array *a* into two halves so @@ -70,7 +72,7 @@ The following functions are provided: Insert *x* in *a* in sorted order. - This function first runs :func:`bisect_left` to locate an insertion point. + This function first runs :py:func:`~bisect.bisect_left` to locate an insertion point. Next, it runs the :meth:`insert` method on *a* to insert *x* at the appropriate position to maintain sort order. @@ -87,10 +89,10 @@ The following functions are provided: .. function:: insort_right(a, x, lo=0, hi=len(a), *, key=None) insort(a, x, lo=0, hi=len(a), *, key=None) - Similar to :func:`insort_left`, but inserting *x* in *a* after any existing + Similar to :py:func:`~bisect.insort_left`, but inserting *x* in *a* after any existing entries of *x*. - This function first runs :func:`bisect_right` to locate an insertion point. + This function first runs :py:func:`~bisect.bisect_right` to locate an insertion point. Next, it runs the :meth:`insert` method on *a* to insert *x* at the appropriate position to maintain sort order. @@ -120,7 +122,7 @@ thoughts in mind: they are used. Consequently, if the search functions are used in a loop, the key function may be called again and again on the same array elements. If the key function isn't fast, consider wrapping it with - :func:`functools.cache` to avoid duplicate computations. Alternatively, + :py:func:`functools.cache` to avoid duplicate computations. Alternatively, consider searching an array of precomputed keys to locate the insertion point (as shown in the examples section below). @@ -140,7 +142,7 @@ thoughts in mind: Searching Sorted Lists ---------------------- -The above :func:`bisect` functions are useful for finding insertion points but +The above `bisect functions`_ are useful for finding insertion points but can be tricky or awkward to use for common searching tasks. The following five functions show how to transform them into the standard lookups for sorted lists:: @@ -186,8 +188,8 @@ Examples .. _bisect-example: -The :func:`bisect` function can be useful for numeric table lookups. This -example uses :func:`bisect` to look up a letter grade for an exam score (say) +The :py:func:`~bisect.bisect` function can be useful for numeric table lookups. This +example uses :py:func:`~bisect.bisect` to look up a letter grade for an exam score (say) based on a set of ordered numeric breakpoints: 90 and up is an 'A', 80 to 89 is a 'B', and so on:: @@ -198,8 +200,8 @@ a 'B', and so on:: >>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]] ['F', 'A', 'C', 'C', 'B', 'A', 'A'] -The :func:`bisect` and :func:`insort` functions also work with lists of -tuples. The *key* argument can serve to extract the field used for ordering +The :py:func:`~bisect.bisect` and :py:func:`~bisect.insort` functions also work with +lists of tuples. The *key* argument can serve to extract the field used for ordering records in a table:: >>> from collections import namedtuple From webhook-mailer at python.org Mon May 8 12:52:18 2023 From: webhook-mailer at python.org (gpshead) Date: Mon, 08 May 2023 16:52:18 -0000 Subject: [Python-checkins] gh-99108: fix typo in Modules/Setup (#104293) Message-ID: <mailman.246.1683564739.13550.python-checkins@python.org> https://github.com/python/cpython/commit/874010c6cab2e079069767619af2e0eab05ad0b2 commit: 874010c6cab2e079069767619af2e0eab05ad0b2 branch: main author: Jonathan Protzenko <protz at microsoft.com> committer: gpshead <greg at krypto.org> date: 2023-05-08T09:52:11-07:00 summary: gh-99108: fix typo in Modules/Setup (#104293) case sensitive filename files: M Modules/Setup diff --git a/Modules/Setup b/Modules/Setup index e5bc078af62c..312e99fea530 100644 --- a/Modules/Setup +++ b/Modules/Setup @@ -166,7 +166,7 @@ PYTHONPATH=$(COREPYTHONPATH) #_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE #_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE #_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a -#_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_sha3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE +#_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE # text encodings and unicode #_codecs_cn cjkcodecs/_codecs_cn.c From webhook-mailer at python.org Mon May 8 12:52:49 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 08 May 2023 16:52:49 -0000 Subject: [Python-checkins] gh-104223: Fix issues with inheriting from buffer classes (#104227) Message-ID: <mailman.247.1683564770.13550.python-checkins@python.org> https://github.com/python/cpython/commit/405eacc1b87a42e19fd176131e70537f0539e05e commit: 405eacc1b87a42e19fd176131e70537f0539e05e branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-08T09:52:41-07:00 summary: gh-104223: Fix issues with inheriting from buffer classes (#104227) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Include/cpython/memoryobject.h M Include/internal/pycore_memoryobject.h M Lib/test/test_buffer.py M Objects/bytearrayobject.c M Objects/memoryobject.c M Objects/typeobject.c diff --git a/Include/cpython/memoryobject.h b/Include/cpython/memoryobject.h index deab3cc89f72..3837fa8c6ab5 100644 --- a/Include/cpython/memoryobject.h +++ b/Include/cpython/memoryobject.h @@ -24,6 +24,7 @@ typedef struct { #define _Py_MEMORYVIEW_FORTRAN 0x004 /* Fortran contiguous layout */ #define _Py_MEMORYVIEW_SCALAR 0x008 /* scalar: ndim = 0 */ #define _Py_MEMORYVIEW_PIL 0x010 /* PIL-style layout */ +#define _Py_MEMORYVIEW_RESTRICTED 0x020 /* Disallow new references to the memoryview's buffer */ typedef struct { PyObject_VAR_HEAD diff --git a/Include/internal/pycore_memoryobject.h b/Include/internal/pycore_memoryobject.h index acc12c927517..fe19e3f9611a 100644 --- a/Include/internal/pycore_memoryobject.h +++ b/Include/internal/pycore_memoryobject.h @@ -9,7 +9,8 @@ extern "C" { #endif PyObject * -PyMemoryView_FromObjectAndFlags(PyObject *v, int flags); +_PyMemoryView_FromBufferProc(PyObject *v, int flags, + getbufferproc bufferproc); #ifdef __cplusplus } diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index b6e82ad4db26..2c65ae811481 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -4579,6 +4579,176 @@ def test_c_buffer(self): buf.__release_buffer__(mv) self.assertEqual(buf.references, 0) + def test_inheritance(self): + class A(bytearray): + def __buffer__(self, flags): + return super().__buffer__(flags) + + a = A(b"hello") + mv = memoryview(a) + self.assertEqual(mv.tobytes(), b"hello") + + def test_inheritance_releasebuffer(self): + rb_call_count = 0 + class B(bytearray): + def __buffer__(self, flags): + return super().__buffer__(flags) + def __release_buffer__(self, view): + nonlocal rb_call_count + rb_call_count += 1 + super().__release_buffer__(view) + + b = B(b"hello") + with memoryview(b) as mv: + self.assertEqual(mv.tobytes(), b"hello") + self.assertEqual(rb_call_count, 0) + self.assertEqual(rb_call_count, 1) + + def test_inherit_but_return_something_else(self): + class A(bytearray): + def __buffer__(self, flags): + return memoryview(b"hello") + + a = A(b"hello") + with memoryview(a) as mv: + self.assertEqual(mv.tobytes(), b"hello") + + rb_call_count = 0 + rb_raised = False + class B(bytearray): + def __buffer__(self, flags): + return memoryview(b"hello") + def __release_buffer__(self, view): + nonlocal rb_call_count + rb_call_count += 1 + try: + super().__release_buffer__(view) + except ValueError: + nonlocal rb_raised + rb_raised = True + + b = B(b"hello") + with memoryview(b) as mv: + self.assertEqual(mv.tobytes(), b"hello") + self.assertEqual(rb_call_count, 0) + self.assertEqual(rb_call_count, 1) + self.assertIs(rb_raised, True) + + def test_override_only_release(self): + class C(bytearray): + def __release_buffer__(self, buffer): + super().__release_buffer__(buffer) + + c = C(b"hello") + with memoryview(c) as mv: + self.assertEqual(mv.tobytes(), b"hello") + + def test_release_saves_reference(self): + smuggled_buffer = None + + class C(bytearray): + def __release_buffer__(s, buffer: memoryview): + with self.assertRaises(ValueError): + memoryview(buffer) + with self.assertRaises(ValueError): + buffer.cast("b") + with self.assertRaises(ValueError): + buffer.toreadonly() + with self.assertRaises(ValueError): + buffer[:1] + with self.assertRaises(ValueError): + buffer.__buffer__(0) + nonlocal smuggled_buffer + smuggled_buffer = buffer + self.assertEqual(buffer.tobytes(), b"hello") + super().__release_buffer__(buffer) + + c = C(b"hello") + with memoryview(c) as mv: + self.assertEqual(mv.tobytes(), b"hello") + c.clear() + with self.assertRaises(ValueError): + smuggled_buffer.tobytes() + + def test_release_saves_reference_no_subclassing(self): + ba = bytearray(b"hello") + + class C: + def __buffer__(self, flags): + return memoryview(ba) + + def __release_buffer__(self, buffer): + self.buffer = buffer + + c = C() + with memoryview(c) as mv: + self.assertEqual(mv.tobytes(), b"hello") + self.assertEqual(c.buffer.tobytes(), b"hello") + + with self.assertRaises(BufferError): + ba.clear() + c.buffer.release() + ba.clear() + + def test_multiple_inheritance_buffer_last(self): + class A: + def __buffer__(self, flags): + return memoryview(b"hello A") + + class B(A, bytearray): + def __buffer__(self, flags): + return super().__buffer__(flags) + + b = B(b"hello") + with memoryview(b) as mv: + self.assertEqual(mv.tobytes(), b"hello A") + + class Releaser: + def __release_buffer__(self, buffer): + self.buffer = buffer + + class C(Releaser, bytearray): + def __buffer__(self, flags): + return super().__buffer__(flags) + + c = C(b"hello C") + with memoryview(c) as mv: + self.assertEqual(mv.tobytes(), b"hello C") + c.clear() + with self.assertRaises(ValueError): + c.buffer.tobytes() + + def test_multiple_inheritance_buffer_last(self): + class A: + def __buffer__(self, flags): + raise RuntimeError("should not be called") + + def __release_buffer__(self, buffer): + raise RuntimeError("should not be called") + + class B(bytearray, A): + def __buffer__(self, flags): + return super().__buffer__(flags) + + b = B(b"hello") + with memoryview(b) as mv: + self.assertEqual(mv.tobytes(), b"hello") + + class Releaser: + buffer = None + def __release_buffer__(self, buffer): + self.buffer = buffer + + class C(bytearray, Releaser): + def __buffer__(self, flags): + return super().__buffer__(flags) + + c = C(b"hello") + with memoryview(c) as mv: + self.assertEqual(mv.tobytes(), b"hello") + c.clear() + self.assertIs(c.buffer, None) + if __name__ == "__main__": unittest.main() diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 49d4dd524696..c36db59baaa1 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -61,6 +61,7 @@ static void bytearray_releasebuffer(PyByteArrayObject *obj, Py_buffer *view) { obj->ob_exports--; + assert(obj->ob_exports >= 0); } static int diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index f008a8cc3e04..b0168044d9f8 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -193,6 +193,20 @@ PyTypeObject _PyManagedBuffer_Type = { return -1; \ } +#define CHECK_RESTRICTED(mv) \ + if (((PyMemoryViewObject *)(mv))->flags & _Py_MEMORYVIEW_RESTRICTED) { \ + PyErr_SetString(PyExc_ValueError, \ + "cannot create new view on restricted memoryview"); \ + return NULL; \ + } + +#define CHECK_RESTRICTED_INT(mv) \ + if (((PyMemoryViewObject *)(mv))->flags & _Py_MEMORYVIEW_RESTRICTED) { \ + PyErr_SetString(PyExc_ValueError, \ + "cannot create new view on restricted memoryview"); \ + return -1; \ + } + /* See gh-92888. These macros signal that we need to check the memoryview again due to possible read after frees. */ #define CHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv) @@ -781,7 +795,7 @@ PyMemoryView_FromBuffer(const Py_buffer *info) using the given flags. If the object is a memoryview, the new memoryview must be registered with the same managed buffer. Otherwise, a new managed buffer is created. */ -PyObject * +static PyObject * PyMemoryView_FromObjectAndFlags(PyObject *v, int flags) { _PyManagedBufferObject *mbuf; @@ -789,6 +803,7 @@ PyMemoryView_FromObjectAndFlags(PyObject *v, int flags) if (PyMemoryView_Check(v)) { PyMemoryViewObject *mv = (PyMemoryViewObject *)v; CHECK_RELEASED(mv); + CHECK_RESTRICTED(mv); return mbuf_add_view(mv->mbuf, &mv->view); } else if (PyObject_CheckBuffer(v)) { @@ -806,6 +821,30 @@ PyMemoryView_FromObjectAndFlags(PyObject *v, int flags) Py_TYPE(v)->tp_name); return NULL; } + +/* Create a memoryview from an object that implements the buffer protocol, + using the given flags. + If the object is a memoryview, the new memoryview must be registered + with the same managed buffer. Otherwise, a new managed buffer is created. */ +PyObject * +_PyMemoryView_FromBufferProc(PyObject *v, int flags, getbufferproc bufferproc) +{ + _PyManagedBufferObject *mbuf = mbuf_alloc(); + if (mbuf == NULL) + return NULL; + + int res = bufferproc(v, &mbuf->master, flags); + if (res < 0) { + mbuf->master.obj = NULL; + Py_DECREF(mbuf); + return NULL; + } + + PyObject *ret = mbuf_add_view(mbuf, NULL); + Py_DECREF(mbuf); + return ret; +} + /* Create a memoryview from an object that implements the buffer protocol. If the object is a memoryview, the new memoryview must be registered with the same managed buffer. Otherwise, a new managed buffer is created. */ @@ -1397,6 +1436,7 @@ memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format, Py_ssize_t ndim = 1; CHECK_RELEASED(self); + CHECK_RESTRICTED(self); if (!MV_C_CONTIGUOUS(self->flags)) { PyErr_SetString(PyExc_TypeError, @@ -1452,6 +1492,7 @@ memoryview_toreadonly_impl(PyMemoryViewObject *self) /*[clinic end generated code: output=2c7e056f04c99e62 input=dc06d20f19ba236f]*/ { CHECK_RELEASED(self); + CHECK_RESTRICTED(self); /* Even if self is already readonly, we still need to create a new * object for .release() to work correctly. */ @@ -1474,6 +1515,7 @@ memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags) int baseflags = self->flags; CHECK_RELEASED_INT(self); + CHECK_RESTRICTED_INT(self); /* start with complete information */ *view = *base; @@ -2535,6 +2577,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) return memory_item(self, index); } else if (PySlice_Check(key)) { + CHECK_RESTRICTED(self); PyMemoryViewObject *sliced; sliced = (PyMemoryViewObject *)mbuf_add_view(self->mbuf, view); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 456b10ee01d6..98fac276a873 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6,7 +6,7 @@ #include "pycore_symtable.h" // _Py_Mangle() #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_initconfig.h" // _PyStatus_OK() -#include "pycore_memoryobject.h" // PyMemoryView_FromObjectAndFlags() +#include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() #include "pycore_long.h" // _PyLong_IsNegative() @@ -56,6 +56,11 @@ typedef struct PySlot_Offset { short slot_offset; } PySlot_Offset; +static void +slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer); + +static void +releasebuffer_call_python(PyObject *self, Py_buffer *buffer); static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -8078,7 +8083,8 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped) return NULL; } - return PyMemoryView_FromObjectAndFlags(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int)); + return _PyMemoryView_FromBufferProc(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int), + (getbufferproc)wrapped); } static PyObject * @@ -8094,6 +8100,10 @@ wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped) return NULL; } PyMemoryViewObject *mview = (PyMemoryViewObject *)arg; + if (mview->view.obj == NULL) { + // Already released, ignore + Py_RETURN_NONE; + } if (mview->view.obj != self) { PyErr_SetString(PyExc_ValueError, "memoryview's buffer is not this object"); @@ -8978,12 +8988,26 @@ bufferwrapper_releasebuf(PyObject *self, Py_buffer *view) { PyBufferWrapper *bw = (PyBufferWrapper *)self; - assert(PyMemoryView_Check(bw->mv)); - Py_TYPE(bw->mv)->tp_as_buffer->bf_releasebuffer(bw->mv, view); - if (Py_TYPE(bw->obj)->tp_as_buffer != NULL - && Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer != NULL) { - Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer(bw->obj, view); + if (bw->mv == NULL || bw->obj == NULL) { + // Already released + return; + } + + PyObject *mv = bw->mv; + PyObject *obj = bw->obj; + + assert(PyMemoryView_Check(mv)); + Py_TYPE(mv)->tp_as_buffer->bf_releasebuffer(mv, view); + // We only need to call bf_releasebuffer if it's a Python function. If it's a C + // bf_releasebuf, it will be called when the memoryview is released. + if (((PyMemoryViewObject *)mv)->view.obj != obj + && Py_TYPE(obj)->tp_as_buffer != NULL + && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer == slot_bf_releasebuffer) { + releasebuffer_call_python(obj, view); } + + Py_CLEAR(bw->mv); + Py_CLEAR(bw->obj); } static PyBufferProcs bufferwrapper_as_buffer = { @@ -9047,31 +9071,112 @@ slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags) return -1; } +static int +releasebuffer_maybe_call_super(PyObject *self, Py_buffer *buffer) +{ + PyTypeObject *self_type = Py_TYPE(self); + PyObject *mro = lookup_tp_mro(self_type); + if (mro == NULL) { + return -1; + } + + assert(PyTuple_Check(mro)); + Py_ssize_t n = PyTuple_GET_SIZE(mro); + Py_ssize_t i; + + /* No need to check the last one: it's gonna be skipped anyway. */ + for (i = 0; i < n -1; i++) { + if ((PyObject *)(self_type) == PyTuple_GET_ITEM(mro, i)) + break; + } + i++; /* skip self_type */ + if (i >= n) + return -1; + + releasebufferproc base_releasebuffer = NULL; + for (; i < n; i++) { + PyObject *obj = PyTuple_GET_ITEM(mro, i); + if (!PyType_Check(obj)) { + continue; + } + PyTypeObject *base_type = (PyTypeObject *)obj; + if (base_type->tp_as_buffer != NULL + && base_type->tp_as_buffer->bf_releasebuffer != NULL + && base_type->tp_as_buffer->bf_releasebuffer != slot_bf_releasebuffer) { + base_releasebuffer = base_type->tp_as_buffer->bf_releasebuffer; + break; + } + } + + if (base_releasebuffer != NULL) { + base_releasebuffer(self, buffer); + } + return 0; +} + static void -slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer) +releasebuffer_call_python(PyObject *self, Py_buffer *buffer) { PyObject *mv; - if (Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type) { + bool is_buffer_wrapper = Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type; + if (is_buffer_wrapper) { // Make sure we pass the same memoryview to // __release_buffer__() that __buffer__() returned. - mv = Py_NewRef(((PyBufferWrapper *)buffer->obj)->mv); + PyBufferWrapper *bw = (PyBufferWrapper *)buffer->obj; + if (bw->mv == NULL) { + return; + } + mv = Py_NewRef(bw->mv); } else { + // This means we are not dealing with a memoryview returned + // from a Python __buffer__ function. mv = PyMemoryView_FromBuffer(buffer); if (mv == NULL) { PyErr_WriteUnraisable(self); return; } + // Set the memoryview to restricted mode, which forbids + // users from saving any reference to the underlying buffer + // (e.g., by doing .cast()). This is necessary to ensure + // no Python code retains a reference to the to-be-released + // buffer. + ((PyMemoryViewObject *)mv)->flags |= _Py_MEMORYVIEW_RESTRICTED; } PyObject *stack[2] = {self, mv}; PyObject *ret = vectorcall_method(&_Py_ID(__release_buffer__), stack, 2); - Py_DECREF(mv); if (ret == NULL) { PyErr_WriteUnraisable(self); } else { Py_DECREF(ret); } + if (!is_buffer_wrapper) { + PyObject_CallMethodNoArgs(mv, &_Py_ID(release)); + } + Py_DECREF(mv); +} + +/* + * bf_releasebuffer is very delicate, because we need to ensure that + * C bf_releasebuffer slots are called correctly (or we'll leak memory), + * but we cannot trust any __release_buffer__ implemented in Python to + * do so correctly. Therefore, if a base class has a C bf_releasebuffer + * slot, we call it directly here. That is safe because this function + * only gets called from C callers of the bf_releasebuffer slot. Python + * code that calls __release_buffer__ directly instead goes through + * wrap_releasebuffer(), which doesn't call the bf_releasebuffer slot + * directly but instead simply releases the associated memoryview. + */ +static void +slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer) +{ + releasebuffer_call_python(self, buffer); + if (releasebuffer_maybe_call_super(self, buffer) < 0) { + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(self); + } + } } static PyObject * From webhook-mailer at python.org Mon May 8 13:56:23 2023 From: webhook-mailer at python.org (gpshead) Date: Mon, 08 May 2023 17:56:23 -0000 Subject: [Python-checkins] gh-89550: Buffer GzipFile.write to reduce execution time by ~15% (#101251) Message-ID: <mailman.248.1683568583.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9af485436b83003b5705a6e54bdeb900c70e0c69 commit: 9af485436b83003b5705a6e54bdeb900c70e0c69 branch: main author: Arjun <ccldarjun at icloud.com> committer: gpshead <greg at krypto.org> date: 2023-05-08T17:55:59Z summary: gh-89550: Buffer GzipFile.write to reduce execution time by ~15% (#101251) Use `io.BufferedWriter` to buffer gzip writes. --------- Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst M Lib/gzip.py diff --git a/Lib/gzip.py b/Lib/gzip.py index 75c6ddc3f2cf..8796c8d9fd9a 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -22,6 +22,7 @@ _COMPRESS_LEVEL_BEST = 9 READ_BUFFER_SIZE = 128 * 1024 +_WRITE_BUFFER_SIZE = 4 * io.DEFAULT_BUFFER_SIZE def open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_BEST, @@ -120,6 +121,21 @@ class BadGzipFile(OSError): """Exception raised in some cases for invalid gzip files.""" +class _WriteBufferStream(io.RawIOBase): + """Minimal object to pass WriteBuffer flushes into GzipFile""" + def __init__(self, gzip_file): + self.gzip_file = gzip_file + + def write(self, data): + return self.gzip_file._write_raw(data) + + def seekable(self): + return False + + def writable(self): + return True + + class GzipFile(_compression.BaseStream): """The GzipFile class simulates most of the methods of a file object with the exception of the truncate() method. @@ -184,6 +200,7 @@ def __init__(self, filename=None, mode=None, if mode is None: mode = getattr(fileobj, 'mode', 'rb') + if mode.startswith('r'): self.mode = READ raw = _GzipReader(fileobj) @@ -206,6 +223,9 @@ def __init__(self, filename=None, mode=None, zlib.DEF_MEM_LEVEL, 0) self._write_mtime = mtime + self._buffer_size = _WRITE_BUFFER_SIZE + self._buffer = io.BufferedWriter(_WriteBufferStream(self), + buffer_size=self._buffer_size) else: raise ValueError("Invalid mode: {!r}".format(mode)) @@ -231,6 +251,11 @@ def _init_write(self, filename): self.bufsize = 0 self.offset = 0 # Current file offset for seek(), tell(), etc + def tell(self): + self._check_not_closed() + self._buffer.flush() + return super().tell() + def _write_gzip_header(self, compresslevel): self.fileobj.write(b'\037\213') # magic header self.fileobj.write(b'\010') # compression method @@ -272,6 +297,10 @@ def write(self,data): if self.fileobj is None: raise ValueError("write() on closed GzipFile object") + return self._buffer.write(data) + + def _write_raw(self, data): + # Called by our self._buffer underlying WriteBufferStream. if isinstance(data, (bytes, bytearray)): length = len(data) else: @@ -322,9 +351,9 @@ def close(self): fileobj = self.fileobj if fileobj is None: return - self.fileobj = None try: if self.mode == WRITE: + self._buffer.flush() fileobj.write(self.compress.flush()) write32u(fileobj, self.crc) # self.size may exceed 2 GiB, or even 4 GiB @@ -332,6 +361,7 @@ def close(self): elif self.mode == READ: self._buffer.close() finally: + self.fileobj = None myfileobj = self.myfileobj if myfileobj: self.myfileobj = None @@ -341,7 +371,7 @@ def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH): self._check_not_closed() if self.mode == WRITE: # Ensure the compressor's buffer is flushed - self.fileobj.write(self.compress.flush(zlib_mode)) + self._buffer.flush() self.fileobj.flush() def fileno(self): @@ -378,10 +408,10 @@ def seek(self, offset, whence=io.SEEK_SET): if offset < self.offset: raise OSError('Negative seek in write mode') count = offset - self.offset - chunk = b'\0' * 1024 - for i in range(count // 1024): + chunk = b'\0' * self._buffer_size + for i in range(count // self._buffer_size): self.write(chunk) - self.write(b'\0' * (count % 1024)) + self.write(b'\0' * (count % self._buffer_size)) elif self.mode == READ: self._check_not_closed() return self._buffer.seek(offset, whence) diff --git a/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst b/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst new file mode 100644 index 000000000000..556db0eae00c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst @@ -0,0 +1,2 @@ +Decrease execution time of some :mod:`gzip` file writes by 15% by +adding more appropriate buffering. From webhook-mailer at python.org Mon May 8 15:01:55 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 08 May 2023 19:01:55 -0000 Subject: [Python-checkins] GH-104284: Fix documentation gettext build (#104296) Message-ID: <mailman.249.1683572516.13550.python-checkins@python.org> https://github.com/python/cpython/commit/942482c8e660765f68098eae347d84b93e37661a commit: 942482c8e660765f68098eae347d84b93e37661a branch: main author: Adam Turner <9087854+AA-Turner at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-08T19:01:25Z summary: GH-104284: Fix documentation gettext build (#104296) files: M Doc/tools/extensions/pyspecific.py diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 4fe54e30b82b..cd8d9febb0d1 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -674,7 +674,14 @@ def process_audit_events(app, doctree, fromdocname): node.replace_self(table) -def patch_pairindextypes(app) -> None: +def patch_pairindextypes(app, _env) -> None: + """Remove all entries from ``pairindextypes`` before writing POT files. + + We want to run this just before writing output files, as the check to + circumvent is in ``I18nBuilder.write_doc()``. + As such, we link this to ``env-check-consistency``, even though it has + nothing to do with the environment consistency check. + """ if app.builder.name != 'gettext': return @@ -688,14 +695,7 @@ def patch_pairindextypes(app) -> None: # the Sphinx-translated pairindextypes values. As we intend to move # away from this, we need Sphinx to believe that these values don't # exist, by deleting them when using the gettext builder. - - pairindextypes.pop('module', None) - pairindextypes.pop('keyword', None) - pairindextypes.pop('operator', None) - pairindextypes.pop('object', None) - pairindextypes.pop('exception', None) - pairindextypes.pop('statement', None) - pairindextypes.pop('builtin', None) + pairindextypes.clear() def setup(app): @@ -719,7 +719,7 @@ def setup(app): app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod) app.add_directive('miscnews', MiscNews) - app.connect('builder-inited', patch_pairindextypes) + app.connect('env-check-consistency', patch_pairindextypes) app.connect('doctree-resolved', process_audit_events) app.connect('env-merge-info', audit_events_merge) app.connect('env-purge-doc', audit_events_purge) From webhook-mailer at python.org Mon May 8 15:15:17 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 08 May 2023 19:15:17 -0000 Subject: [Python-checkins] gh-99113: A Per-Interpreter GIL! (gh-104210) Message-ID: <mailman.250.1683573318.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5c9ee498c6f4b75e0e020f17b6860309c3b7e11e commit: 5c9ee498c6f4b75e0e020f17b6860309c3b7e11e branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-08T13:15:09-06:00 summary: gh-99113: A Per-Interpreter GIL! (gh-104210) This is the culmination of PEP 684 (and of my 8-year long multi-core Python project)! Each subinterpreter may now be created with its own GIL (via Py_NewInterpreterFromConfig()). If not so configured then the interpreter will share with the main interpreter--the status quo since subinterpreters were added decades ago. The main interpreter always has its own GIL and subinterpreters from Py_NewInterpreter() will always share with the main interpreter. files: A Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst M Include/internal/pycore_ceval.h M Include/internal/pycore_ceval_state.h M Include/internal/pycore_interp.h M Include/internal/pycore_runtime.h M Python/ceval_gil.c M Python/pystate.c diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 9fd8571cbc87..3c8b368bd2af 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -21,8 +21,7 @@ struct _ceval_runtime_state; extern void _Py_FinishPendingCalls(PyThreadState *tstate); -extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *); -extern void _PyEval_InitState(struct _ceval_state *, PyThread_type_lock); +extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock); extern void _PyEval_FiniState(struct _ceval_state *ceval); PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); PyAPI_FUNC(int) _PyEval_AddPendingCall( diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index 4781dd5735dc..b352801673c4 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -49,9 +49,6 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; - - /* This is (only) used indirectly through PyInterpreterState.ceval.gil. */ - struct _gil_runtime_state gil; }; #ifdef PY_HAVE_PERF_TRAMPOLINE diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 7276ce35ba68..527b2121148f 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -178,6 +178,9 @@ struct _is { basis. Also see _PyRuntimeState regarding the various mutex fields. */ + /* The per-interpreter GIL, which might not be used. */ + struct _gil_runtime_state _gil; + /* the initial PyInterpreterState.threads.head */ PyThreadState _initial_thread; }; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index d1b165d0ab9c..6e06e874711b 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -32,8 +32,6 @@ struct _getargs_runtime_state { struct _PyArg_Parser *static_parsers; }; -/* ceval state */ - /* GIL state */ struct _gilstate_runtime_state { diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst new file mode 100644 index 000000000000..42e26cb27b6e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst @@ -0,0 +1,6 @@ +The GIL is now (optionally) per-interpreter. This is the fundamental change +for PEP 684. This is all made possible by virtue of the isolated state of +each interpreter in the process. The behavior of the main interpreter +remains unchanged. Likewise, interpreters created using +``Py_NewInterpreter()`` are not affected. To get an interpreter with its +own GIL, call ``Py_NewInterpreterFromConfig()``. diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 9958856bae80..42e1436bc913 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -464,8 +464,7 @@ take_gil(PyThreadState *tstate) void _PyEval_SetSwitchInterval(unsigned long microseconds) { - /* XXX per-interpreter GIL */ - PyInterpreterState *interp = _PyInterpreterState_Main(); + PyInterpreterState *interp = _PyInterpreterState_Get(); struct _gil_runtime_state *gil = interp->ceval.gil; assert(gil != NULL); gil->interval = microseconds; @@ -473,8 +472,7 @@ void _PyEval_SetSwitchInterval(unsigned long microseconds) unsigned long _PyEval_GetSwitchInterval(void) { - /* XXX per-interpreter GIL */ - PyInterpreterState *interp = _PyInterpreterState_Main(); + PyInterpreterState *interp = _PyInterpreterState_Get(); struct _gil_runtime_state *gil = interp->ceval.gil; assert(gil != NULL); return gil->interval; @@ -484,7 +482,9 @@ unsigned long _PyEval_GetSwitchInterval(void) int _PyEval_ThreadsInitialized(void) { - /* XXX per-interpreter GIL */ + /* XXX This is only needed for an assert in PyGILState_Ensure(), + * which currently does not work with subinterpreters. + * Thus we only use the main interpreter. */ PyInterpreterState *interp = _PyInterpreterState_Main(); if (interp == NULL) { return 0; @@ -532,27 +532,16 @@ _PyEval_InitGIL(PyThreadState *tstate, int own_gil) assert(tstate->interp->ceval.gil == NULL); int locked; if (!own_gil) { + /* The interpreter will share the main interpreter's instead. */ PyInterpreterState *main_interp = _PyInterpreterState_Main(); assert(tstate->interp != main_interp); struct _gil_runtime_state *gil = main_interp->ceval.gil; init_shared_gil(tstate->interp, gil); locked = current_thread_holds_gil(gil, tstate); } - /* XXX per-interpreter GIL */ - else if (!_Py_IsMainInterpreter(tstate->interp)) { - /* Currently, the GIL is shared by all interpreters, - and only the main interpreter is responsible to create - and destroy it. */ - struct _gil_runtime_state *main_gil = _PyInterpreterState_Main()->ceval.gil; - init_shared_gil(tstate->interp, main_gil); - // XXX For now we lie. - tstate->interp->ceval.own_gil = 1; - locked = current_thread_holds_gil(main_gil, tstate); - } else { PyThread_init_thread(); - // XXX per-interpreter GIL: switch to interp->_gil. - init_own_gil(tstate->interp, &tstate->interp->runtime->ceval.gil); + init_own_gil(tstate->interp, &tstate->interp->_gil); locked = 0; } if (!locked) { @@ -565,7 +554,8 @@ _PyEval_InitGIL(PyThreadState *tstate, int own_gil) void _PyEval_FiniGIL(PyInterpreterState *interp) { - if (interp->ceval.gil == NULL) { + struct _gil_runtime_state *gil = interp->ceval.gil; + if (gil == NULL) { /* It was already finalized (or hasn't been initialized yet). */ assert(!interp->ceval.own_gil); return; @@ -573,24 +563,13 @@ _PyEval_FiniGIL(PyInterpreterState *interp) else if (!interp->ceval.own_gil) { #ifdef Py_DEBUG PyInterpreterState *main_interp = _PyInterpreterState_Main(); - assert(interp != main_interp); + assert(main_interp != NULL && interp != main_interp); assert(interp->ceval.gil == main_interp->ceval.gil); #endif interp->ceval.gil = NULL; return; } - /* XXX per-interpreter GIL */ - struct _gil_runtime_state *gil = &interp->runtime->ceval.gil; - if (!_Py_IsMainInterpreter(interp)) { - /* Currently, the GIL is shared by all interpreters, - and only the main interpreter is responsible to create - and destroy it. */ - assert(interp->ceval.gil == gil); - interp->ceval.gil = NULL; - return; - } - if (!gil_created(gil)) { /* First Py_InitializeFromConfig() call: the GIL doesn't exist yet: do nothing. */ @@ -974,21 +953,13 @@ Py_MakePendingCalls(void) return 0; } -/* The interpreter's recursion limit */ - void -_PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval) +_PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock) { - /* XXX per-interpreter GIL */ - _gil_initialize(&ceval->gil); -} + _gil_initialize(&interp->_gil); -void -_PyEval_InitState(struct _ceval_state *ceval, PyThread_type_lock pending_lock) -{ - struct _pending_calls *pending = &ceval->pending; + struct _pending_calls *pending = &interp->ceval.pending; assert(pending->lock == NULL); - pending->lock = pending_lock; } diff --git a/Python/pystate.c b/Python/pystate.c index f14934361dab..26debf1f88b9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -425,8 +425,6 @@ init_runtime(_PyRuntimeState *runtime, runtime->open_code_userdata = open_code_userdata; runtime->audit_hook_head = audit_hook_head; - _PyEval_InitRuntimeState(&runtime->ceval); - PyPreConfig_InitPythonConfig(&runtime->preconfig); PyThread_type_lock *lockptrs[NUMLOCKS] = { @@ -682,7 +680,7 @@ init_interpreter(PyInterpreterState *interp, memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp)); } - _PyEval_InitState(&interp->ceval, pending_lock); + _PyEval_InitState(interp, pending_lock); _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); From webhook-mailer at python.org Mon May 8 15:17:49 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 08 May 2023 19:17:49 -0000 Subject: [Python-checkins] [3.11] GH-104284: Fix documentation gettext build (GH-104296) (#104299) Message-ID: <mailman.251.1683573470.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2ee250383f6fd2560f04152da0f79433263ef223 commit: 2ee250383f6fd2560f04152da0f79433263ef223 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-08T13:17:42-06:00 summary: [3.11] GH-104284: Fix documentation gettext build (GH-104296) (#104299) Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> files: M Doc/tools/extensions/pyspecific.py diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index c63a5cd817be..446cffc80020 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -679,7 +679,14 @@ def process_audit_events(app, doctree, fromdocname): node.replace_self(table) -def patch_pairindextypes(app) -> None: +def patch_pairindextypes(app, _env) -> None: + """Remove all entries from ``pairindextypes`` before writing POT files. + + We want to run this just before writing output files, as the check to + circumvent is in ``I18nBuilder.write_doc()``. + As such, we link this to ``env-check-consistency``, even though it has + nothing to do with the environment consistency check. + """ if app.builder.name != 'gettext': return @@ -693,14 +700,7 @@ def patch_pairindextypes(app) -> None: # the Sphinx-translated pairindextypes values. As we intend to move # away from this, we need Sphinx to believe that these values don't # exist, by deleting them when using the gettext builder. - - pairindextypes.pop('module', None) - pairindextypes.pop('keyword', None) - pairindextypes.pop('operator', None) - pairindextypes.pop('object', None) - pairindextypes.pop('exception', None) - pairindextypes.pop('statement', None) - pairindextypes.pop('builtin', None) + pairindextypes.clear() def setup(app): @@ -725,7 +725,7 @@ def setup(app): app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod) app.add_directive('miscnews', MiscNews) - app.connect('builder-inited', patch_pairindextypes) + app.connect('env-check-consistency', patch_pairindextypes) app.connect('doctree-resolved', process_audit_events) app.connect('env-merge-info', audit_events_merge) app.connect('env-purge-doc', audit_events_purge) From webhook-mailer at python.org Mon May 8 18:56:08 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 08 May 2023 22:56:08 -0000 Subject: [Python-checkins] gh-104310: Add importlib.util.allowing_all_extensions() (gh-104311) Message-ID: <mailman.252.1683586569.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4541d1a0dba3ef0c386991cf54c4c3c411a364c0 commit: 4541d1a0dba3ef0c386991cf54c4c3c411a364c0 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-08T16:56:01-06:00 summary: gh-104310: Add importlib.util.allowing_all_extensions() (gh-104311) (I'll be adding docs for this separately.) files: A Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst M Lib/importlib/util.py M Lib/test/support/import_helper.py M Lib/test/test_importlib/test_util.py diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py index 5294578cc26c..b1d9271f8e47 100644 --- a/Lib/importlib/util.py +++ b/Lib/importlib/util.py @@ -112,6 +112,43 @@ def find_spec(name, package=None): return spec +# Normally we would use contextlib.contextmanager. However, this module +# is imported by runpy, which means we want to avoid any unnecessary +# dependencies. Thus we use a class. + +class allowing_all_extensions: + """A context manager that lets users skip the compatibility check. + + Normally, extensions that do not support multiple interpreters + may not be imported in a subinterpreter. That implies modules + that do not implement multi-phase init. + + Likewise for modules import in a subinterpeter with its own GIL + when the extension does not support a per-interpreter GIL. This + implies the module does not have a Py_mod_multiple_interpreters slot + set to Py_MOD_PER_INTERPRETER_GIL_SUPPORTED. + + In both cases, this context manager may be used to temporarily + disable the check for compatible extension modules. + """ + + def __init__(self, disable_check=True): + self.disable_check = disable_check + + def __enter__(self): + self.old = _imp._override_multi_interp_extensions_check(self.override) + return self + + def __exit__(self, *args): + old = self.old + del self.old + _imp._override_multi_interp_extensions_check(old) + + @property + def override(self): + return -1 if self.disable_check else 1 + + class _LazyModule(types.ModuleType): """A subclass of the module type which triggers loading upon attribute access.""" diff --git a/Lib/test/support/import_helper.py b/Lib/test/support/import_helper.py index 772c0987c2eb..67f18e530edc 100644 --- a/Lib/test/support/import_helper.py +++ b/Lib/test/support/import_helper.py @@ -115,6 +115,8 @@ def multi_interp_extensions_check(enabled=True): It overrides the PyInterpreterConfig.check_multi_interp_extensions setting (see support.run_in_subinterp_with_config() and _xxsubinterpreters.create()). + + Also see importlib.utils.allowing_all_extensions(). """ old = _imp._override_multi_interp_extensions_check(1 if enabled else -1) try: diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index 08a615ecf528..0be504925ecc 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -8,14 +8,29 @@ import importlib.util import os import pathlib +import re import string import sys from test import support +import textwrap import types import unittest import unittest.mock import warnings +try: + import _testsinglephase +except ImportError: + _testsinglephase = None +try: + import _testmultiphase +except ImportError: + _testmultiphase = None +try: + import _xxsubinterpreters as _interpreters +except ModuleNotFoundError: + _interpreters = None + class DecodeSourceBytesTests: @@ -637,5 +652,111 @@ def test_magic_number(self): self.assertEqual(EXPECTED_MAGIC_NUMBER, actual, msg) + at unittest.skipIf(_interpreters is None, 'subinterpreters required') +class AllowingAllExtensionsTests(unittest.TestCase): + + ERROR = re.compile("^<class 'ImportError'>: module (.*) does not support loading in subinterpreters") + + def run_with_own_gil(self, script): + interpid = _interpreters.create(isolated=True) + try: + _interpreters.run_string(interpid, script) + except _interpreters.RunFailedError as exc: + if m := self.ERROR.match(str(exc)): + modname, = m.groups() + raise ImportError(modname) + + def run_with_shared_gil(self, script): + interpid = _interpreters.create(isolated=False) + try: + _interpreters.run_string(interpid, script) + except _interpreters.RunFailedError as exc: + if m := self.ERROR.match(str(exc)): + modname, = m.groups() + raise ImportError(modname) + + @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module") + def test_single_phase_init_module(self): + script = textwrap.dedent(''' + import importlib.util + with importlib.util.allowing_all_extensions(): + import _testsinglephase + ''') + with self.subTest('check disabled, shared GIL'): + self.run_with_shared_gil(script) + with self.subTest('check disabled, per-interpreter GIL'): + self.run_with_own_gil(script) + + script = textwrap.dedent(f''' + import importlib.util + with importlib.util.allowing_all_extensions(False): + import _testsinglephase + ''') + with self.subTest('check enabled, shared GIL'): + with self.assertRaises(ImportError): + self.run_with_shared_gil(script) + with self.subTest('check enabled, per-interpreter GIL'): + with self.assertRaises(ImportError): + self.run_with_own_gil(script) + + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + def test_incomplete_multi_phase_init_module(self): + prescript = textwrap.dedent(f''' + from importlib.util import spec_from_loader, module_from_spec + from importlib.machinery import ExtensionFileLoader + + name = '_test_shared_gil_only' + filename = {_testmultiphase.__file__!r} + loader = ExtensionFileLoader(name, filename) + spec = spec_from_loader(name, loader) + + ''') + + script = prescript + textwrap.dedent(''' + import importlib.util + with importlib.util.allowing_all_extensions(): + module = module_from_spec(spec) + loader.exec_module(module) + ''') + with self.subTest('check disabled, shared GIL'): + self.run_with_shared_gil(script) + with self.subTest('check disabled, per-interpreter GIL'): + self.run_with_own_gil(script) + + script = prescript + textwrap.dedent(''' + import importlib.util + with importlib.util.allowing_all_extensions(False): + module = module_from_spec(spec) + loader.exec_module(module) + ''') + with self.subTest('check enabled, shared GIL'): + self.run_with_shared_gil(script) + with self.subTest('check enabled, per-interpreter GIL'): + with self.assertRaises(ImportError): + self.run_with_own_gil(script) + + @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") + def test_complete_multi_phase_init_module(self): + script = textwrap.dedent(''' + import importlib.util + with importlib.util.allowing_all_extensions(): + import _testmultiphase + ''') + with self.subTest('check disabled, shared GIL'): + self.run_with_shared_gil(script) + with self.subTest('check disabled, per-interpreter GIL'): + self.run_with_own_gil(script) + + script = textwrap.dedent(f''' + import importlib.util + with importlib.util.allowing_all_extensions(False): + import _testmultiphase + ''') + with self.subTest('check enabled, shared GIL'): + self.run_with_shared_gil(script) + with self.subTest('check enabled, per-interpreter GIL'): + self.run_with_own_gil(script) + + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst b/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst new file mode 100644 index 000000000000..3743d569995f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst @@ -0,0 +1,3 @@ +Users may now use ``importlib.util.allowing_all_extensions()`` (a context +manager) to temporarily disable the strict compatibility checks for +importing extension modules in subinterpreters. From webhook-mailer at python.org Mon May 8 19:27:30 2023 From: webhook-mailer at python.org (njsmith) Date: Mon, 08 May 2023 23:27:30 -0000 Subject: [Python-checkins] GH-104308: socket.getnameinfo should release the GIL (#104307) Message-ID: <mailman.253.1683588451.13550.python-checkins@python.org> https://github.com/python/cpython/commit/faf196213e60d8a90773e9e5680d3252bd294643 commit: faf196213e60d8a90773e9e5680d3252bd294643 branch: main author: Nathaniel J. Smith <njs at pobox.com> committer: njsmith <njs at pobox.com> date: 2023-05-08T16:27:20-07:00 summary: GH-104308: socket.getnameinfo should release the GIL (#104307) * socket.getnameinfo should release the GIL * ?? Added by blurb_it. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst M Modules/socketmodule.c diff --git a/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst new file mode 100644 index 000000000000..03775845450c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst @@ -0,0 +1 @@ +:func:`socket.getnameinfo` now releases the GIL while contacting the DNS server diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 60219593be61..c11fb4400eab 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -6883,8 +6883,10 @@ socket_getnameinfo(PyObject *self, PyObject *args) } #endif } + Py_BEGIN_ALLOW_THREADS error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags); + Py_END_ALLOW_THREADS if (error) { socket_state *state = get_module_state(self); set_gaierror(state, error); From webhook-mailer at python.org Mon May 8 19:49:52 2023 From: webhook-mailer at python.org (njsmith) Date: Mon, 08 May 2023 23:49:52 -0000 Subject: [Python-checkins] [3.11] GH-104308: socket.getnameinfo should release the GIL (GH-104307) (#104313) Message-ID: <mailman.254.1683589794.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b7622e7a054497c9e9a17ee8c2b0bee33c098d5d commit: b7622e7a054497c9e9a17ee8c2b0bee33c098d5d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: njsmith <njs at pobox.com> date: 2023-05-08T23:49:45Z summary: [3.11] GH-104308: socket.getnameinfo should release the GIL (GH-104307) (#104313) GH-104308: socket.getnameinfo should release the GIL (GH-104307) * socket.getnameinfo should release the GIL * ?? Added by blurb_it. --------- (cherry picked from commit faf196213e60d8a90773e9e5680d3252bd294643) Co-authored-by: Nathaniel J. Smith <njs at pobox.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst M Modules/socketmodule.c diff --git a/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst new file mode 100644 index 000000000000..03775845450c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst @@ -0,0 +1 @@ +:func:`socket.getnameinfo` now releases the GIL while contacting the DNS server diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 0e319a4cfd38..47539d354b49 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -6737,8 +6737,10 @@ socket_getnameinfo(PyObject *self, PyObject *args) } #endif } + Py_BEGIN_ALLOW_THREADS error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags); + Py_END_ALLOW_THREADS if (error) { set_gaierror(error); goto fail; From webhook-mailer at python.org Mon May 8 20:52:04 2023 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 09 May 2023 00:52:04 -0000 Subject: [Python-checkins] gh-97696 Remove unnecessary check for eager_start kwarg (#104188) Message-ID: <mailman.255.1683593525.13550.python-checkins@python.org> https://github.com/python/cpython/commit/bf89d4283a28dd00836f2c312a9255f543f93fc7 commit: bf89d4283a28dd00836f2c312a9255f543f93fc7 branch: main author: Jacob Bower <1978924+jbower-fb at users.noreply.github.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-09T00:51:58Z summary: gh-97696 Remove unnecessary check for eager_start kwarg (#104188) Instead, add docstring to create_eager_task_factory. files: M Lib/asyncio/tasks.py diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 7eb647bd1298..8d5bde09ea9b 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -942,18 +942,31 @@ def callback(): def create_eager_task_factory(custom_task_constructor): + """Create a function suitable for use as a task factory on an event-loop. - if "eager_start" not in inspect.signature(custom_task_constructor).parameters: - raise TypeError( - "Provided constructor does not support eager task execution") + Example usage: + + loop.set_task_factory( + asyncio.create_eager_task_factory(my_task_constructor)) + + Now, tasks created will be started immediately (rather than being first + scheduled to an event loop). The constructor argument can be any callable + that returns a Task-compatible object and has a signature compatible + with `Task.__init__`; it must have the `eager_start` keyword argument. + + Most applications will use `Task` for `custom_task_constructor` and in + this case there's no need to call `create_eager_task_factory()` + directly. Instead the global `eager_task_factory` instance can be + used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`. + """ def factory(loop, coro, *, name=None, context=None): return custom_task_constructor( coro, loop=loop, name=name, context=context, eager_start=True) - return factory + eager_task_factory = create_eager_task_factory(Task) From webhook-mailer at python.org Tue May 9 04:25:05 2023 From: webhook-mailer at python.org (ronaldoussoren) Date: Tue, 09 May 2023 08:25:05 -0000 Subject: [Python-checkins] gh-104180: Read SOCKS proxies from macOS System Configuration (#104181) Message-ID: <mailman.256.1683620706.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9a9b176eb7e052af84c01c0cfb3231e51f980f2d commit: 9a9b176eb7e052af84c01c0cfb3231e51f980f2d branch: main author: samschott <sam.schott at outlook.com> committer: ronaldoussoren <ronaldoussoren at mac.com> date: 2023-05-09T10:24:29+02:00 summary: gh-104180: Read SOCKS proxies from macOS System Configuration (#104181) read SOCKS proxies from macOS System Configuration in ``urllib.request``. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: A Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst M Modules/_scproxy.c diff --git a/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst b/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst new file mode 100644 index 000000000000..b6b18dcfd813 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst @@ -0,0 +1,2 @@ +Support reading SOCKS proxy configuration from macOS System Configuration. +Patch by Sam Schott. diff --git a/Modules/_scproxy.c b/Modules/_scproxy.c index e66918016b8d..0df0324df55f 100644 --- a/Modules/_scproxy.c +++ b/Modules/_scproxy.c @@ -206,6 +206,11 @@ get_proxies(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored)) kSCPropNetProxiesGopherProxy, kSCPropNetProxiesGopherPort); if (r == -1) goto error; + r = set_proxy(result, "socks", proxyDict, + kSCPropNetProxiesSOCKSEnable, + kSCPropNetProxiesSOCKSProxy, + kSCPropNetProxiesSOCKSPort); + if (r == -1) goto error; CFRelease(proxyDict); return result; From webhook-mailer at python.org Tue May 9 05:19:48 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 09 May 2023 09:19:48 -0000 Subject: [Python-checkins] gh-90656: Add platform triplets for 64-bit LoongArch (LA64) (#30939) Message-ID: <mailman.257.1683623989.13550.python-checkins@python.org> https://github.com/python/cpython/commit/03029ace924f7dac7ef49eee3417e0af6623060d commit: 03029ace924f7dac7ef49eee3417e0af6623060d branch: main author: Zhang Na <44800775+loongson-zn at users.noreply.github.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-09T09:19:40Z summary: gh-90656: Add platform triplets for 64-bit LoongArch (LA64) (#30939) Signed-off-by: Zhang Na <zhangna at loongson.cn> Co-authored-by: WANG Xuerui <git at xen0n.name> files: A Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst M Doc/whatsnew/3.12.rst M configure M configure.ac diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 65b3e9ffb807..fe6ad575f717 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1169,6 +1169,14 @@ Build Changes optimization levels (0, 1, 2) at once. (Contributed by Victor Stinner in :gh:`99289`.) +* Add platform triplets for 64-bit LoongArch: + + * loongarch64-linux-gnusf + * loongarch64-linux-gnuf32 + * loongarch64-linux-gnu + + (Contributed by Zhang Na in :gh:`90656`.) + C API Changes ============= diff --git a/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst b/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst new file mode 100644 index 000000000000..dfe71a555207 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst @@ -0,0 +1,7 @@ +Add platform triplets for 64-bit LoongArch: + +* loongarch64-linux-gnusf +* loongarch64-linux-gnuf32 +* loongarch64-linux-gnu + +Patch by Zhang Na. diff --git a/configure b/configure index b8fa9d66e735..c9ea72cf6efa 100755 --- a/configure +++ b/configure @@ -6143,6 +6143,20 @@ cat > conftest.c <<EOF hppa-linux-gnu # elif defined(__ia64__) ia64-linux-gnu +# elif defined(__loongarch__) +# if defined(__loongarch_lp64) +# if defined(__loongarch_soft_float) + loongarch64-linux-gnusf +# elif defined(__loongarch_single_float) + loongarch64-linux-gnuf32 +# elif defined(__loongarch_double_float) + loongarch64-linux-gnu +# else +# error unknown platform triplet +# endif +# else +# error unknown platform triplet +# endif # elif defined(__m68k__) && !defined(__mcoldfire__) m68k-linux-gnu # elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6) && defined(_MIPSEL) diff --git a/configure.ac b/configure.ac index 0940b93c25f7..10672bd3761d 100644 --- a/configure.ac +++ b/configure.ac @@ -959,6 +959,20 @@ cat > conftest.c <<EOF hppa-linux-gnu # elif defined(__ia64__) ia64-linux-gnu +# elif defined(__loongarch__) +# if defined(__loongarch_lp64) +# if defined(__loongarch_soft_float) + loongarch64-linux-gnusf +# elif defined(__loongarch_single_float) + loongarch64-linux-gnuf32 +# elif defined(__loongarch_double_float) + loongarch64-linux-gnu +# else +# error unknown platform triplet +# endif +# else +# error unknown platform triplet +# endif # elif defined(__m68k__) && !defined(__mcoldfire__) m68k-linux-gnu # elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6) && defined(_MIPSEL) From webhook-mailer at python.org Tue May 9 05:27:23 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 09 May 2023 09:27:23 -0000 Subject: [Python-checkins] [3.11] gh-102500: collections.abc.Buffer doesn't exist in 3.11 (#104317) Message-ID: <mailman.258.1683624443.13550.python-checkins@python.org> https://github.com/python/cpython/commit/15624b445e57859edb13eec64f0cd71198f0fc00 commit: 15624b445e57859edb13eec64f0cd71198f0fc00 branch: 3.11 author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-09T10:27:15+01:00 summary: [3.11] gh-102500: collections.abc.Buffer doesn't exist in 3.11 (#104317) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index de716b3f2227..2a53df4b746d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2094,7 +2094,7 @@ Corresponding to collections in :mod:`collections.abc` and :class:`memoryview` of byte sequences. .. deprecated-removed:: 3.9 3.14 - Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. + Prefer ``typing_extensions.Buffer``, or a union like ``bytes | bytearray | memoryview``. .. class:: Collection(Sized, Iterable[T_co], Container[T_co]) From webhook-mailer at python.org Tue May 9 06:29:10 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 09 May 2023 10:29:10 -0000 Subject: [Python-checkins] require-pr-label.yml: Add missing "permissions:" (#104309) Message-ID: <mailman.259.1683628151.13550.python-checkins@python.org> https://github.com/python/cpython/commit/41aff464cef83d2655029ddd180a51110e8d7f8e commit: 41aff464cef83d2655029ddd180a51110e8d7f8e branch: main author: Sebastian Pipping <sebastian at pipping.org> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-09T13:29:00+03:00 summary: require-pr-label.yml: Add missing "permissions:" (#104309) files: M .github/workflows/require-pr-label.yml diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index 916bbeb43527..88aaea039f04 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -4,6 +4,10 @@ on: pull_request: types: [opened, reopened, labeled, unlabeled, synchronize] +permissions: + issues: read + pull-requests: read + jobs: label: name: DO-NOT-MERGE / unresolved review From webhook-mailer at python.org Tue May 9 08:33:43 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 09 May 2023 12:33:43 -0000 Subject: [Python-checkins] gh-103193: Fix refleaks in `test_inspect` and `test_typing` (#104320) Message-ID: <mailman.260.1683635625.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9196da417d20e1484e23b3c80483b0222abaadf2 commit: 9196da417d20e1484e23b3c80483b0222abaadf2 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-09T18:03:36+05:30 summary: gh-103193: Fix refleaks in `test_inspect` and `test_typing` (#104320) files: M Lib/test/libregrtest/utils.py diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index fb13fa0e243b..fd46819fd903 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -210,6 +210,13 @@ def clear_caches(): else: fractions._hash_algorithm.cache_clear() + try: + inspect = sys.modules['inspect'] + except KeyError: + pass + else: + inspect._shadowed_dict_from_mro_tuple.cache_clear() + def get_build_info(): # Get most important configure and build options as a list of strings. From webhook-mailer at python.org Tue May 9 08:40:06 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 09 May 2023 12:40:06 -0000 Subject: [Python-checkins] gh-97696: Move around and update the whatsnew entry for asyncio eager task factory (#104298) Message-ID: <mailman.261.1683636006.13550.python-checkins@python.org> https://github.com/python/cpython/commit/85f981880ae9591ba577e44d2945a771078a7c35 commit: 85f981880ae9591ba577e44d2945a771078a7c35 branch: main author: Itamar Ostricher <itamarost at gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-09T12:39:59Z summary: gh-97696: Move around and update the whatsnew entry for asyncio eager task factory (#104298) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index fe6ad575f717..12d357f117b1 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -282,6 +282,11 @@ asyncio writing to sockets and uses :meth:`~socket.socket.sendmsg` if the platform supports it. (Contributed by Kumar Aditya in :gh:`91166`.) +* Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory` + functions to allow opting an event loop in to eager task execution, + making some use-cases 2x to 5x faster. + (Contributed by Jacob Bower & Itamar O in :gh:`102853`, :gh:`104140`, and :gh:`104138`) + * On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default if :func:`os.pidfd_open` is available and functional instead of :class:`~asyncio.ThreadedChildWatcher`. @@ -644,11 +649,6 @@ Optimizations * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting. (Contributed by Itamar O in :gh:`103793`.) -* Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory` - functions to allow opting an event loop in to eager task execution, - speeding up some use-cases by up to 50%. - (Contributed by Jacob Bower & Itamar O in :gh:`102853`) - CPython bytecode changes ======================== From webhook-mailer at python.org Tue May 9 08:41:16 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 09 May 2023 12:41:16 -0000 Subject: [Python-checkins] gh-104276: Make `_struct.unpack_iterator` type use type flag instead of custom constructor (#104277) Message-ID: <mailman.262.1683636077.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c21f82876089f3e9a7b1e706c029664b799fa659 commit: c21f82876089f3e9a7b1e706c029664b799fa659 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-09T12:41:09Z summary: gh-104276: Make `_struct.unpack_iterator` type use type flag instead of custom constructor (#104277) files: M Modules/_struct.c diff --git a/Modules/_struct.c b/Modules/_struct.c index 26434f714de5..4f9478bd9809 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1832,11 +1832,6 @@ unpackiter_iternext(unpackiterobject *self) return result; } -PyObject *unpackiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyErr_Format(PyExc_TypeError, "Cannot create '%.200s objects", _PyType_Name(type)); - return NULL; -} - static PyType_Slot unpackiter_type_slots[] = { {Py_tp_dealloc, unpackiter_dealloc}, {Py_tp_getattro, PyObject_GenericGetAttr}, @@ -1844,7 +1839,6 @@ static PyType_Slot unpackiter_type_slots[] = { {Py_tp_iter, PyObject_SelfIter}, {Py_tp_iternext, unpackiter_iternext}, {Py_tp_methods, unpackiter_methods}, - {Py_tp_new, unpackiter_new}, {0, 0}, }; @@ -1853,7 +1847,7 @@ static PyType_Spec unpackiter_type_spec = { sizeof(unpackiterobject), 0, (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_IMMUTABLETYPE), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), unpackiter_type_slots }; From webhook-mailer at python.org Tue May 9 09:33:57 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 09 May 2023 13:33:57 -0000 Subject: [Python-checkins] gh-104240: return code unit metadata from codegen (#104300) Message-ID: <mailman.263.1683639239.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ca95edf177e3c10e10d7011ed52619b1312cf15e commit: ca95edf177e3c10e10d7011ed52619b1312cf15e branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-09T14:33:40+01:00 summary: gh-104240: return code unit metadata from codegen (#104300) files: M Lib/test/support/bytecode_helper.py M Lib/test/test_compiler_assemble.py M Modules/_testinternalcapi.c M Python/compile.c diff --git a/Lib/test/support/bytecode_helper.py b/Lib/test/support/bytecode_helper.py index 357ec44dbc21..7b577f54b8ad 100644 --- a/Lib/test/support/bytecode_helper.py +++ b/Lib/test/support/bytecode_helper.py @@ -124,7 +124,7 @@ def complete_insts_info(self, insts): class CodegenTestCase(CompilationStepTestCase): def generate_code(self, ast): - insts = compiler_codegen(ast, "my_file.py", 0) + insts, _ = compiler_codegen(ast, "my_file.py", 0) return insts diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py index 96c1691e24a9..0bd7a09b001c 100644 --- a/Lib/test/test_compiler_assemble.py +++ b/Lib/test/test_compiler_assemble.py @@ -52,7 +52,7 @@ def test_simple_expr(self): 'filename' : 'avg.py', 'name' : 'avg', 'qualname' : 'stats.avg', - 'consts' : [2], + 'consts' : {2 : 0}, 'argcount' : 2, 'varnames' : {'x' : 0, 'y' : 1}, } diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 40ad6f88868d..8009dca3d0b7 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -670,7 +670,7 @@ _testinternalcapi_assemble_code_object_impl(PyObject *module, umd.u_cellvars = PyDict_GetItemString(metadata, "cellvars"); umd.u_freevars = PyDict_GetItemString(metadata, "freevars"); - assert(PyList_Check(umd.u_consts)); + assert(PyDict_Check(umd.u_consts)); assert(PyDict_Check(umd.u_names)); assert(PyDict_Check(umd.u_varnames)); assert(PyDict_Check(umd.u_cellvars)); diff --git a/Python/compile.c b/Python/compile.c index f875e4e17e0a..12ae83136196 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7261,6 +7261,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, int optimize, int compile_mode) { PyObject *res = NULL; + PyObject *metadata = NULL; if (!PyAST_Check(ast)) { PyErr_SetString(PyExc_TypeError, "expected an AST"); @@ -7287,14 +7288,53 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, if (compiler_codegen(c, mod) < 0) { goto finally; } + + _PyCompile_CodeUnitMetadata *umd = &c->u->u_metadata; + metadata = PyDict_New(); + if (metadata == NULL) { + goto finally; + } +#define SET_MATADATA_ITEM(key, value) \ + if (value != NULL) { \ + if (PyDict_SetItemString(metadata, key, value) < 0) goto finally; \ + } + + SET_MATADATA_ITEM("name", umd->u_name); + SET_MATADATA_ITEM("qualname", umd->u_qualname); + SET_MATADATA_ITEM("consts", umd->u_consts); + SET_MATADATA_ITEM("names", umd->u_names); + SET_MATADATA_ITEM("varnames", umd->u_varnames); + SET_MATADATA_ITEM("cellvars", umd->u_cellvars); + SET_MATADATA_ITEM("freevars", umd->u_freevars); +#undef SET_MATADATA_ITEM + +#define SET_MATADATA_INT(key, value) do { \ + PyObject *v = PyLong_FromLong((long)value); \ + if (v == NULL) goto finally; \ + int res = PyDict_SetItemString(metadata, key, v); \ + Py_XDECREF(v); \ + if (res < 0) goto finally; \ + } while (0); + + SET_MATADATA_INT("argcount", umd->u_argcount); + SET_MATADATA_INT("posonlyargcount", umd->u_posonlyargcount); + SET_MATADATA_INT("kwonlyargcount", umd->u_kwonlyargcount); +#undef SET_MATADATA_INT + int addNone = mod->kind != Expression_kind; if (add_return_at_end(c, addNone) < 0) { - return NULL; + goto finally; } - res = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); + PyObject *insts = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); + if (insts == NULL) { + goto finally; + } + res = PyTuple_Pack(2, insts, metadata); + Py_DECREF(insts); finally: + Py_XDECREF(metadata); compiler_exit_scope(c); compiler_free(c); _PyArena_Free(arena); @@ -7375,10 +7415,14 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, goto error; } - PyObject *consts = umd->u_consts; + PyObject *consts = consts_dict_keys_inorder(umd->u_consts); + if (consts == NULL) { + goto error; + } co = _PyAssemble_MakeCodeObject(umd, const_cache, consts, maxdepth, &optimized_instrs, nlocalsplus, code_flags, filename); + Py_DECREF(consts); error: Py_DECREF(const_cache); From webhook-mailer at python.org Tue May 9 10:04:58 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 09 May 2023 14:04:58 -0000 Subject: [Python-checkins] gh-104139: Add itms-services to uses_netloc urllib.parse. (#104312) Message-ID: <mailman.264.1683641099.13550.python-checkins@python.org> https://github.com/python/cpython/commit/82f789be3b15df5f6660f5fd0c563ad690ee00fb commit: 82f789be3b15df5f6660f5fd0c563ad690ee00fb branch: main author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-09T07:04:50-07:00 summary: gh-104139: Add itms-services to uses_netloc urllib.parse. (#104312) Teach unsplit to retain the `"//"` when assembling `itms-services://?action=generate-bugs` style [Apple Platform Deployment](https://support.apple.com/en-gb/guide/deployment/depce7cefc4d/web) URLs. files: A Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 80fb9e5cd2a4..dcdbb1cc64fd 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -72,20 +72,20 @@ class UrlParseTestCase(unittest.TestCase): def checkRoundtrips(self, url, parsed, split): result = urllib.parse.urlparse(url) - self.assertEqual(result, parsed) + self.assertSequenceEqual(result, parsed) t = (result.scheme, result.netloc, result.path, result.params, result.query, result.fragment) - self.assertEqual(t, parsed) + self.assertSequenceEqual(t, parsed) # put it back together and it should be the same result2 = urllib.parse.urlunparse(result) - self.assertEqual(result2, url) - self.assertEqual(result2, result.geturl()) + self.assertSequenceEqual(result2, url) + self.assertSequenceEqual(result2, result.geturl()) # the result of geturl() is a fixpoint; we can always parse it # again to get the same result: result3 = urllib.parse.urlparse(result.geturl()) self.assertEqual(result3.geturl(), result.geturl()) - self.assertEqual(result3, result) + self.assertSequenceEqual(result3, result) self.assertEqual(result3.scheme, result.scheme) self.assertEqual(result3.netloc, result.netloc) self.assertEqual(result3.path, result.path) @@ -99,18 +99,18 @@ def checkRoundtrips(self, url, parsed, split): # check the roundtrip using urlsplit() as well result = urllib.parse.urlsplit(url) - self.assertEqual(result, split) + self.assertSequenceEqual(result, split) t = (result.scheme, result.netloc, result.path, result.query, result.fragment) - self.assertEqual(t, split) + self.assertSequenceEqual(t, split) result2 = urllib.parse.urlunsplit(result) - self.assertEqual(result2, url) - self.assertEqual(result2, result.geturl()) + self.assertSequenceEqual(result2, url) + self.assertSequenceEqual(result2, result.geturl()) # check the fixpoint property of re-parsing the result of geturl() result3 = urllib.parse.urlsplit(result.geturl()) self.assertEqual(result3.geturl(), result.geturl()) - self.assertEqual(result3, result) + self.assertSequenceEqual(result3, result) self.assertEqual(result3.scheme, result.scheme) self.assertEqual(result3.netloc, result.netloc) self.assertEqual(result3.path, result.path) @@ -162,10 +162,15 @@ def test_roundtrips(self): ('svn+ssh', 'svn.zope.org', '/repos/main/ZConfig/trunk/', '', '')), ('git+ssh://git at github.com/user/project.git', - ('git+ssh', 'git at github.com','/user/project.git', - '','',''), - ('git+ssh', 'git at github.com','/user/project.git', - '', '')), + ('git+ssh', 'git at github.com','/user/project.git', + '','',''), + ('git+ssh', 'git at github.com','/user/project.git', + '', '')), + ('itms-services://?action=download-manifest&url=https://example.com/app', + ('itms-services', '', '', '', + 'action=download-manifest&url=https://example.com/app', ''), + ('itms-services', '', '', + 'action=download-manifest&url=https://example.com/app', '')), ] def _encode(t): return (t[0].encode('ascii'), diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 5f95c5ff7f9c..777b7c53efe5 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -54,7 +54,7 @@ 'imap', 'wais', 'file', 'mms', 'https', 'shttp', 'snews', 'prospero', 'rtsp', 'rtspu', 'rsync', 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh', - 'ws', 'wss'] + 'ws', 'wss', 'itms-services'] uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap', 'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips', diff --git a/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst b/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst new file mode 100644 index 000000000000..145e75f6dea6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst @@ -0,0 +1,3 @@ +Teach :func:`urllib.parse.unsplit` to retain the ``"//"`` when assembling +``itms-services://?action=generate-bugs`` style `Apple Platform Deployment +<https://support.apple.com/en-gb/guide/deployment/depce7cefc4d/web>`_ URLs. From webhook-mailer at python.org Tue May 9 10:31:07 2023 From: webhook-mailer at python.org (vsajip) Date: Tue, 09 May 2023 14:31:07 -0000 Subject: [Python-checkins] [3.11] [doc] logging.rst - Change link to point directly to the Google Group. (GH-93390) (GH-104318) Message-ID: <mailman.265.1683642668.13550.python-checkins@python.org> https://github.com/python/cpython/commit/97e1e43af1378e24f902719da43d43964dad0960 commit: 97e1e43af1378e24f902719da43d43964dad0960 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip <vinay_sajip at yahoo.co.uk> date: 2023-05-09T15:31:00+01:00 summary: [3.11] [doc] logging.rst - Change link to point directly to the Google Group. (GH-93390) (GH-104318) (cherry picked from commit e6e81602f49a9bff51e2049c7bad60d1acb18d3f) files: M Doc/howto/logging.rst diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 87065273dab7..e2cf1b4fc392 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -336,7 +336,7 @@ favourite beverage and carry on. If your logging needs are simple, then use the above examples to incorporate logging into your own scripts, and if you run into problems or don't understand something, please post a question on the comp.lang.python Usenet -group (available at https://groups.google.com/forum/#!forum/comp.lang.python) and you +group (available at https://groups.google.com/g/comp.lang.python) and you should receive help before too long. Still here? You can carry on reading the next few sections, which provide a From webhook-mailer at python.org Tue May 9 10:53:28 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 09 May 2023 14:53:28 -0000 Subject: [Python-checkins] gh-104184: fix building --with-pydebug --enable-pystats (#104217) Message-ID: <mailman.266.1683644009.13550.python-checkins@python.org> https://github.com/python/cpython/commit/afe7703744f813adb15719642444b5fd35888d86 commit: afe7703744f813adb15719642444b5fd35888d86 branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-09T08:53:19-06:00 summary: gh-104184: fix building --with-pydebug --enable-pystats (#104217) files: M Python/specialize.c diff --git a/Python/specialize.c b/Python/specialize.c index b1cc66124cfa..2ccca3a2802c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1455,7 +1455,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins goto fail; } if (PyObject_CheckBuffer(container)) { - if (PyLong_CheckExact(sub) && (((size_t)Py_SIZE(sub)) > 1)) { + if (PyLong_CheckExact(sub) && (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub))) { SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE); } else if (strcmp(container_type->tp_name, "array.array") == 0) { From webhook-mailer at python.org Tue May 9 11:22:00 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 09 May 2023 15:22:00 -0000 Subject: [Python-checkins] [3.10] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104119) Message-ID: <mailman.267.1683645721.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d77e77c363a170f4435cbe826628b6a347654d9e commit: d77e77c363a170f4435cbe826628b6a347654d9e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-09T15:21:53Z summary: [3.10] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104119) gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) Do not expose the local server's on-disk location from `SimpleHTTPRequestHandler` when generating a directory index. (unnecessary information disclosure) --------- (cherry picked from commit c7c3a60c88de61a79ded9fdaf6bc6a29da4efb9a) Co-authored-by: Ethan Furman <ethan at stoneleaf.us> Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index 9c218d06acf5..b965c593d56d 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -791,7 +791,7 @@ def list_directory(self, path): displaypath = urllib.parse.unquote(self.path, errors='surrogatepass') except UnicodeDecodeError: - displaypath = urllib.parse.unquote(path) + displaypath = urllib.parse.unquote(self.path) displaypath = html.escape(displaypath, quote=False) enc = sys.getfilesystemencoding() title = 'Directory listing for %s' % displaypath diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index a5f787ff48c9..66ab064241a0 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -417,6 +417,14 @@ def test_undecodable_filename(self): self.check_status_and_reason(response, HTTPStatus.OK, data=os_helper.TESTFN_UNDECODABLE) + def test_undecodable_parameter(self): + # sanity check using a valid parameter + response = self.request(self.base_url + '/?x=123').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + # now the bogus encoding + response = self.request(self.base_url + '/?x=%bb').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. diff --git a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst new file mode 100644 index 000000000000..969deb26bfeb --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst @@ -0,0 +1,2 @@ +Do not expose the local on-disk location in directory indexes +produced by :class:`http.client.SimpleHTTPRequestHandler`. From webhook-mailer at python.org Tue May 9 12:02:06 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 09 May 2023 16:02:06 -0000 Subject: [Python-checkins] gh-99889: Fix directory traversal security flaw in uu.decode() (#104096) Message-ID: <mailman.268.1683648128.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0aeda297931820436a50b78f4f7f0597274b5df4 commit: 0aeda297931820436a50b78f4f7f0597274b5df4 branch: main author: Sam Carroll <70000253+samcarroll42 at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-09T16:01:58Z summary: gh-99889: Fix directory traversal security flaw in uu.decode() (#104096) * Fix directory traversal security flaw in uu.decode() * also check absolute paths and os.altsep * Add a regression test. --------- Co-authored-by: Gregory P. Smith <greg at krypto.org> [Google] files: A Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst M Lib/test/test_uu.py M Lib/uu.py diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py index 0493aae4fc67..a189d6bc4b05 100644 --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -147,6 +147,34 @@ def test_newlines_escaped(self): uu.encode(inp, out, filename) self.assertIn(safefilename, out.getvalue()) + def test_no_directory_traversal(self): + relative_bad = b"""\ +begin 644 ../../../../../../../../tmp/test1 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad)) + if os.altsep: + relative_bad_bs = relative_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad_bs)) + + absolute_bad = b"""\ +begin 644 /tmp/test2 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad)) + if os.altsep: + absolute_bad_bs = absolute_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad_bs)) + + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Lib/uu.py b/Lib/uu.py old mode 100755 new mode 100644 index 6f8805d8c5d0..26bb59ae073e --- a/Lib/uu.py +++ b/Lib/uu.py @@ -133,7 +133,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False): # If the filename isn't ASCII, what's up with that?!? out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii") if os.path.exists(out_file): - raise Error('Cannot overwrite existing file: %s' % out_file) + raise Error(f'Cannot overwrite existing file: {out_file}') + if (out_file.startswith(os.sep) or + f'..{os.sep}' in out_file or ( + os.altsep and + (out_file.startswith(os.altsep) or + f'..{os.altsep}' in out_file)) + ): + raise Error(f'Refusing to write to {out_file} due to directory traversal') if mode is None: mode = int(hdrfields[1], 8) # diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst new file mode 100644 index 000000000000..b7002e81b6b6 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst @@ -0,0 +1,2 @@ +Fixed a security in flaw in :func:`uu.decode` that could allow for +directory traversal based on the input if no ``out_file`` was specified. From webhook-mailer at python.org Tue May 9 12:46:32 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 09 May 2023 16:46:32 -0000 Subject: [Python-checkins] [3.11] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104329) Message-ID: <mailman.269.1683650793.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4ed59b1f330ca97b9f0b5567485283df24175fe4 commit: 4ed59b1f330ca97b9f0b5567485283df24175fe4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-09T09:46:25-07:00 summary: [3.11] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104329) gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) * Fix directory traversal security flaw in uu.decode() * also check absolute paths and os.altsep * Add a regression test. --------- (cherry picked from commit 0aeda297931820436a50b78f4f7f0597274b5df4) [Google] Co-authored-by: Sam Carroll <70000253+samcarroll42 at users.noreply.github.com> files: A Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst M Lib/test/test_uu.py M Lib/uu.py diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py index 0493aae4fc67..a189d6bc4b05 100644 --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -147,6 +147,34 @@ def test_newlines_escaped(self): uu.encode(inp, out, filename) self.assertIn(safefilename, out.getvalue()) + def test_no_directory_traversal(self): + relative_bad = b"""\ +begin 644 ../../../../../../../../tmp/test1 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad)) + if os.altsep: + relative_bad_bs = relative_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad_bs)) + + absolute_bad = b"""\ +begin 644 /tmp/test2 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad)) + if os.altsep: + absolute_bad_bs = absolute_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad_bs)) + + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Lib/uu.py b/Lib/uu.py old mode 100755 new mode 100644 index 6f8805d8c5d0..26bb59ae073e --- a/Lib/uu.py +++ b/Lib/uu.py @@ -133,7 +133,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False): # If the filename isn't ASCII, what's up with that?!? out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii") if os.path.exists(out_file): - raise Error('Cannot overwrite existing file: %s' % out_file) + raise Error(f'Cannot overwrite existing file: {out_file}') + if (out_file.startswith(os.sep) or + f'..{os.sep}' in out_file or ( + os.altsep and + (out_file.startswith(os.altsep) or + f'..{os.altsep}' in out_file)) + ): + raise Error(f'Refusing to write to {out_file} due to directory traversal') if mode is None: mode = int(hdrfields[1], 8) # diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst new file mode 100644 index 000000000000..b7002e81b6b6 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst @@ -0,0 +1,2 @@ +Fixed a security in flaw in :func:`uu.decode` that could allow for +directory traversal based on the input if no ``out_file`` was specified. From webhook-mailer at python.org Tue May 9 12:46:54 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 09 May 2023 16:46:54 -0000 Subject: [Python-checkins] [3.10] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104330) Message-ID: <mailman.270.1683650815.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cfa4295cd14ce00fe5263c7083aa5a73b515828d commit: cfa4295cd14ce00fe5263c7083aa5a73b515828d branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-09T09:46:47-07:00 summary: [3.10] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104330) gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) * Fix directory traversal security flaw in uu.decode() * also check absolute paths and os.altsep * Add a regression test. --------- (cherry picked from commit 0aeda297931820436a50b78f4f7f0597274b5df4) [Google] Co-authored-by: Sam Carroll <70000253+samcarroll42 at users.noreply.github.com> files: A Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst M Lib/test/test_uu.py M Lib/uu.py diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py index 753b31eef0d3..8cc1c074850b 100644 --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -145,6 +145,34 @@ def test_newlines_escaped(self): uu.encode(inp, out, filename) self.assertIn(safefilename, out.getvalue()) + def test_no_directory_traversal(self): + relative_bad = b"""\ +begin 644 ../../../../../../../../tmp/test1 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad)) + if os.altsep: + relative_bad_bs = relative_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad_bs)) + + absolute_bad = b"""\ +begin 644 /tmp/test2 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad)) + if os.altsep: + absolute_bad_bs = absolute_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad_bs)) + + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Lib/uu.py b/Lib/uu.py old mode 100755 new mode 100644 index 9f1f37f1a641..9fe252a639ea --- a/Lib/uu.py +++ b/Lib/uu.py @@ -130,7 +130,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False): # If the filename isn't ASCII, what's up with that?!? out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii") if os.path.exists(out_file): - raise Error('Cannot overwrite existing file: %s' % out_file) + raise Error(f'Cannot overwrite existing file: {out_file}') + if (out_file.startswith(os.sep) or + f'..{os.sep}' in out_file or ( + os.altsep and + (out_file.startswith(os.altsep) or + f'..{os.altsep}' in out_file)) + ): + raise Error(f'Refusing to write to {out_file} due to directory traversal') if mode is None: mode = int(hdrfields[1], 8) # diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst new file mode 100644 index 000000000000..b7002e81b6b6 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst @@ -0,0 +1,2 @@ +Fixed a security in flaw in :func:`uu.decode` that could allow for +directory traversal based on the input if no ``out_file`` was specified. From webhook-mailer at python.org Tue May 9 13:02:25 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 09 May 2023 17:02:25 -0000 Subject: [Python-checkins] gh-97933: (PEP 709) inline list/dict/set comprehensions (#101441) Message-ID: <mailman.271.1683651746.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c3b595e73efac59360d6dc869802abc752092460 commit: c3b595e73efac59360d6dc869802abc752092460 branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-09T11:02:14-06:00 summary: gh-97933: (PEP 709) inline list/dict/set comprehensions (#101441) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst M Doc/library/dis.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_code.h M Include/internal/pycore_compile.h M Include/internal/pycore_flowgraph.h M Include/internal/pycore_opcode.h M Include/internal/pycore_symtable.h M Include/opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test_compile.py M Lib/test/test_compiler_assemble.py M Lib/test/test_dis.py M Lib/test/test_inspect.py M Lib/test/test_listcomps.py M Lib/test/test_trace.py M Modules/_testinternalcapi.c M Objects/frameobject.c M Python/assemble.c M Python/bytecodes.c M Python/compile.c M Python/flowgraph.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/opcode_targets.h M Python/symtable.c diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 296d8a9c66fa..248743b8fa0a 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1196,6 +1196,14 @@ iterations of the loop. .. versionadded:: 3.12 +.. opcode:: LOAD_FAST_AND_CLEAR (var_num) + + Pushes a reference to the local ``co_varnames[var_num]`` onto the stack (or + pushes ``NULL`` onto the stack if the local variable has not been + initialized) and sets ``co_varnames[var_num]`` to ``NULL``. + + .. versionadded:: 3.12 + .. opcode:: STORE_FAST (var_num) Stores ``STACK.pop()`` into the local ``co_varnames[var_num]``. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 12d357f117b1..eb13d4bf031c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -153,6 +153,30 @@ New Features In Python 3.14, the default will switch to ``'data'``. (Contributed by Petr Viktorin in :pep:`706`.) +.. _whatsnew312-pep709: + +PEP 709: Comprehension inlining +------------------------------- + +Dictionary, list, and set comprehensions are now inlined, rather than creating a +new single-use function object for each execution of the comprehension. This +speeds up execution of a comprehension by up to 2x. + +Comprehension iteration variables remain isolated; they don't overwrite a +variable of the same name in the outer scope, nor are they visible after the +comprehension. This isolation is now maintained via stack/locals manipulation, +not via separate function scope. + +Inlining does result in a few visible behavior changes: + +* There is no longer a separate frame for the comprehension in tracebacks, + and tracing/profiling no longer shows the comprehension as a function call. +* Calling :func:`locals` inside a comprehension now includes variables + from outside the comprehension, and no longer includes the synthetic ``.0`` + variable for the comprehension "argument". + +Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`. + PEP 688: Making the buffer protocol accessible in Python -------------------------------------------------------- diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 86fd48b63ef8..c1f017fdb753 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -131,6 +131,7 @@ struct callable_cache { // Note that these all fit within a byte, as do combinations. // Later, we will use the smaller numbers to differentiate the different // kinds of locals (e.g. pos-only arg, varkwargs, local-only). +#define CO_FAST_HIDDEN 0x10 #define CO_FAST_LOCAL 0x20 #define CO_FAST_CELL 0x40 #define CO_FAST_FREE 0x80 diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index d2b12c91fe7a..499f55f3e276 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -70,6 +70,9 @@ typedef struct { PyObject *u_varnames; /* local variables */ PyObject *u_cellvars; /* cell variables */ PyObject *u_freevars; /* free variables */ + PyObject *u_fasthidden; /* dict; keys are names that are fast-locals only + temporarily within an inlined comprehension. When + value is True, treat as fast-local. */ Py_ssize_t u_argcount; /* number of arguments for block */ Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */ diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 883334f4b182..720feb186369 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -94,7 +94,7 @@ _PyCfgInstruction* _PyCfg_BasicblockLastInstr(const _PyCfgBasicblock *b); int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, int code_flags, int nlocals, int nparams, int firstlineno); int _PyCfg_Stackdepth(_PyCfgBasicblock *entryblock, int code_flags); -void _PyCfg_ConvertExceptionHandlersToNops(_PyCfgBasicblock *entryblock); +void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock); int _PyCfg_ResolveJumps(_PyCfgBuilder *g); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index a82885463ab2..52ee70a7bfdc 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -173,6 +173,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_CONST__LOAD_FAST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, [LOAD_FAST] = LOAD_FAST, + [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR, [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, [LOAD_FAST__LOAD_FAST] = LOAD_FAST, @@ -239,7 +240,7 @@ const uint8_t _PyOpcode_Deopt[256] = { #endif // NEED_OPCODE_TABLES #ifdef Py_DEBUG -static const char *const _PyOpcode_OpName[266] = { +static const char *const _PyOpcode_OpName[267] = { [CACHE] = "CACHE", [POP_TOP] = "POP_TOP", [PUSH_NULL] = "PUSH_NULL", @@ -383,7 +384,7 @@ static const char *const _PyOpcode_OpName[266] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [LOAD_SUPER_ATTR] = "LOAD_SUPER_ATTR", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [LOAD_FAST_AND_CLEAR] = "LOAD_FAST_AND_CLEAR", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -393,21 +394,21 @@ static const char *const _PyOpcode_OpName[266] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", - [167] = "<167>", [168] = "<168>", [169] = "<169>", [170] = "<170>", @@ -506,11 +507,11 @@ static const char *const _PyOpcode_OpName[266] = { [LOAD_SUPER_METHOD] = "LOAD_SUPER_METHOD", [LOAD_ZERO_SUPER_METHOD] = "LOAD_ZERO_SUPER_METHOD", [LOAD_ZERO_SUPER_ATTR] = "LOAD_ZERO_SUPER_ATTR", + [STORE_FAST_MAYBE_NULL] = "STORE_FAST_MAYBE_NULL", }; #endif #define EXTRA_CASES \ - case 167: \ case 168: \ case 169: \ case 170: \ diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 512c4c931f73..9a005be5402c 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -64,6 +64,7 @@ typedef struct _symtable_entry { unsigned ste_needs_class_closure : 1; /* for class scopes, true if a closure over __class__ should be created */ + unsigned ste_comp_inlined : 1; /* true if this comprehension is inlined */ unsigned ste_comp_iter_target : 1; /* true if visiting comprehension target */ int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */ int ste_lineno; /* first line of block */ diff --git a/Include/opcode.h b/Include/opcode.h index 37a9e9bffa4c..f6f4af8c793d 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -97,6 +97,7 @@ extern "C" { #define JUMP_BACKWARD 140 #define LOAD_SUPER_ATTR 141 #define CALL_FUNCTION_EX 142 +#define LOAD_FAST_AND_CLEAR 143 #define EXTENDED_ARG 144 #define LIST_APPEND 145 #define SET_ADD 146 @@ -146,7 +147,8 @@ extern "C" { #define LOAD_SUPER_METHOD 263 #define LOAD_ZERO_SUPER_METHOD 264 #define LOAD_ZERO_SUPER_ATTR 265 -#define MAX_PSEUDO_OPCODE 265 +#define STORE_FAST_MAYBE_NULL 266 +#define MAX_PSEUDO_OPCODE 266 #define BINARY_OP_ADD_FLOAT 6 #define BINARY_OP_ADD_INT 7 #define BINARY_OP_ADD_UNICODE 8 @@ -202,14 +204,14 @@ extern "C" { #define STORE_ATTR_INSTANCE_VALUE 111 #define STORE_ATTR_SLOT 112 #define STORE_ATTR_WITH_HINT 113 -#define STORE_FAST__LOAD_FAST 143 -#define STORE_FAST__STORE_FAST 153 -#define STORE_SUBSCR_DICT 154 -#define STORE_SUBSCR_LIST_INT 158 -#define UNPACK_SEQUENCE_LIST 159 -#define UNPACK_SEQUENCE_TUPLE 160 -#define UNPACK_SEQUENCE_TWO_TUPLE 161 -#define SEND_GEN 166 +#define STORE_FAST__LOAD_FAST 153 +#define STORE_FAST__STORE_FAST 154 +#define STORE_SUBSCR_DICT 158 +#define STORE_SUBSCR_LIST_INT 159 +#define UNPACK_SEQUENCE_LIST 160 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 166 +#define SEND_GEN 167 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ @@ -218,6 +220,7 @@ extern "C" { || ((op) == LOAD_SUPER_METHOD) \ || ((op) == LOAD_ZERO_SUPER_METHOD) \ || ((op) == LOAD_ZERO_SUPER_ATTR) \ + || ((op) == STORE_FAST_MAYBE_NULL) \ ) #define HAS_CONST(op) (false\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 7a3fdbaebdf2..d4a1593db2c8 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -442,6 +442,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12b1 3526 (Add instrumentation support) # Python 3.12b1 3527 (Add LOAD_SUPER_ATTR) # Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization) +# Python 3.12b1 3529 (Inline list/dict/set comprehensions) # Python 3.13 will start with 3550 @@ -458,7 +459,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 = (3528).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3529).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 ad54bd27fba3..d6d478aa1f47 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -198,6 +198,8 @@ def pseudo_op(name, op, real_ops): jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) name_op('LOAD_SUPER_ATTR', 141) def_op('CALL_FUNCTION_EX', 142) # Flags +def_op('LOAD_FAST_AND_CLEAR', 143) # Local variable number +haslocal.append(143) def_op('EXTENDED_ARG', 144) EXTENDED_ARG = 144 @@ -268,6 +270,8 @@ def pseudo_op(name, op, real_ops): pseudo_op('LOAD_ZERO_SUPER_METHOD', 264, ['LOAD_SUPER_ATTR']) pseudo_op('LOAD_ZERO_SUPER_ATTR', 265, ['LOAD_SUPER_ATTR']) +pseudo_op('STORE_FAST_MAYBE_NULL', 266, ['STORE_FAST']) + MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1 del def_op, name_op, jrel_op, jabs_op, pseudo_op diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index dca38418935b..c68b9ce38846 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1352,14 +1352,11 @@ def test_multiline_list_comprehension(self): and x != 50)] """) compiled_code, _ = self.check_positions_against_ast(snippet) - compiled_code = compiled_code.co_consts[0] self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND', line=1, end_line=2, column=1, end_column=8, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=8, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', - line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_list_comprehension(self): snippet = textwrap.dedent("""\ @@ -1374,13 +1371,13 @@ async def f(): compiled_code, _ = self.check_positions_against_ast(snippet) g = {} eval(compiled_code, g) - compiled_code = g['f'].__code__.co_consts[1] + compiled_code = g['f'].__code__ self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND', line=2, end_line=3, column=5, end_column=12, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=2, end_line=3, column=5, end_column=12, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST', line=2, end_line=7, column=4, end_column=36, occurrence=1) def test_multiline_set_comprehension(self): @@ -1393,14 +1390,11 @@ def test_multiline_set_comprehension(self): and x != 50)} """) compiled_code, _ = self.check_positions_against_ast(snippet) - compiled_code = compiled_code.co_consts[0] self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD', line=1, end_line=2, column=1, end_column=8, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=8, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', - line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_set_comprehension(self): snippet = textwrap.dedent("""\ @@ -1415,13 +1409,13 @@ async def f(): compiled_code, _ = self.check_positions_against_ast(snippet) g = {} eval(compiled_code, g) - compiled_code = g['f'].__code__.co_consts[1] + compiled_code = g['f'].__code__ self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD', line=2, end_line=3, column=5, end_column=12, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=2, end_line=3, column=5, end_column=12, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST', line=2, end_line=7, column=4, end_column=36, occurrence=1) def test_multiline_dict_comprehension(self): @@ -1434,14 +1428,11 @@ def test_multiline_dict_comprehension(self): and x != 50)} """) compiled_code, _ = self.check_positions_against_ast(snippet) - compiled_code = compiled_code.co_consts[0] self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD', line=1, end_line=2, column=1, end_column=7, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=7, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', - line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_dict_comprehension(self): snippet = textwrap.dedent("""\ @@ -1456,13 +1447,13 @@ async def f(): compiled_code, _ = self.check_positions_against_ast(snippet) g = {} eval(compiled_code, g) - compiled_code = g['f'].__code__.co_consts[1] + compiled_code = g['f'].__code__ self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD', line=2, end_line=3, column=5, end_column=11, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=2, end_line=3, column=5, end_column=11, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST', line=2, end_line=7, column=4, end_column=36, occurrence=1) def test_matchcase_sequence(self): @@ -1711,9 +1702,6 @@ def test_column_offset_deduplication(self): for source in [ "lambda: a", "(a for b in c)", - "[a for b in c]", - "{a for b in c}", - "{a: b for c in d}", ]: with self.subTest(source): code = compile(f"{source}, {source}", "<test>", "eval") diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py index 0bd7a09b001c..3e2a127de728 100644 --- a/Lib/test/test_compiler_assemble.py +++ b/Lib/test/test_compiler_assemble.py @@ -16,7 +16,7 @@ def complete_metadata(self, metadata, filename="myfile.py"): metadata.setdefault(key, key) for key in ['consts']: metadata.setdefault(key, []) - for key in ['names', 'varnames', 'cellvars', 'freevars']: + for key in ['names', 'varnames', 'cellvars', 'freevars', 'fasthidden']: metadata.setdefault(key, {}) for key in ['argcount', 'posonlyargcount', 'kwonlyargcount']: metadata.setdefault(key, 0) @@ -33,6 +33,9 @@ def assemble_test(self, insts, metadata, expected): expected_metadata = {} for key, value in metadata.items(): + if key == "fasthidden": + # not exposed on code object + continue if isinstance(value, list): expected_metadata[key] = tuple(value) elif isinstance(value, dict): diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 2f5d67fde861..c90702a408eb 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -154,7 +154,7 @@ def bug708901(): def bug1333982(x=[]): - assert 0, ([s for s in x] + + assert 0, ((s for s in x) + 1) pass @@ -162,7 +162,7 @@ def bug1333982(x=[]): %3d RESUME 0 %3d LOAD_ASSERTION_ERROR - LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) + LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>) MAKE_FUNCTION 0 LOAD_FAST 0 (x) GET_ITER @@ -675,7 +675,7 @@ async def _co(x): def _h(y): def foo(x): '''funcdoc''' - return [x + z for z in y] + return list(x + z for z in y) return foo dis_nested_0 = """\ @@ -705,13 +705,15 @@ def foo(x): %3d RESUME 0 -%3d LOAD_CLOSURE 0 (x) +%3d LOAD_GLOBAL 1 (NULL + list) + LOAD_CLOSURE 0 (x) BUILD_TUPLE 1 - LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) + LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>) MAKE_FUNCTION 8 (closure) LOAD_DEREF 1 (y) GET_ITER CALL 0 + CALL 1 RETURN_VALUE """ % (dis_nested_0, __file__, @@ -723,21 +725,28 @@ def foo(x): ) dis_nested_2 = """%s -Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>: +Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>: COPY_FREE_VARS 1 -%3d RESUME 0 - BUILD_LIST 0 +%3d RETURN_GENERATOR + POP_TOP + RESUME 0 LOAD_FAST 0 (.0) - >> FOR_ITER 7 (to 26) + >> FOR_ITER 9 (to 32) STORE_FAST 1 (z) LOAD_DEREF 2 (x) LOAD_FAST 1 (z) BINARY_OP 0 (+) - LIST_APPEND 2 - JUMP_BACKWARD 9 (to 8) + YIELD_VALUE 1 + RESUME 1 + POP_TOP + JUMP_BACKWARD 11 (to 10) >> END_FOR - RETURN_VALUE + RETURN_CONST 0 (None) + >> CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR) + RERAISE 1 +ExceptionTable: +1 row """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index d2b2f3171e78..364f75db908b 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -4280,14 +4280,14 @@ def test(*args, **kwargs): @cpython_only def test_signature_bind_implicit_arg(self): - # Issue #19611: getcallargs should work with set comprehensions + # Issue #19611: getcallargs should work with comprehensions def make_set(): - return {z * z for z in range(5)} - setcomp_code = make_set.__code__.co_consts[1] - setcomp_func = types.FunctionType(setcomp_code, {}) + return set(z * z for z in range(5)) + gencomp_code = make_set.__code__.co_consts[1] + gencomp_func = types.FunctionType(gencomp_code, {}) iterator = iter(range(5)) - self.assertEqual(self.call(setcomp_func, iterator), {0, 1, 4, 9, 16}) + self.assertEqual(set(self.call(gencomp_func, iterator)), {0, 1, 4, 9, 16}) def test_signature_bind_posonly_kwargs(self): def foo(bar, /, **kwargs): diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 91bf2547edc4..92fed98dd000 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -1,4 +1,5 @@ import doctest +import textwrap import unittest @@ -87,63 +88,227 @@ >>> [None for i in range(10)] [None, None, None, None, None, None, None, None, None, None] -########### Tests for various scoping corner cases ############ - -Return lambdas that use the iteration variable as a default argument - - >>> items = [(lambda i=i: i) for i in range(5)] - >>> [x() for x in items] - [0, 1, 2, 3, 4] - -Same again, only this time as a closure variable - - >>> items = [(lambda: i) for i in range(5)] - >>> [x() for x in items] - [4, 4, 4, 4, 4] - -Another way to test that the iteration variable is local to the list comp - - >>> items = [(lambda: i) for i in range(5)] - >>> i = 20 - >>> [x() for x in items] - [4, 4, 4, 4, 4] - -And confirm that a closure can jump over the list comp scope - - >>> items = [(lambda: y) for i in range(5)] - >>> y = 2 - >>> [x() for x in items] - [2, 2, 2, 2, 2] - -We also repeat each of the above scoping tests inside a function - - >>> def test_func(): - ... items = [(lambda i=i: i) for i in range(5)] - ... return [x() for x in items] - >>> test_func() - [0, 1, 2, 3, 4] +""" - >>> def test_func(): - ... items = [(lambda: i) for i in range(5)] - ... return [x() for x in items] - >>> test_func() - [4, 4, 4, 4, 4] - - >>> def test_func(): - ... items = [(lambda: i) for i in range(5)] - ... i = 20 - ... return [x() for x in items] - >>> test_func() - [4, 4, 4, 4, 4] - - >>> def test_func(): - ... items = [(lambda: y) for i in range(5)] - ... y = 2 - ... return [x() for x in items] - >>> test_func() - [2, 2, 2, 2, 2] -""" +class ListComprehensionTest(unittest.TestCase): + def _check_in_scopes(self, code, outputs=None, ns=None, scopes=None, raises=()): + code = textwrap.dedent(code) + scopes = scopes or ["module", "class", "function"] + for scope in scopes: + with self.subTest(scope=scope): + if scope == "class": + newcode = textwrap.dedent(""" + class _C: + {code} + """).format(code=textwrap.indent(code, " ")) + def get_output(moddict, name): + return getattr(moddict["_C"], name) + elif scope == "function": + newcode = textwrap.dedent(""" + def _f(): + {code} + return locals() + _out = _f() + """).format(code=textwrap.indent(code, " ")) + def get_output(moddict, name): + return moddict["_out"][name] + else: + newcode = code + def get_output(moddict, name): + return moddict[name] + ns = ns or {} + try: + exec(newcode, ns) + except raises as e: + # We care about e.g. NameError vs UnboundLocalError + self.assertIs(type(e), raises) + else: + for k, v in (outputs or {}).items(): + self.assertEqual(get_output(ns, k), v) + + def test_lambdas_with_iteration_var_as_default(self): + code = """ + items = [(lambda i=i: i) for i in range(5)] + y = [x() for x in items] + """ + outputs = {"y": [0, 1, 2, 3, 4]} + self._check_in_scopes(code, outputs) + + def test_lambdas_with_free_var(self): + code = """ + items = [(lambda: i) for i in range(5)] + y = [x() for x in items] + """ + outputs = {"y": [4, 4, 4, 4, 4]} + self._check_in_scopes(code, outputs) + + def test_class_scope_free_var_with_class_cell(self): + class C: + def method(self): + super() + return __class__ + items = [(lambda: i) for i in range(5)] + y = [x() for x in items] + + self.assertEqual(C.y, [4, 4, 4, 4, 4]) + self.assertIs(C().method(), C) + + def test_inner_cell_shadows_outer(self): + code = """ + items = [(lambda: i) for i in range(5)] + i = 20 + y = [x() for x in items] + """ + outputs = {"y": [4, 4, 4, 4, 4], "i": 20} + self._check_in_scopes(code, outputs) + + def test_closure_can_jump_over_comp_scope(self): + code = """ + items = [(lambda: y) for i in range(5)] + y = 2 + z = [x() for x in items] + """ + outputs = {"z": [2, 2, 2, 2, 2]} + self._check_in_scopes(code, outputs) + + def test_inner_cell_shadows_outer_redefined(self): + code = """ + y = 10 + items = [(lambda: y) for y in range(5)] + x = y + y = 20 + out = [z() for z in items] + """ + outputs = {"x": 10, "out": [4, 4, 4, 4, 4]} + self._check_in_scopes(code, outputs) + + def test_shadows_outer_cell(self): + code = """ + def inner(): + return g + [g for g in range(5)] + x = inner() + """ + outputs = {"x": -1} + self._check_in_scopes(code, outputs, ns={"g": -1}) + + def test_assignment_expression(self): + code = """ + x = -1 + items = [(x:=y) for y in range(3)] + """ + outputs = {"x": 2} + # assignment expression in comprehension is disallowed in class scope + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + + def test_free_var_in_comp_child(self): + code = """ + lst = range(3) + funcs = [lambda: x for x in lst] + inc = [x + 1 for x in lst] + [x for x in inc] + x = funcs[0]() + """ + outputs = {"x": 2} + self._check_in_scopes(code, outputs) + + def test_shadow_with_free_and_local(self): + code = """ + lst = range(3) + x = -1 + funcs = [lambda: x for x in lst] + items = [x + 1 for x in lst] + """ + outputs = {"x": -1} + self._check_in_scopes(code, outputs) + + def test_shadow_comp_iterable_name(self): + code = """ + x = [1] + y = [x for x in x] + """ + outputs = {"x": [1]} + self._check_in_scopes(code, outputs) + + def test_nested_free(self): + code = """ + x = 1 + def g(): + [x for x in range(3)] + return x + g() + """ + outputs = {"x": 1} + self._check_in_scopes(code, outputs) + + def test_introspecting_frame_locals(self): + code = """ + import sys + [i for i in range(2)] + i = 20 + sys._getframe().f_locals + """ + outputs = {"i": 20} + self._check_in_scopes(code, outputs) + + def test_nested(self): + code = """ + l = [2, 3] + y = [[x ** 2 for x in range(x)] for x in l] + """ + outputs = {"y": [[0, 1], [0, 1, 4]]} + self._check_in_scopes(code, outputs) + + def test_nested_2(self): + code = """ + l = [1, 2, 3] + x = 3 + y = [x for [x ** x for x in range(x)][x - 1] in l] + """ + outputs = {"y": [3, 3, 3]} + self._check_in_scopes(code, outputs) + + def test_nested_3(self): + code = """ + l = [(1, 2), (3, 4), (5, 6)] + y = [x for (x, [x ** x for x in range(x)][x - 1]) in l] + """ + outputs = {"y": [1, 3, 5]} + self._check_in_scopes(code, outputs) + + def test_nameerror(self): + code = """ + [x for x in [1]] + x + """ + + self._check_in_scopes(code, raises=NameError) + + def test_dunder_name(self): + code = """ + y = [__x for __x in [1]] + """ + outputs = {"y": [1]} + self._check_in_scopes(code, outputs) + + def test_unbound_local_after_comprehension(self): + def f(): + if False: + x = 0 + [x for x in [1]] + return x + + with self.assertRaises(UnboundLocalError): + f() + + def test_unbound_local_inside_comprehension(self): + def f(): + l = [None] + return [1 for (l[0], l) in [[1, 2]]] + + with self.assertRaises(UnboundLocalError): + f() __test__ = {'doctests' : doctests} diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py index fad2b3b8379f..73339ebdb7c4 100644 --- a/Lib/test/test_trace.py +++ b/Lib/test/test_trace.py @@ -187,9 +187,7 @@ def test_trace_list_comprehension(self): firstlineno_called = get_firstlineno(traced_doubler) expected = { (self.my_py_filename, firstlineno_calling + 1): 1, - # List comprehensions work differently in 3.x, so the count - # below changed compared to 2.x. - (self.my_py_filename, firstlineno_calling + 2): 12, + (self.my_py_filename, firstlineno_calling + 2): 11, (self.my_py_filename, firstlineno_calling + 3): 1, (self.my_py_filename, firstlineno_called + 1): 10, } diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst new file mode 100644 index 000000000000..2eec05cb3ace --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst @@ -0,0 +1,2 @@ +:pep:`709`: inline list, dict and set comprehensions to improve performance +and reduce bytecode size. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 8009dca3d0b7..ea9b6e72b3c9 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -669,12 +669,14 @@ _testinternalcapi_assemble_code_object_impl(PyObject *module, umd.u_varnames = PyDict_GetItemString(metadata, "varnames"); umd.u_cellvars = PyDict_GetItemString(metadata, "cellvars"); umd.u_freevars = PyDict_GetItemString(metadata, "freevars"); + umd.u_fasthidden = PyDict_GetItemString(metadata, "fasthidden"); assert(PyDict_Check(umd.u_consts)); assert(PyDict_Check(umd.u_names)); assert(PyDict_Check(umd.u_varnames)); assert(PyDict_Check(umd.u_cellvars)); assert(PyDict_Check(umd.u_freevars)); + assert(PyDict_Check(umd.u_fasthidden)); umd.u_argcount = get_nonnegative_int_from_dict(metadata, "argcount"); umd.u_posonlyargcount = get_nonnegative_int_from_dict(metadata, "posonlyargcount"); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d0eca447c012..d9aaea7831a3 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1224,6 +1224,10 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) } PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); + _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); + if (kind & CO_FAST_HIDDEN) { + continue; + } if (value == NULL) { if (PyObject_DelItem(locals, name) != 0) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { diff --git a/Python/assemble.c b/Python/assemble.c index 369dd8dcde9b..6889831ae3fe 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -456,6 +456,9 @@ compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus, assert(offset < nlocalsplus); // For now we do not distinguish arg kinds. _PyLocals_Kind kind = CO_FAST_LOCAL; + if (PyDict_Contains(umd->u_fasthidden, k)) { + kind |= CO_FAST_HIDDEN; + } if (PyDict_GetItem(umd->u_cellvars, k) != NULL) { kind |= CO_FAST_CELL; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e83894e89028..82c100444183 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -194,6 +194,12 @@ dummy_func( Py_INCREF(value); } + inst(LOAD_FAST_AND_CLEAR, (-- value)) { + value = GETLOCAL(oparg); + // do not use SETLOCAL here, it decrefs the old value + GETLOCAL(oparg) = NULL; + } + inst(LOAD_CONST, (-- value)) { value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); diff --git a/Python/compile.c b/Python/compile.c index 12ae83136196..941c6e9d4fdb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -381,7 +381,6 @@ struct compiler_unit { int u_scope_type; - PyObject *u_private; /* for private name mangling */ instr_sequence u_instr_sequence; /* codegen output */ @@ -485,13 +484,15 @@ static int compiler_sync_comprehension_generator( struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, - expr_ty elt, expr_ty val, int type); + expr_ty elt, expr_ty val, int type, + int iter_on_stack); static int compiler_async_comprehension_generator( struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, - expr_ty elt, expr_ty val, int type); + expr_ty elt, expr_ty val, int type, + int iter_on_stack); static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *); static int compiler_match(struct compiler *, stmt_ty); @@ -689,6 +690,7 @@ compiler_unit_free(struct compiler_unit *u) 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_metadata.u_fasthidden); Py_CLEAR(u->u_private); PyObject_Free(u); } @@ -837,6 +839,8 @@ stack_effect(int opcode, int oparg, int jump) * if an exception be raised. */ return jump ? 1 : 0; + case STORE_FAST_MAYBE_NULL: + return -1; case LOAD_METHOD: return 1; case LOAD_SUPER_METHOD: @@ -1239,11 +1243,9 @@ compiler_enter_scope(struct compiler *c, identifier name, } if (u->u_ste->ste_needs_class_closure) { /* Cook up an implicit __class__ cell. */ - int res; + Py_ssize_t res; assert(u->u_scope_type == COMPILER_SCOPE_CLASS); - assert(PyDict_GET_SIZE(u->u_metadata.u_cellvars) == 0); - res = PyDict_SetItem(u->u_metadata.u_cellvars, &_Py_ID(__class__), - _PyLong_GetZero()); + res = dict_add_o(u->u_metadata.u_cellvars, &_Py_ID(__class__)); if (res < 0) { compiler_unit_free(u); return ERROR; @@ -1257,6 +1259,12 @@ compiler_enter_scope(struct compiler *c, identifier name, return ERROR; } + u->u_metadata.u_fasthidden = PyDict_New(); + if (!u->u_metadata.u_fasthidden) { + compiler_unit_free(u); + return ERROR; + } + u->u_nfblocks = 0; u->u_metadata.u_firstlineno = lineno; u->u_metadata.u_consts = PyDict_New(); @@ -2235,7 +2243,6 @@ compiler_class(struct compiler *c, stmt_ty s) compiler_exit_scope(c); return ERROR; } - assert(i == 0); ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); ADDOP_I(c, NO_LOCATION, COPY, 1); if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) { @@ -2245,7 +2252,6 @@ compiler_class(struct compiler *c, stmt_ty s) } else { /* No methods referenced __class__, so just return None */ - 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); @@ -3718,7 +3724,8 @@ compiler_nameop(struct compiler *c, location loc, optype = OP_DEREF; break; case LOCAL: - if (c->u->u_ste->ste_type == FunctionBlock) + if (c->u->u_ste->ste_type == FunctionBlock || + (PyDict_GetItem(c->u->u_metadata.u_fasthidden, mangled) == Py_True)) optype = OP_FAST; break; case GLOBAL_IMPLICIT: @@ -4742,16 +4749,19 @@ static int compiler_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, - expr_ty elt, expr_ty val, int type) + expr_ty elt, expr_ty val, int type, + int iter_on_stack) { comprehension_ty gen; gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); if (gen->is_async) { return compiler_async_comprehension_generator( - c, loc, generators, gen_index, depth, elt, val, type); + c, loc, generators, gen_index, depth, elt, val, type, + iter_on_stack); } else { return compiler_sync_comprehension_generator( - c, loc, generators, gen_index, depth, elt, val, type); + c, loc, generators, gen_index, depth, elt, val, type, + iter_on_stack); } } @@ -4759,7 +4769,8 @@ static int compiler_sync_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, - expr_ty elt, expr_ty val, int type) + expr_ty elt, expr_ty val, int type, + int iter_on_stack) { /* generate code for the iterator, then each of the ifs, and then write to the element */ @@ -4771,37 +4782,39 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); - if (gen_index == 0) { - /* Receive outermost iter as an implicit argument */ - c->u->u_metadata.u_argcount = 1; - ADDOP_I(c, loc, LOAD_FAST, 0); - } - else { - /* Sub-iter - calculate on the fly */ - /* Fast path for the temporary variable assignment idiom: - for y in [f(x)] - */ - asdl_expr_seq *elts; - switch (gen->iter->kind) { - case List_kind: - elts = gen->iter->v.List.elts; - break; - case Tuple_kind: - elts = gen->iter->v.Tuple.elts; - break; - default: - elts = NULL; - } - if (asdl_seq_LEN(elts) == 1) { - expr_ty elt = asdl_seq_GET(elts, 0); - if (elt->kind != Starred_kind) { - VISIT(c, expr, elt); - start = NO_LABEL; - } + if (!iter_on_stack) { + if (gen_index == 0) { + /* Receive outermost iter as an implicit argument */ + c->u->u_metadata.u_argcount = 1; + ADDOP_I(c, loc, LOAD_FAST, 0); } - if (IS_LABEL(start)) { - VISIT(c, expr, gen->iter); - ADDOP(c, loc, GET_ITER); + else { + /* Sub-iter - calculate on the fly */ + /* Fast path for the temporary variable assignment idiom: + for y in [f(x)] + */ + asdl_expr_seq *elts; + switch (gen->iter->kind) { + case List_kind: + elts = gen->iter->v.List.elts; + break; + case Tuple_kind: + elts = gen->iter->v.Tuple.elts; + break; + default: + elts = NULL; + } + if (asdl_seq_LEN(elts) == 1) { + expr_ty elt = asdl_seq_GET(elts, 0); + if (elt->kind != Starred_kind) { + VISIT(c, expr, elt); + start = NO_LABEL; + } + } + if (IS_LABEL(start)) { + VISIT(c, expr, gen->iter); + ADDOP(c, loc, GET_ITER); + } } } if (IS_LABEL(start)) { @@ -4822,7 +4835,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc, RETURN_IF_ERROR( compiler_comprehension_generator(c, loc, generators, gen_index, depth, - elt, val, type)); + elt, val, type, 0)); } location elt_loc = LOC(elt); @@ -4875,7 +4888,8 @@ static int compiler_async_comprehension_generator(struct compiler *c, location loc, asdl_comprehension_seq *generators, int gen_index, int depth, - expr_ty elt, expr_ty val, int type) + expr_ty elt, expr_ty val, int type, + int iter_on_stack) { NEW_JUMP_TARGET_LABEL(c, start); NEW_JUMP_TARGET_LABEL(c, except); @@ -4884,15 +4898,17 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators, gen_index); - if (gen_index == 0) { - /* Receive outermost iter as an implicit argument */ - c->u->u_metadata.u_argcount = 1; - ADDOP_I(c, loc, LOAD_FAST, 0); - } - else { - /* Sub-iter - calculate on the fly */ - VISIT(c, expr, gen->iter); - ADDOP(c, loc, GET_AITER); + if (!iter_on_stack) { + if (gen_index == 0) { + /* Receive outermost iter as an implicit argument */ + c->u->u_metadata.u_argcount = 1; + ADDOP_I(c, loc, LOAD_FAST, 0); + } + else { + /* Sub-iter - calculate on the fly */ + VISIT(c, expr, gen->iter); + ADDOP(c, loc, GET_AITER); + } } USE_LABEL(c, start); @@ -4919,7 +4935,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, RETURN_IF_ERROR( compiler_comprehension_generator(c, loc, generators, gen_index, depth, - elt, val, type)); + elt, val, type, 0)); } location elt_loc = LOC(elt); @@ -4968,26 +4984,212 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, return SUCCESS; } +typedef struct { + PyObject *pushed_locals; + PyObject *temp_symbols; + PyObject *fast_hidden; +} inlined_comprehension_state; + +static int +push_inlined_comprehension_state(struct compiler *c, location loc, + PySTEntryObject *entry, + inlined_comprehension_state *state) +{ + // iterate over names bound in the comprehension and ensure we isolate + // them from the outer scope as needed + PyObject *k, *v; + Py_ssize_t pos = 0; + while (PyDict_Next(entry->ste_symbols, &pos, &k, &v)) { + assert(PyLong_Check(v)); + long symbol = PyLong_AS_LONG(v); + // only values bound in the comprehension (DEF_LOCAL) need to be handled + // at all; DEF_LOCAL | DEF_NONLOCAL can occur in the case of an + // assignment expression to a nonlocal in the comprehension, these don't + // need handling here since they shouldn't be isolated + if (symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) { + if (c->u->u_ste->ste_type != FunctionBlock) { + // non-function scope: override this name to use fast locals + PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k); + if (orig != Py_True) { + if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_True) < 0) { + return ERROR; + } + if (state->fast_hidden == NULL) { + state->fast_hidden = PySet_New(NULL); + if (state->fast_hidden == NULL) { + return ERROR; + } + } + if (PySet_Add(state->fast_hidden, k) < 0) { + return ERROR; + } + } + } + long scope = (symbol >> SCOPE_OFFSET) & SCOPE_MASK; + PyObject *outv = PyDict_GetItemWithError(c->u->u_ste->ste_symbols, k); + if (outv == NULL) { + return ERROR; + } + assert(PyLong_Check(outv)); + long outsc = (PyLong_AS_LONG(outv) >> SCOPE_OFFSET) & SCOPE_MASK; + if (scope != outsc) { + // If a name has different scope inside than outside the + // comprehension, we need to temporarily handle it with the + // right scope while compiling the comprehension. + if (state->temp_symbols == NULL) { + state->temp_symbols = PyDict_New(); + if (state->temp_symbols == NULL) { + return ERROR; + } + } + // update the symbol to the in-comprehension version and save + // the outer version; we'll restore it after running the + // comprehension + Py_INCREF(outv); + if (PyDict_SetItem(c->u->u_ste->ste_symbols, k, v) < 0) { + Py_DECREF(outv); + return ERROR; + } + if (PyDict_SetItem(state->temp_symbols, k, outv) < 0) { + Py_DECREF(outv); + return ERROR; + } + Py_DECREF(outv); + } + if (outsc == LOCAL || outsc == CELL || outsc == FREE) { + // local names bound in comprehension must be isolated from + // outer scope; push existing value (which may be NULL if + // not defined) on stack + if (state->pushed_locals == NULL) { + state->pushed_locals = PyList_New(0); + if (state->pushed_locals == NULL) { + return ERROR; + } + } + // in the case of a cell, this will actually push the cell + // itself to the stack, then we'll create a new one for the + // comprehension and restore the original one after + ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames); + if (scope == CELL) { + ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars); + } + if (PyList_Append(state->pushed_locals, k) < 0) { + return ERROR; + } + } + } + } + if (state->pushed_locals) { + // Outermost iterable expression was already evaluated and is on the + // stack, we need to swap it back to TOS. This also rotates the order of + // `pushed_locals` on the stack, but this will be reversed when we swap + // out the comprehension result in pop_inlined_comprehension_state + ADDOP_I(c, loc, SWAP, PyList_GET_SIZE(state->pushed_locals) + 1); + } + + return SUCCESS; +} + +static int +pop_inlined_comprehension_state(struct compiler *c, location loc, + inlined_comprehension_state state) +{ + PyObject *k, *v; + Py_ssize_t pos = 0; + if (state.temp_symbols) { + while (PyDict_Next(state.temp_symbols, &pos, &k, &v)) { + if (PyDict_SetItem(c->u->u_ste->ste_symbols, k, v)) { + return ERROR; + } + } + Py_CLEAR(state.temp_symbols); + } + if (state.pushed_locals) { + // pop names we pushed to stack earlier + Py_ssize_t npops = PyList_GET_SIZE(state.pushed_locals); + // Preserve the list/dict/set result of the comprehension as TOS. This + // reverses the SWAP we did in push_inlined_comprehension_state to get + // the outermost iterable to TOS, so we can still just iterate + // pushed_locals in simple reverse order + ADDOP_I(c, loc, SWAP, npops + 1); + for (Py_ssize_t i = npops - 1; i >= 0; --i) { + k = PyList_GetItem(state.pushed_locals, i); + if (k == NULL) { + return ERROR; + } + ADDOP_NAME(c, loc, STORE_FAST_MAYBE_NULL, k, varnames); + } + Py_CLEAR(state.pushed_locals); + } + if (state.fast_hidden) { + while (PySet_Size(state.fast_hidden) > 0) { + PyObject *k = PySet_Pop(state.fast_hidden); + if (k == NULL) { + return ERROR; + } + // we set to False instead of clearing, so we can track which names + // were temporarily fast-locals and should use CO_FAST_HIDDEN + if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_False)) { + Py_DECREF(k); + return ERROR; + } + Py_DECREF(k); + } + Py_CLEAR(state.fast_hidden); + } + return SUCCESS; +} + +static inline int +compiler_comprehension_iter(struct compiler *c, location loc, + comprehension_ty comp) +{ + VISIT(c, expr, comp->iter); + if (comp->is_async) { + ADDOP(c, loc, GET_AITER); + } + else { + ADDOP(c, loc, GET_ITER); + } + return SUCCESS; +} + static int compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, asdl_comprehension_seq *generators, expr_ty elt, expr_ty val) { PyCodeObject *co = NULL; + inlined_comprehension_state inline_state = {NULL, NULL}; comprehension_ty outermost; int scope_type = c->u->u_scope_type; - int is_async_generator = 0; int is_top_level_await = IS_TOP_LEVEL_AWAIT(c); - - outermost = (comprehension_ty) asdl_seq_GET(generators, 0); - if (compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION, - (void *)e, e->lineno) < 0) - { + PySTEntryObject *entry = PySymtable_Lookup(c->c_st, (void *)e); + if (entry == NULL) { goto error; } + int is_inlined = entry->ste_comp_inlined; + int is_async_generator = entry->ste_coroutine; + location loc = LOC(e); - is_async_generator = c->u->u_ste->ste_coroutine; + outermost = (comprehension_ty) asdl_seq_GET(generators, 0); + if (is_inlined) { + if (compiler_comprehension_iter(c, loc, outermost)) { + goto error; + } + if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) { + goto error; + } + } + else { + if (compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION, + (void *)e, e->lineno) < 0) + { + goto error; + } + } + Py_CLEAR(entry); if (is_async_generator && type != COMP_GENEXP && scope_type != COMPILER_SCOPE_ASYNC_FUNCTION && @@ -5018,13 +5220,23 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } ADDOP_I(c, loc, op, 0); + if (is_inlined) { + ADDOP_I(c, loc, SWAP, 2); + } } if (compiler_comprehension_generator(c, loc, generators, 0, 0, - elt, val, type) < 0) { + elt, val, type, is_inlined) < 0) { goto error_in_scope; } + if (is_inlined) { + if (pop_inlined_comprehension_state(c, loc, inline_state)) { + goto error; + } + return SUCCESS; + } + if (type != COMP_GENEXP) { ADDOP(c, LOC(e), RETURN_VALUE); } @@ -5047,15 +5259,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, if (compiler_make_closure(c, loc, co, 0) < 0) { goto error; } - Py_DECREF(co); + Py_CLEAR(co); - VISIT(c, expr, outermost->iter); - - loc = LOC(e); - if (outermost->is_async) { - ADDOP(c, loc, GET_AITER); - } else { - ADDOP(c, loc, GET_ITER); + if (compiler_comprehension_iter(c, loc, outermost)) { + goto error; } ADDOP_I(c, loc, CALL, 0); @@ -5068,9 +5275,15 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, return SUCCESS; error_in_scope: - compiler_exit_scope(c); + if (!is_inlined) { + compiler_exit_scope(c); + } error: Py_XDECREF(co); + Py_XDECREF(entry); + Py_XDECREF(inline_state.pushed_locals); + Py_XDECREF(inline_state.temp_symbols); + Py_XDECREF(inline_state.fast_hidden); return ERROR; } @@ -6989,7 +7202,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, goto error; } - _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock); + _PyCfg_ConvertPseudoOps(g.g_entryblock); /* Order of basic blocks must have been determined by now */ @@ -7401,7 +7614,7 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, goto error; } - _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock); + _PyCfg_ConvertPseudoOps(g.g_entryblock); /* Order of basic blocks must have been determined by now */ diff --git a/Python/flowgraph.c b/Python/flowgraph.c index f79afb4c66cd..7f790b79d284 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1289,7 +1289,9 @@ swaptimize(basicblock *block, int *ix) // - can't invoke arbitrary code (besides finalizers) // - only touch the TOS (and pop it when finished) #define SWAPPABLE(opcode) \ - ((opcode) == STORE_FAST || (opcode) == POP_TOP) + ((opcode) == STORE_FAST || \ + (opcode) == STORE_FAST_MAYBE_NULL || \ + (opcode) == POP_TOP) static int next_swappable_instruction(basicblock *block, int i, int lineno) @@ -1600,6 +1602,8 @@ scan_block_for_locals(basicblock *b, basicblock ***sp) uint64_t bit = (uint64_t)1 << instr->i_oparg; switch (instr->i_opcode) { case DELETE_FAST: + case LOAD_FAST_AND_CLEAR: + case STORE_FAST_MAYBE_NULL: unsafe_mask |= bit; break; case STORE_FAST: @@ -1639,7 +1643,8 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals) Py_ssize_t blocknum = 0; // state[i - 64] == blocknum if local i is guaranteed to // be initialized, i.e., if it has had a previous LOAD_FAST or - // STORE_FAST within that basicblock (not followed by DELETE_FAST). + // STORE_FAST within that basicblock (not followed by + // DELETE_FAST/LOAD_FAST_AND_CLEAR/STORE_FAST_MAYBE_NULL). for (basicblock *b = entryblock; b != NULL; b = b->b_next) { blocknum++; for (int i = 0; i < b->b_iused; i++) { @@ -1653,6 +1658,8 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals) assert(arg >= 0); switch (instr->i_opcode) { case DELETE_FAST: + case LOAD_FAST_AND_CLEAR: + case STORE_FAST_MAYBE_NULL: states[arg - 64] = blocknum - 1; break; case STORE_FAST: @@ -1975,7 +1982,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { } void -_PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock) +_PyCfg_ConvertPseudoOps(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { @@ -1983,6 +1990,9 @@ _PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock) if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) { INSTR_SET_OP0(instr, NOP); } + else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) { + instr->i_opcode = STORE_FAST; + } } } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 069a7ced0a4c..819c857c3c01 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -92,13 +92,25 @@ DISPATCH(); } + TARGET(LOAD_FAST_AND_CLEAR) { + PyObject *value; + #line 198 "Python/bytecodes.c" + value = GETLOCAL(oparg); + // do not use SETLOCAL here, it decrefs the old value + GETLOCAL(oparg) = NULL; + #line 102 "Python/generated_cases.c.h" + STACK_GROW(1); + stack_pointer[-1] = value; + DISPATCH(); + } + TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - #line 198 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); - #line 102 "Python/generated_cases.c.h" + #line 114 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -106,9 +118,9 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 203 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 112 "Python/generated_cases.c.h" + #line 124 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -122,7 +134,7 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 126 "Python/generated_cases.c.h" + #line 138 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; @@ -132,7 +144,7 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 136 "Python/generated_cases.c.h" + #line 148 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -150,16 +162,16 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 154 "Python/generated_cases.c.h" + #line 166 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 198 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); - #line 163 "Python/generated_cases.c.h" + #line 175 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -172,9 +184,9 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; - #line 203 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 178 "Python/generated_cases.c.h" + #line 190 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { @@ -183,7 +195,7 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 187 "Python/generated_cases.c.h" + #line 199 "Python/generated_cases.c.h" _tmp_1 = value; } stack_pointer[-1] = _tmp_1; @@ -195,16 +207,16 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 203 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 201 "Python/generated_cases.c.h" + #line 213 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; - #line 203 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 208 "Python/generated_cases.c.h" + #line 220 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -215,10 +227,10 @@ PyObject *_tmp_2; { PyObject *value; - #line 198 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); - #line 222 "Python/generated_cases.c.h" + #line 234 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; @@ -228,7 +240,7 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 232 "Python/generated_cases.c.h" + #line 244 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -239,8 +251,8 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 213 "Python/bytecodes.c" - #line 244 "Python/generated_cases.c.h" + #line 219 "Python/bytecodes.c" + #line 256 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); @@ -248,9 +260,9 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 217 "Python/bytecodes.c" + #line 223 "Python/bytecodes.c" res = NULL; - #line 254 "Python/generated_cases.c.h" + #line 266 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -261,14 +273,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 213 "Python/bytecodes.c" - #line 266 "Python/generated_cases.c.h" + #line 219 "Python/bytecodes.c" + #line 278 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 213 "Python/bytecodes.c" - #line 272 "Python/generated_cases.c.h" + #line 219 "Python/bytecodes.c" + #line 284 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); @@ -278,7 +290,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 223 "Python/bytecodes.c" + #line 229 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -288,7 +300,7 @@ } PyErr_SetRaisedException(NULL); } - #line 292 "Python/generated_cases.c.h" + #line 304 "Python/generated_cases.c.h" Py_DECREF(receiver); Py_DECREF(value); STACK_SHRINK(2); @@ -298,9 +310,9 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 236 "Python/bytecodes.c" + #line 242 "Python/bytecodes.c" Py_DECREF(receiver); - #line 304 "Python/generated_cases.c.h" + #line 316 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); @@ -309,7 +321,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 240 "Python/bytecodes.c" + #line 246 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -318,7 +330,7 @@ PyErr_SetRaisedException(NULL); } Py_DECREF(receiver); - #line 322 "Python/generated_cases.c.h" + #line 334 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); @@ -327,13 +339,13 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 251 "Python/bytecodes.c" + #line 257 "Python/bytecodes.c" res = PyNumber_Negative(value); - #line 333 "Python/generated_cases.c.h" + #line 345 "Python/generated_cases.c.h" Py_DECREF(value); - #line 253 "Python/bytecodes.c" + #line 259 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 337 "Python/generated_cases.c.h" + #line 349 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -341,11 +353,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 257 "Python/bytecodes.c" + #line 263 "Python/bytecodes.c" int err = PyObject_IsTrue(value); - #line 347 "Python/generated_cases.c.h" + #line 359 "Python/generated_cases.c.h" Py_DECREF(value); - #line 259 "Python/bytecodes.c" + #line 265 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -354,7 +366,7 @@ res = Py_False; } Py_INCREF(res); - #line 358 "Python/generated_cases.c.h" + #line 370 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -362,13 +374,13 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 270 "Python/bytecodes.c" + #line 276 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 368 "Python/generated_cases.c.h" + #line 380 "Python/generated_cases.c.h" Py_DECREF(value); - #line 272 "Python/bytecodes.c" + #line 278 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 372 "Python/generated_cases.c.h" + #line 384 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -377,7 +389,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 289 "Python/bytecodes.c" + #line 295 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -385,7 +397,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) goto pop_2_error; - #line 389 "Python/generated_cases.c.h" + #line 401 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -396,14 +408,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 299 "Python/bytecodes.c" + #line 305 "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 407 "Python/generated_cases.c.h" + #line 419 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -414,7 +426,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 308 "Python/bytecodes.c" + #line 314 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -422,7 +434,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sub == NULL) goto pop_2_error; - #line 426 "Python/generated_cases.c.h" + #line 438 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -433,13 +445,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 318 "Python/bytecodes.c" + #line 324 "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 443 "Python/generated_cases.c.h" + #line 455 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -450,7 +462,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 326 "Python/bytecodes.c" + #line 332 "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); @@ -458,7 +470,7 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 462 "Python/generated_cases.c.h" + #line 474 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -468,7 +480,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 342 "Python/bytecodes.c" + #line 348 "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]; @@ -495,7 +507,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - #line 499 "Python/generated_cases.c.h" + #line 511 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -504,14 +516,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 371 "Python/bytecodes.c" + #line 377 "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 515 "Python/generated_cases.c.h" + #line 527 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -522,7 +534,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 380 "Python/bytecodes.c" + #line 386 "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); @@ -530,7 +542,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sum == NULL) goto pop_2_error; - #line 534 "Python/generated_cases.c.h" + #line 546 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -543,7 +555,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 398 "Python/bytecodes.c" + #line 404 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -555,12 +567,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 559 "Python/generated_cases.c.h" + #line 571 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 410 "Python/bytecodes.c" + #line 416 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 564 "Python/generated_cases.c.h" + #line 576 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -572,7 +584,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 414 "Python/bytecodes.c" + #line 420 "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. @@ -585,7 +597,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 589 "Python/generated_cases.c.h" + #line 601 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -596,7 +608,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 429 "Python/bytecodes.c" + #line 435 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -609,7 +621,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 613 "Python/generated_cases.c.h" + #line 625 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -618,7 +630,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 444 "Python/bytecodes.c" + #line 450 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -632,7 +644,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 636 "Python/generated_cases.c.h" + #line 648 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -643,7 +655,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 460 "Python/bytecodes.c" + #line 466 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -657,7 +669,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 661 "Python/generated_cases.c.h" + #line 673 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -668,7 +680,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 476 "Python/bytecodes.c" + #line 482 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -676,14 +688,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 680 "Python/generated_cases.c.h" + #line 692 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 484 "Python/bytecodes.c" + #line 490 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 687 "Python/generated_cases.c.h" + #line 699 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -695,7 +707,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 491 "Python/bytecodes.c" + #line 497 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; @@ -717,15 +729,15 @@ JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 721 "Python/generated_cases.c.h" + #line 733 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 515 "Python/bytecodes.c" + #line 521 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 729 "Python/generated_cases.c.h" + #line 741 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -734,13 +746,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 520 "Python/bytecodes.c" + #line 526 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 740 "Python/generated_cases.c.h" + #line 752 "Python/generated_cases.c.h" Py_DECREF(v); - #line 522 "Python/bytecodes.c" + #line 528 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 744 "Python/generated_cases.c.h" + #line 756 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -753,7 +765,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 533 "Python/bytecodes.c" + #line 539 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -768,13 +780,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 772 "Python/generated_cases.c.h" + #line 784 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 548 "Python/bytecodes.c" + #line 554 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 778 "Python/generated_cases.c.h" + #line 790 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -784,7 +796,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 552 "Python/bytecodes.c" + #line 558 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -801,7 +813,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 805 "Python/generated_cases.c.h" + #line 817 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -811,13 +823,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 571 "Python/bytecodes.c" + #line 577 "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 821 "Python/generated_cases.c.h" + #line 833 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -826,15 +838,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 579 "Python/bytecodes.c" + #line 585 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 833 "Python/generated_cases.c.h" + #line 845 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 582 "Python/bytecodes.c" + #line 588 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 838 "Python/generated_cases.c.h" + #line 850 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -842,14 +854,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 586 "Python/bytecodes.c" + #line 592 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 849 "Python/generated_cases.c.h" + #line 861 "Python/generated_cases.c.h" Py_DECREF(value); - #line 589 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 853 "Python/generated_cases.c.h" + #line 865 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -858,15 +870,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 593 "Python/bytecodes.c" + #line 599 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 865 "Python/generated_cases.c.h" + #line 877 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 596 "Python/bytecodes.c" + #line 602 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 870 "Python/generated_cases.c.h" + #line 882 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -874,7 +886,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 600 "Python/bytecodes.c" + #line 606 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -892,12 +904,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 896 "Python/generated_cases.c.h" + #line 908 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 620 "Python/bytecodes.c" + #line 626 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -908,12 +920,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 912 "Python/generated_cases.c.h" + #line 924 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 633 "Python/bytecodes.c" + #line 639 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -926,12 +938,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 930 "Python/generated_cases.c.h" + #line 942 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 648 "Python/bytecodes.c" + #line 654 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -948,11 +960,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 952 "Python/generated_cases.c.h" + #line 964 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 667 "Python/bytecodes.c" + #line 673 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -966,11 +978,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 970 "Python/generated_cases.c.h" + #line 982 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 683 "Python/bytecodes.c" + #line 689 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -988,13 +1000,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 992 "Python/generated_cases.c.h" + #line 1004 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 703 "Python/bytecodes.c" + #line 709 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1007,16 +1019,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1011 "Python/generated_cases.c.h" + #line 1023 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 716 "Python/bytecodes.c" + #line 722 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1018 "Python/generated_cases.c.h" + #line 1030 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 721 "Python/bytecodes.c" + #line 727 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1029,7 +1041,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1033 "Python/generated_cases.c.h" + #line 1045 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1037,7 +1049,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 736 "Python/bytecodes.c" + #line 742 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1081,7 +1093,7 @@ } } - #line 1085 "Python/generated_cases.c.h" + #line 1097 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -1092,16 +1104,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 783 "Python/bytecodes.c" + #line 789 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1103 "Python/generated_cases.c.h" + #line 1115 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 790 "Python/bytecodes.c" + #line 796 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1119,7 +1131,7 @@ if (iter == NULL) goto pop_1_error; - #line 1123 "Python/generated_cases.c.h" + #line 1135 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1130,7 +1142,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 816 "Python/bytecodes.c" + #line 822 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1176,7 +1188,7 @@ } } Py_DECREF(v); - #line 1180 "Python/generated_cases.c.h" + #line 1192 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1185,7 +1197,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 864 "Python/bytecodes.c" + #line 870 "Python/bytecodes.c" PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); @@ -1200,12 +1212,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1204 "Python/generated_cases.c.h" + #line 1216 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 881 "Python/bytecodes.c" + #line 887 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1222,12 +1234,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1226 "Python/generated_cases.c.h" + #line 1238 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 900 "Python/bytecodes.c" + #line 906 "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. @@ -1243,15 +1255,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1247 "Python/generated_cases.c.h" + #line 1259 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 918 "Python/bytecodes.c" + #line 924 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1255 "Python/generated_cases.c.h" + #line 1267 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1259,7 +1271,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 923 "Python/bytecodes.c" + #line 929 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1277,26 +1289,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1281 "Python/generated_cases.c.h" + #line 1293 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 943 "Python/bytecodes.c" + #line 949 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1290 "Python/generated_cases.c.h" + #line 1302 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 946 "Python/bytecodes.c" + #line 952 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1300 "Python/generated_cases.c.h" + #line 1312 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1307,23 +1319,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 955 "Python/bytecodes.c" + #line 961 "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 1316 "Python/generated_cases.c.h" + #line 1328 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 960 "Python/bytecodes.c" + #line 966 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1327 "Python/generated_cases.c.h" + #line 1339 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1332,9 +1344,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 969 "Python/bytecodes.c" + #line 975 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1338 "Python/generated_cases.c.h" + #line 1350 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1342,7 +1354,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 973 "Python/bytecodes.c" + #line 979 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1364,7 +1376,7 @@ if (true) goto error; } } - #line 1368 "Python/generated_cases.c.h" + #line 1380 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1372,33 +1384,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 997 "Python/bytecodes.c" + #line 1003 "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 1383 "Python/generated_cases.c.h" + #line 1395 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1004 "Python/bytecodes.c" + #line 1010 "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 1392 "Python/generated_cases.c.h" + #line 1404 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1011 "Python/bytecodes.c" + #line 1017 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1396 "Python/generated_cases.c.h" + #line 1408 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1015 "Python/bytecodes.c" + #line 1021 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1415,7 +1427,7 @@ name); goto error; } - #line 1419 "Python/generated_cases.c.h" + #line 1431 "Python/generated_cases.c.h" DISPATCH(); } @@ -1423,7 +1435,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1041 "Python/bytecodes.c" + #line 1047 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1436,11 +1448,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1440 "Python/generated_cases.c.h" + #line 1452 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1054 "Python/bytecodes.c" + #line 1060 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1444 "Python/generated_cases.c.h" + #line 1456 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1450,14 +1462,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1058 "Python/bytecodes.c" + #line 1064 "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 1461 "Python/generated_cases.c.h" + #line 1473 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1468,7 +1480,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1068 "Python/bytecodes.c" + #line 1074 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1476,7 +1488,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1480 "Python/generated_cases.c.h" + #line 1492 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1487,7 +1499,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1079 "Python/bytecodes.c" + #line 1085 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1495,7 +1507,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1499 "Python/generated_cases.c.h" + #line 1511 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1505,15 +1517,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1090 "Python/bytecodes.c" + #line 1096 "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 1513 "Python/generated_cases.c.h" + #line 1525 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1094 "Python/bytecodes.c" + #line 1100 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1517 "Python/generated_cases.c.h" + #line 1529 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1524,7 +1536,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1105 "Python/bytecodes.c" + #line 1111 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1540,12 +1552,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1544 "Python/generated_cases.c.h" + #line 1556 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1121 "Python/bytecodes.c" + #line 1127 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1549 "Python/generated_cases.c.h" + #line 1561 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1553,34 +1565,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1125 "Python/bytecodes.c" + #line 1131 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1560 "Python/generated_cases.c.h" + #line 1572 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1128 "Python/bytecodes.c" + #line 1134 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1564 "Python/generated_cases.c.h" + #line 1576 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1132 "Python/bytecodes.c" + #line 1138 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1574 "Python/generated_cases.c.h" + #line 1586 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1135 "Python/bytecodes.c" + #line 1141 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1578 "Python/generated_cases.c.h" + #line 1590 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1139 "Python/bytecodes.c" + #line 1145 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1592,13 +1604,13 @@ } goto error; } - #line 1596 "Python/generated_cases.c.h" + #line 1608 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; - #line 1153 "Python/bytecodes.c" + #line 1159 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1657,7 +1669,7 @@ } } } - #line 1661 "Python/generated_cases.c.h" + #line 1673 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1668,7 +1680,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1220 "Python/bytecodes.c" + #line 1226 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1720,7 +1732,7 @@ } } null = NULL; - #line 1724 "Python/generated_cases.c.h" + #line 1736 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1734,7 +1746,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1274 "Python/bytecodes.c" + #line 1280 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1745,7 +1757,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1749 "Python/generated_cases.c.h" + #line 1761 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1760,7 +1772,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 1287 "Python/bytecodes.c" + #line 1293 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1775,7 +1787,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1779 "Python/generated_cases.c.h" + #line 1791 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1785,16 +1797,16 @@ } TARGET(DELETE_FAST) { - #line 1304 "Python/bytecodes.c" + #line 1310 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1793 "Python/generated_cases.c.h" + #line 1805 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1310 "Python/bytecodes.c" + #line 1316 "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); @@ -1803,12 +1815,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1807 "Python/generated_cases.c.h" + #line 1819 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1321 "Python/bytecodes.c" + #line 1327 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1819,13 +1831,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1823 "Python/generated_cases.c.h" + #line 1835 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1334 "Python/bytecodes.c" + #line 1340 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1857,7 +1869,7 @@ } Py_INCREF(value); } - #line 1861 "Python/generated_cases.c.h" + #line 1873 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1865,7 +1877,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1368 "Python/bytecodes.c" + #line 1374 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1873,7 +1885,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1877 "Python/generated_cases.c.h" + #line 1889 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1881,18 +1893,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1378 "Python/bytecodes.c" + #line 1384 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1890 "Python/generated_cases.c.h" + #line 1902 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1385 "Python/bytecodes.c" + #line 1391 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1903,22 +1915,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1907 "Python/generated_cases.c.h" + #line 1919 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1398 "Python/bytecodes.c" + #line 1404 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1916 "Python/generated_cases.c.h" + #line 1928 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1400 "Python/bytecodes.c" + #line 1406 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1922 "Python/generated_cases.c.h" + #line 1934 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1928,10 +1940,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1404 "Python/bytecodes.c" + #line 1410 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1935 "Python/generated_cases.c.h" + #line 1947 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1941,10 +1953,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1409 "Python/bytecodes.c" + #line 1415 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1948 "Python/generated_cases.c.h" + #line 1960 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1954,7 +1966,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1414 "Python/bytecodes.c" + #line 1420 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1965,13 +1977,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1969 "Python/generated_cases.c.h" + #line 1981 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1425 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1975 "Python/generated_cases.c.h" + #line 1987 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1980,13 +1992,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1432 "Python/bytecodes.c" + #line 1438 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1986 "Python/generated_cases.c.h" + #line 1998 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1434 "Python/bytecodes.c" + #line 1440 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1990 "Python/generated_cases.c.h" + #line 2002 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1994,7 +2006,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1438 "Python/bytecodes.c" + #line 1444 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2009,7 +2021,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2013 "Python/generated_cases.c.h" + #line 2025 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2019,7 +2031,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1455 "Python/bytecodes.c" + #line 1461 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2027,13 +2039,13 @@ if (map == NULL) goto error; - #line 2031 "Python/generated_cases.c.h" + #line 2043 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1463 "Python/bytecodes.c" + #line 1469 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2037 "Python/generated_cases.c.h" + #line 2049 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2041,7 +2053,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1467 "Python/bytecodes.c" + #line 1473 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2081,7 +2093,7 @@ Py_DECREF(ann_dict); } } - #line 2085 "Python/generated_cases.c.h" + #line 2097 "Python/generated_cases.c.h" DISPATCH(); } @@ -2089,7 +2101,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1509 "Python/bytecodes.c" + #line 1515 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2099,14 +2111,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2103 "Python/generated_cases.c.h" + #line 2115 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1519 "Python/bytecodes.c" + #line 1525 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2110 "Python/generated_cases.c.h" + #line 2122 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2114,7 +2126,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1523 "Python/bytecodes.c" + #line 1529 "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)) { @@ -2122,12 +2134,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2126 "Python/generated_cases.c.h" + #line 2138 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1531 "Python/bytecodes.c" + #line 1537 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2131 "Python/generated_cases.c.h" + #line 2143 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2135,17 +2147,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1537 "Python/bytecodes.c" + #line 1543 "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 2144 "Python/generated_cases.c.h" + #line 2156 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1542 "Python/bytecodes.c" + #line 1548 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2149 "Python/generated_cases.c.h" + #line 2161 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2155,13 +2167,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1549 "Python/bytecodes.c" + #line 1555 "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 2165 "Python/generated_cases.c.h" + #line 2177 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2175,7 +2187,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1563 "Python/bytecodes.c" + #line 1569 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2193,16 +2205,16 @@ // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); - #line 2197 "Python/generated_cases.c.h" + #line 2209 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1581 "Python/bytecodes.c" + #line 1587 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2206 "Python/generated_cases.c.h" + #line 2218 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2220,7 +2232,7 @@ uint32_t class_version = read_u32(&next_instr[1].cache); uint32_t self_type_version = read_u32(&next_instr[3].cache); PyObject *method = read_obj(&next_instr[5].cache); - #line 1588 "Python/bytecodes.c" + #line 1594 "Python/bytecodes.c" DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR); @@ -2231,7 +2243,7 @@ Py_INCREF(res2); Py_DECREF(global_super); Py_DECREF(class); - #line 2235 "Python/generated_cases.c.h" + #line 2247 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2245,7 +2257,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1615 "Python/bytecodes.c" + #line 1621 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2279,9 +2291,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2283 "Python/generated_cases.c.h" + #line 2295 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1649 "Python/bytecodes.c" + #line 1655 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2290,12 +2302,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2294 "Python/generated_cases.c.h" + #line 2306 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1658 "Python/bytecodes.c" + #line 1664 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2299 "Python/generated_cases.c.h" + #line 2311 "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; } @@ -2309,7 +2321,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1663 "Python/bytecodes.c" + #line 1669 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2322,7 +2334,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2326 "Python/generated_cases.c.h" + #line 2338 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2337,7 +2349,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1679 "Python/bytecodes.c" + #line 1685 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2350,7 +2362,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2354 "Python/generated_cases.c.h" + #line 2366 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2365,7 +2377,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1695 "Python/bytecodes.c" + #line 1701 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2392,7 +2404,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2396 "Python/generated_cases.c.h" + #line 2408 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2407,7 +2419,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1725 "Python/bytecodes.c" + #line 1731 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2417,7 +2429,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2421 "Python/generated_cases.c.h" + #line 2433 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2432,7 +2444,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1738 "Python/bytecodes.c" + #line 1744 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2444,7 +2456,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2448 "Python/generated_cases.c.h" + #line 2460 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2458,7 +2470,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 1753 "Python/bytecodes.c" + #line 1759 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2482,7 +2494,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2486 "Python/generated_cases.c.h" + #line 2498 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2490,7 +2502,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 1779 "Python/bytecodes.c" + #line 1785 "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); @@ -2516,7 +2528,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2520 "Python/generated_cases.c.h" + #line 2532 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2524,7 +2536,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 1807 "Python/bytecodes.c" + #line 1813 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2542,7 +2554,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2546 "Python/generated_cases.c.h" + #line 2558 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2553,7 +2565,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 1827 "Python/bytecodes.c" + #line 1833 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2592,7 +2604,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2596 "Python/generated_cases.c.h" + #line 2608 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2603,7 +2615,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 1868 "Python/bytecodes.c" + #line 1874 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2613,7 +2625,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2617 "Python/generated_cases.c.h" + #line 2629 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2625,7 +2637,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1887 "Python/bytecodes.c" + #line 1893 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2638,12 +2650,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2642 "Python/generated_cases.c.h" + #line 2654 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1900 "Python/bytecodes.c" + #line 1906 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2647 "Python/generated_cases.c.h" + #line 2659 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2654,7 +2666,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1904 "Python/bytecodes.c" + #line 1910 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2666,7 +2678,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2670 "Python/generated_cases.c.h" + #line 2682 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2677,7 +2689,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1919 "Python/bytecodes.c" + #line 1925 "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); @@ -2693,7 +2705,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2697 "Python/generated_cases.c.h" + #line 2709 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2704,7 +2716,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1938 "Python/bytecodes.c" + #line 1944 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2717,7 +2729,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2721 "Python/generated_cases.c.h" + #line 2733 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2728,14 +2740,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1953 "Python/bytecodes.c" + #line 1959 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2734 "Python/generated_cases.c.h" + #line 2746 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1955 "Python/bytecodes.c" + #line 1961 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2739 "Python/generated_cases.c.h" + #line 2751 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2745,15 +2757,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1959 "Python/bytecodes.c" + #line 1965 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2751 "Python/generated_cases.c.h" + #line 2763 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1961 "Python/bytecodes.c" + #line 1967 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2757 "Python/generated_cases.c.h" + #line 2769 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2764,12 +2776,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1966 "Python/bytecodes.c" + #line 1972 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2770 "Python/generated_cases.c.h" + #line 2782 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1968 "Python/bytecodes.c" + #line 1974 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2777,10 +2789,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2781 "Python/generated_cases.c.h" + #line 2793 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1976 "Python/bytecodes.c" + #line 1982 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2789,7 +2801,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2793 "Python/generated_cases.c.h" + #line 2805 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2799,21 +2811,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1987 "Python/bytecodes.c" + #line 1993 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2806 "Python/generated_cases.c.h" + #line 2818 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1990 "Python/bytecodes.c" + #line 1996 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2813 "Python/generated_cases.c.h" + #line 2825 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1995 "Python/bytecodes.c" + #line 2001 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2817 "Python/generated_cases.c.h" + #line 2829 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2822,15 +2834,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1999 "Python/bytecodes.c" + #line 2005 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2829 "Python/generated_cases.c.h" + #line 2841 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2002 "Python/bytecodes.c" + #line 2008 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2834 "Python/generated_cases.c.h" + #line 2846 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2839,29 +2851,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2006 "Python/bytecodes.c" + #line 2012 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2847 "Python/generated_cases.c.h" + #line 2859 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2012 "Python/bytecodes.c" + #line 2018 "Python/bytecodes.c" JUMPBY(oparg); - #line 2856 "Python/generated_cases.c.h" + #line 2868 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2016 "Python/bytecodes.c" + #line 2022 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2865 "Python/generated_cases.c.h" + #line 2877 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2869,7 +2881,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2022 "Python/bytecodes.c" + #line 2028 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2879,9 +2891,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2883 "Python/generated_cases.c.h" + #line 2895 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2032 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2889,14 +2901,14 @@ if (err < 0) goto pop_1_error; } } - #line 2893 "Python/generated_cases.c.h" + #line 2905 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2042 "Python/bytecodes.c" + #line 2048 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2906,9 +2918,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2910 "Python/generated_cases.c.h" + #line 2922 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2052 "Python/bytecodes.c" + #line 2058 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2916,67 +2928,67 @@ if (err < 0) goto pop_1_error; } } - #line 2920 "Python/generated_cases.c.h" + #line 2932 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2062 "Python/bytecodes.c" + #line 2068 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2929 "Python/generated_cases.c.h" + #line 2941 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2064 "Python/bytecodes.c" + #line 2070 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2937 "Python/generated_cases.c.h" + #line 2949 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2072 "Python/bytecodes.c" + #line 2078 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2950 "Python/generated_cases.c.h" + #line 2962 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2078 "Python/bytecodes.c" + #line 2084 "Python/bytecodes.c" } - #line 2954 "Python/generated_cases.c.h" + #line 2966 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2082 "Python/bytecodes.c" + #line 2088 "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 2967 "Python/generated_cases.c.h" + #line 2979 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2091 "Python/bytecodes.c" + #line 2097 "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 2980 "Python/generated_cases.c.h" + #line 2992 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2987,16 +2999,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2099 "Python/bytecodes.c" + #line 2105 "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 2996 "Python/generated_cases.c.h" + #line 3008 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2104 "Python/bytecodes.c" + #line 2110 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3004,7 +3016,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3008 "Python/generated_cases.c.h" + #line 3020 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3013,10 +3025,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2114 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3020 "Python/generated_cases.c.h" + #line 3032 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3026,10 +3038,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2120 "Python/bytecodes.c" + #line 2126 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3033 "Python/generated_cases.c.h" + #line 3045 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3040,11 +3052,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2126 "Python/bytecodes.c" + #line 2132 "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 3048 "Python/generated_cases.c.h" + #line 3060 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3053,14 +3065,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2132 "Python/bytecodes.c" + #line 2138 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3060 "Python/generated_cases.c.h" + #line 3072 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2135 "Python/bytecodes.c" + #line 2141 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3064 "Python/generated_cases.c.h" + #line 3076 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3068,7 +3080,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2139 "Python/bytecodes.c" + #line 2145 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3091,11 +3103,11 @@ if (iter == NULL) { goto error; } - #line 3095 "Python/generated_cases.c.h" + #line 3107 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2162 "Python/bytecodes.c" + #line 2168 "Python/bytecodes.c" } - #line 3099 "Python/generated_cases.c.h" + #line 3111 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3106,7 +3118,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2181 "Python/bytecodes.c" + #line 2187 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3137,7 +3149,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3141 "Python/generated_cases.c.h" + #line 3153 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3145,7 +3157,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2214 "Python/bytecodes.c" + #line 2220 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3171,14 +3183,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3175 "Python/generated_cases.c.h" + #line 3187 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2242 "Python/bytecodes.c" + #line 2248 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3198,7 +3210,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3202 "Python/generated_cases.c.h" + #line 3214 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3208,7 +3220,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2264 "Python/bytecodes.c" + #line 2270 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3228,7 +3240,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3232 "Python/generated_cases.c.h" + #line 3244 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3238,7 +3250,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2286 "Python/bytecodes.c" + #line 2292 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3256,7 +3268,7 @@ if (next == NULL) { goto error; } - #line 3260 "Python/generated_cases.c.h" + #line 3272 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3265,7 +3277,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2306 "Python/bytecodes.c" + #line 2312 "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); @@ -3280,14 +3292,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3284 "Python/generated_cases.c.h" + #line 3296 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2323 "Python/bytecodes.c" + #line 2329 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3310,16 +3322,16 @@ Py_DECREF(enter); goto error; } - #line 3314 "Python/generated_cases.c.h" + #line 3326 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2346 "Python/bytecodes.c" + #line 2352 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3323 "Python/generated_cases.c.h" + #line 3335 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3331,7 +3343,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2356 "Python/bytecodes.c" + #line 2362 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3357,16 +3369,16 @@ Py_DECREF(enter); goto error; } - #line 3361 "Python/generated_cases.c.h" + #line 3373 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2382 "Python/bytecodes.c" + #line 2388 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3370 "Python/generated_cases.c.h" + #line 3382 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3378,7 +3390,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2391 "Python/bytecodes.c" + #line 2397 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3399,7 +3411,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3403 "Python/generated_cases.c.h" + #line 3415 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3408,7 +3420,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2414 "Python/bytecodes.c" + #line 2420 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3418,7 +3430,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3422 "Python/generated_cases.c.h" + #line 3434 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3432,7 +3444,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 2426 "Python/bytecodes.c" + #line 2432 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3449,7 +3461,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3453 "Python/generated_cases.c.h" + #line 3465 "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; } @@ -3463,7 +3475,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2445 "Python/bytecodes.c" + #line 2451 "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); @@ -3473,7 +3485,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3477 "Python/generated_cases.c.h" + #line 3489 "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; } @@ -3487,7 +3499,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2457 "Python/bytecodes.c" + #line 2463 "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; @@ -3501,7 +3513,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3505 "Python/generated_cases.c.h" + #line 3517 "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; } @@ -3510,16 +3522,16 @@ } TARGET(KW_NAMES) { - #line 2473 "Python/bytecodes.c" + #line 2479 "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 3518 "Python/generated_cases.c.h" + #line 3530 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2479 "Python/bytecodes.c" + #line 2485 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3532,7 +3544,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3536 "Python/generated_cases.c.h" + #line 3548 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3542,7 +3554,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2524 "Python/bytecodes.c" + #line 2530 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3624,7 +3636,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3628 "Python/generated_cases.c.h" + #line 3640 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3636,7 +3648,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2612 "Python/bytecodes.c" + #line 2618 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3646,7 +3658,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3650 "Python/generated_cases.c.h" + #line 3662 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3655,7 +3667,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2624 "Python/bytecodes.c" + #line 2630 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3681,7 +3693,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3685 "Python/generated_cases.c.h" + #line 3697 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3689,7 +3701,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2652 "Python/bytecodes.c" + #line 2658 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3725,7 +3737,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3729 "Python/generated_cases.c.h" + #line 3741 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3733,7 +3745,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2690 "Python/bytecodes.c" + #line 2696 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3743,7 +3755,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3747 "Python/generated_cases.c.h" + #line 3759 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3756,7 +3768,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2702 "Python/bytecodes.c" + #line 2708 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3767,7 +3779,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3771 "Python/generated_cases.c.h" + #line 3783 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3781,7 +3793,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2716 "Python/bytecodes.c" + #line 2722 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3792,7 +3804,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3796 "Python/generated_cases.c.h" + #line 3808 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3806,7 +3818,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2730 "Python/bytecodes.c" + #line 2736 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3828,7 +3840,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3832 "Python/generated_cases.c.h" + #line 3844 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3842,7 +3854,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2755 "Python/bytecodes.c" + #line 2761 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3870,7 +3882,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3874 "Python/generated_cases.c.h" + #line 3886 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3884,7 +3896,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2786 "Python/bytecodes.c" + #line 2792 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3916,7 +3928,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3920 "Python/generated_cases.c.h" + #line 3932 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3930,7 +3942,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2821 "Python/bytecodes.c" + #line 2827 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -3962,7 +3974,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3966 "Python/generated_cases.c.h" + #line 3978 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3976,7 +3988,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2856 "Python/bytecodes.c" + #line 2862 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4001,7 +4013,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4005 "Python/generated_cases.c.h" + #line 4017 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4014,7 +4026,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2883 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4041,7 +4053,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4045 "Python/generated_cases.c.h" + #line 4057 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4053,7 +4065,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2913 "Python/bytecodes.c" + #line 2919 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4071,14 +4083,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4075 "Python/generated_cases.c.h" + #line 4087 "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 2933 "Python/bytecodes.c" + #line 2939 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4109,7 +4121,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4113 "Python/generated_cases.c.h" + #line 4125 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4122,7 +4134,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2967 "Python/bytecodes.c" + #line 2973 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4151,7 +4163,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4155 "Python/generated_cases.c.h" + #line 4167 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4164,7 +4176,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2999 "Python/bytecodes.c" + #line 3005 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4193,7 +4205,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4197 "Python/generated_cases.c.h" + #line 4209 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4206,7 +4218,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3031 "Python/bytecodes.c" + #line 3037 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4234,7 +4246,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4238 "Python/generated_cases.c.h" + #line 4250 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4244,9 +4256,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3062 "Python/bytecodes.c" + #line 3068 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4250 "Python/generated_cases.c.h" + #line 4262 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4255,7 +4267,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3066 "Python/bytecodes.c" + #line 3072 "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)); @@ -4317,14 +4329,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4321 "Python/generated_cases.c.h" + #line 4333 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3128 "Python/bytecodes.c" + #line 3134 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4328 "Python/generated_cases.c.h" + #line 4340 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4339,7 +4351,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 3138 "Python/bytecodes.c" + #line 3144 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4368,14 +4380,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4372 "Python/generated_cases.c.h" + #line 4384 "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 3169 "Python/bytecodes.c" + #line 3175 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4396,7 +4408,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4400 "Python/generated_cases.c.h" + #line 4412 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4404,15 +4416,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3192 "Python/bytecodes.c" + #line 3198 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4410 "Python/generated_cases.c.h" + #line 4422 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3194 "Python/bytecodes.c" + #line 3200 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4416 "Python/generated_cases.c.h" + #line 4428 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4423,7 +4435,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 3198 "Python/bytecodes.c" + #line 3204 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4458,7 +4470,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 4462 "Python/generated_cases.c.h" + #line 4474 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4467,10 +4479,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3235 "Python/bytecodes.c" + #line 3241 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4474 "Python/generated_cases.c.h" + #line 4486 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4482,7 +4494,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3240 "Python/bytecodes.c" + #line 3246 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4497,12 +4509,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4501 "Python/generated_cases.c.h" + #line 4513 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3255 "Python/bytecodes.c" + #line 3261 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4506 "Python/generated_cases.c.h" + #line 4518 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4512,16 +4524,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3260 "Python/bytecodes.c" + #line 3266 "Python/bytecodes.c" assert(oparg >= 2); - #line 4518 "Python/generated_cases.c.h" + #line 4530 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_LINE) { - #line 3264 "Python/bytecodes.c" + #line 3270 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _PyFrame_SetStackPointer(frame, stack_pointer); int original_opcode = _Py_call_instrumentation_line( @@ -4541,11 +4553,11 @@ } opcode = original_opcode; DISPATCH_GOTO(); - #line 4545 "Python/generated_cases.c.h" + #line 4557 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3286 "Python/bytecodes.c" + #line 3292 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4557,26 +4569,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4561 "Python/generated_cases.c.h" + #line 4573 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3300 "Python/bytecodes.c" + #line 3306 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4567 "Python/generated_cases.c.h" + #line 4579 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3304 "Python/bytecodes.c" + #line 3310 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4574 "Python/generated_cases.c.h" + #line 4586 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3309 "Python/bytecodes.c" + #line 3315 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4585,12 +4597,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4589 "Python/generated_cases.c.h" + #line 4601 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3320 "Python/bytecodes.c" + #line 3326 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4599,12 +4611,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4603 "Python/generated_cases.c.h" + #line 4615 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3331 "Python/bytecodes.c" + #line 3337 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4617,12 +4629,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4621 "Python/generated_cases.c.h" + #line 4633 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3346 "Python/bytecodes.c" + #line 3352 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4635,30 +4647,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4639 "Python/generated_cases.c.h" + #line 4651 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3361 "Python/bytecodes.c" + #line 3367 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4650 "Python/generated_cases.c.h" + #line 4662 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3369 "Python/bytecodes.c" + #line 3375 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4657 "Python/generated_cases.c.h" + #line 4669 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3374 "Python/bytecodes.c" + #line 3380 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4664 "Python/generated_cases.c.h" + #line 4676 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 77f0ae0c1a4c..c1a6ed4c18ab 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -21,6 +21,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case LOAD_FAST: return 0; + case LOAD_FAST_AND_CLEAR: + return 0; case LOAD_CONST: return 0; case STORE_FAST: @@ -409,6 +411,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case LOAD_FAST: return 1; + case LOAD_FAST_AND_CLEAR: + return 1; case LOAD_CONST: return 1; case STORE_FAST: @@ -795,6 +799,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, [LOAD_FAST] = { true, INSTR_FMT_IB }, + [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB }, [LOAD_CONST] = { true, INSTR_FMT_IB }, [STORE_FAST] = { true, INSTR_FMT_IB }, [LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 042cee222f70..00f15ff98da4 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_LOAD_SUPER_ATTR, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_LOAD_FAST_AND_CLEAR, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,24 +152,24 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, diff --git a/Python/symtable.c b/Python/symtable.c index df7473943f3f..6e74d764245a 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -103,6 +103,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block, ste->ste_comprehension = NoComprehension; ste->ste_returns_value = 0; ste->ste_needs_class_closure = 0; + ste->ste_comp_inlined = 0; ste->ste_comp_iter_target = 0; ste->ste_comp_iter_expr = 0; @@ -558,6 +559,67 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, return 1; } +static int +is_free_in_any_child(PySTEntryObject *entry, PyObject *key) +{ + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(entry->ste_children); i++) { + PySTEntryObject *child_ste = (PySTEntryObject *)PyList_GET_ITEM( + entry->ste_children, i); + long scope = _PyST_GetScope(child_ste, key); + if (scope == FREE) { + return 1; + } + } + return 0; +} + +static int +inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, + PyObject *scopes, PyObject *comp_free) +{ + PyObject *k, *v; + Py_ssize_t pos = 0; + while (PyDict_Next(comp->ste_symbols, &pos, &k, &v)) { + // skip comprehension parameter + long comp_flags = PyLong_AS_LONG(v); + if (comp_flags & DEF_PARAM) { + assert(_PyUnicode_EqualToASCIIString(k, ".0")); + continue; + } + int scope = (comp_flags >> SCOPE_OFFSET) & SCOPE_MASK; + int only_flags = comp_flags & ((1 << SCOPE_OFFSET) - 1); + PyObject *existing = PyDict_GetItemWithError(ste->ste_symbols, k); + if (existing == NULL && PyErr_Occurred()) { + return 0; + } + if (!existing) { + // name does not exist in scope, copy from comprehension + assert(scope != FREE || PySet_Contains(comp_free, k) == 1); + PyObject *v_flags = PyLong_FromLong(only_flags); + if (v_flags == NULL) { + return 0; + } + int ok = PyDict_SetItem(ste->ste_symbols, k, v_flags); + Py_DECREF(v_flags); + if (ok < 0) { + return 0; + } + SET_SCOPE(scopes, k, scope); + } + else { + // free vars in comprehension that are locals in outer scope can + // now simply be locals, unless they are free in comp children + if ((PyLong_AsLong(existing) & DEF_BOUND) && + !is_free_in_any_child(comp, k)) { + if (PySet_Discard(comp_free, k) < 0) { + return 0; + } + } + } + } + return 1; +} + #undef SET_SCOPE /* If a name is defined in free and also in locals, then this block @@ -727,17 +789,17 @@ update_symbols(PyObject *symbols, PyObject *scopes, static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, - PyObject *global, PyObject* child_free); + PyObject *global, PyObject **child_free); static int analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, PyObject *global) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; - PyObject *newglobal = NULL, *newfree = NULL, *allfree = NULL; + PyObject *newglobal = NULL, *newfree = NULL; PyObject *temp; - int i, success = 0; - Py_ssize_t pos = 0; + int success = 0; + Py_ssize_t i, pos = 0; local = PySet_New(NULL); /* collect new names bound in block */ if (!local) @@ -746,8 +808,8 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, if (!scopes) goto error; - /* Allocate new global and bound variable dictionaries. These - dictionaries hold the names visible in nested blocks. For + /* Allocate new global, bound and free variable sets. These + sets hold the names visible in nested blocks. For ClassBlocks, the bound and global names are initialized before analyzing names, because class bindings aren't visible in methods. For other blocks, they are initialized @@ -826,28 +888,55 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, newbound, newglobal now contain the names visible in nested blocks. The free variables in the children will - be collected in allfree. + be added to newfree. */ - allfree = PySet_New(NULL); - if (!allfree) - goto error; for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) { + PyObject *child_free = NULL; PyObject *c = PyList_GET_ITEM(ste->ste_children, i); PySTEntryObject* entry; assert(c && PySTEntry_Check(c)); entry = (PySTEntryObject*)c; + + // we inline all non-generator-expression comprehensions + int inline_comp = + entry->ste_comprehension && + !entry->ste_generator; + if (!analyze_child_block(entry, newbound, newfree, newglobal, - allfree)) + &child_free)) + { goto error; + } + if (inline_comp) { + if (!inline_comprehension(ste, entry, scopes, child_free)) { + Py_DECREF(child_free); + goto error; + } + entry->ste_comp_inlined = 1; + } + temp = PyNumber_InPlaceOr(newfree, child_free); + Py_DECREF(child_free); + if (!temp) + goto error; + Py_DECREF(temp); /* Check if any children have free variables */ if (entry->ste_free || entry->ste_child_free) ste->ste_child_free = 1; } - temp = PyNumber_InPlaceOr(newfree, allfree); - if (!temp) - goto error; - Py_DECREF(temp); + /* Splice children of inlined comprehensions into our children list */ + for (i = PyList_GET_SIZE(ste->ste_children) - 1; i >= 0; --i) { + PyObject* c = PyList_GET_ITEM(ste->ste_children, i); + PySTEntryObject* entry; + assert(c && PySTEntry_Check(c)); + entry = (PySTEntryObject*)c; + if (entry->ste_comp_inlined && + PyList_SetSlice(ste->ste_children, i, i + 1, + entry->ste_children) < 0) + { + goto error; + } + } /* Check if any local variables must be converted to cell variables */ if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree)) @@ -870,7 +959,6 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, Py_XDECREF(newbound); Py_XDECREF(newglobal); Py_XDECREF(newfree); - Py_XDECREF(allfree); if (!success) assert(PyErr_Occurred()); return success; @@ -878,16 +966,15 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, - PyObject *global, PyObject* child_free) + PyObject *global, PyObject** child_free) { PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL; - PyObject *temp; - /* Copy the bound and global dictionaries. + /* Copy the bound/global/free sets. - These dictionaries are used by all blocks enclosed by the + These sets are used by all blocks enclosed by the current block. The analyze_block() call modifies these - dictionaries. + sets. */ temp_bound = PySet_New(bound); @@ -902,12 +989,8 @@ analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, if (!analyze_block(entry, temp_bound, temp_free, temp_global)) goto error; - temp = PyNumber_InPlaceOr(child_free, temp_free); - if (!temp) - goto error; - Py_DECREF(temp); + *child_free = temp_free; Py_DECREF(temp_bound); - Py_DECREF(temp_free); Py_DECREF(temp_global); return 1; error: @@ -2216,4 +2299,3 @@ _Py_Mangle(PyObject *privateobj, PyObject *ident) assert(_PyUnicode_CheckConsistency(result, 1)); return result; } - From webhook-mailer at python.org Tue May 9 13:09:24 2023 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 09 May 2023 17:09:24 -0000 Subject: [Python-checkins] gh-97696 Add documentation for get_coro() behavior with eager tasks (#104304) Message-ID: <mailman.272.1683652165.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2866e030f01dc3ff08de32857fa77d52468b676b commit: 2866e030f01dc3ff08de32857fa77d52468b676b branch: main author: Jacob Bower <1978924+jbower-fb at users.noreply.github.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-09T10:09:16-07:00 summary: gh-97696 Add documentation for get_coro() behavior with eager tasks (#104304) files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index b2d7362a9de2..fe8d02815040 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -527,6 +527,8 @@ Running Tasks Concurrently and there is no running event loop. +.. _eager-task-factory: + Eager Task Factory ================== @@ -1174,8 +1176,17 @@ Task Object Return the coroutine object wrapped by the :class:`Task`. + .. note:: + + This will return ``None`` for Tasks which have already + completed eagerly. See the :ref:`Eager Task Factory <eager-task-factory>`. + .. versionadded:: 3.8 + .. versionchanged:: 3.12 + + Newly added eager task execution means result may be ``None``. + .. method:: get_context() Return the :class:`contextvars.Context` object From webhook-mailer at python.org Tue May 9 15:18:48 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 09 May 2023 19:18:48 -0000 Subject: [Python-checkins] gh-104328: Fix typo in ``typing.Generic`` multiple inheritance error message (#104335) Message-ID: <mailman.273.1683659929.13550.python-checkins@python.org> https://github.com/python/cpython/commit/01c321ca34d99f35f174768c6f8c500801d4ef4c commit: 01c321ca34d99f35f174768c6f8c500801d4ef4c branch: main author: Kirill Podoprigora <kirill.bast9 at mail.ru> committer: carljm <carl at oddbird.net> date: 2023-05-09T13:18:15-06:00 summary: gh-104328: Fix typo in ``typing.Generic`` multiple inheritance error message (#104335) files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 0dacdd9031a7..4f8cba88632d 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1896,7 +1896,7 @@ def __init_subclass__(cls, *args, **kwargs): base.__origin__ is Generic): if gvars is not None: raise TypeError( - "Cannot inherit from Generic[...] multiple types.") + "Cannot inherit from Generic[...] multiple times.") gvars = base.__parameters__ if gvars is not None: tvarset = set(tvars) From webhook-mailer at python.org Tue May 9 15:43:05 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 09 May 2023 19:43:05 -0000 Subject: [Python-checkins] [3.11] gh-104328: Fix typo in ``typing.Generic`` multiple inheritance error message (GH-104335) (#104338) Message-ID: <mailman.274.1683661386.13550.python-checkins@python.org> https://github.com/python/cpython/commit/663b32199e709a83b2eebc3eeeb602f0af949bee commit: 663b32199e709a83b2eebc3eeeb602f0af949bee branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-09T19:42:57Z summary: [3.11] gh-104328: Fix typo in ``typing.Generic`` multiple inheritance error message (GH-104335) (#104338) gh-104328: Fix typo in ``typing.Generic`` multiple inheritance error message (GH-104335) (cherry picked from commit 01c321ca34d99f35f174768c6f8c500801d4ef4c) Co-authored-by: Kirill Podoprigora <kirill.bast9 at mail.ru> files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 2db354017a8b..921542f49c32 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1860,7 +1860,7 @@ def __init_subclass__(cls, *args, **kwargs): base.__origin__ is Generic): if gvars is not None: raise TypeError( - "Cannot inherit from Generic[...] multiple types.") + "Cannot inherit from Generic[...] multiple times.") gvars = base.__parameters__ if gvars is not None: tvarset = set(tvars) From webhook-mailer at python.org Tue May 9 15:57:26 2023 From: webhook-mailer at python.org (Mariatta) Date: Tue, 09 May 2023 19:57:26 -0000 Subject: [Python-checkins] gh-102327: Extend docs for "url" and "headers" parameters to HTTPConnection.request() Message-ID: <mailman.275.1683662247.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7ba6288feb961fcd60a29415c6371d2d3eb80bec commit: 7ba6288feb961fcd60a29415c6371d2d3eb80bec branch: main author: David Foster <david at dafoster.net> committer: Mariatta <Mariatta at users.noreply.github.com> date: 2023-05-09T12:57:17-07:00 summary: gh-102327: Extend docs for "url" and "headers" parameters to HTTPConnection.request() Added example on how to use the HTTPConnection object for making GET request. Original issue: https://github.com/python/cpython/issues/102327 --------- Co-authored-by: ?ric <earaujo at caravan.coop> files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index eb8c1e198e2b..bf1f2e392078 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -264,7 +264,10 @@ HTTPConnection Objects encode_chunked=False) This will send a request to the server using the HTTP request - method *method* and the selector *url*. + method *method* and the request URI *url*. The provided *url* must be + an absolute path to conform with :rfc:`RFC 2616 ?5.1.2 <2616#section-5.1.2>` + (unless connecting to an HTTP proxy server or using the ``OPTIONS`` or + ``CONNECT`` methods). If *body* is specified, the specified data is sent after the headers are finished. It may be a :class:`str`, a :term:`bytes-like object`, an @@ -279,7 +282,10 @@ HTTPConnection Objects iterable are sent as is until the iterable is exhausted. The *headers* argument should be a mapping of extra HTTP headers to send - with the request. + with the request. A :rfc:`Host header <2616#section-14.23>` + must be provided to conform with :rfc:`RFC 2616 ?5.1.2 <2616#section-5.1.2>` + (unless connecting to an HTTP proxy server or using the ``OPTIONS`` or + ``CONNECT`` methods). If *headers* contains neither Content-Length nor Transfer-Encoding, but there is a request body, one of those @@ -298,6 +304,16 @@ HTTPConnection Objects HTTPConnection object assumes that all encoding is handled by the calling code. If it is ``True``, the body will be chunk-encoded. + For example, to perform a ``GET`` request to ``https://docs.python.org/3/``:: + + >>> import http.client + >>> host = "docs.python.org" + >>> conn = http.client.HTTPSConnection(host) + >>> conn.request("GET", "/3/", headers={"Host": host}) + >>> response = conn.getresponse() + >>> print(response.status, response.reason) + 200 OK + .. note:: Chunked transfer encoding has been added to the HTTP protocol version 1.1. Unless the HTTP server is known to handle HTTP 1.1, From webhook-mailer at python.org Tue May 9 16:01:05 2023 From: webhook-mailer at python.org (Mariatta) Date: Tue, 09 May 2023 20:01:05 -0000 Subject: [Python-checkins] [3.11] gh-102327: Extend docs for "url" and "headers" parameters to HTTPConnection.request() Message-ID: <mailman.276.1683662466.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fffdbf483140c1abfd2bba2da363af6fba0987b1 commit: fffdbf483140c1abfd2bba2da363af6fba0987b1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Mariatta <Mariatta at users.noreply.github.com> date: 2023-05-09T20:00:58Z summary: [3.11] gh-102327: Extend docs for "url" and "headers" parameters to HTTPConnection.request() gh-102327: Extend docs for "url" and "headers" parameters to HTTPConnection.request() Added example on how to use the HTTPConnection object for making GET request. Original issue: https://github.com/python/cpython/issues/102327 --------- (cherry picked from commit 7ba6288feb961fcd60a29415c6371d2d3eb80bec) Co-authored-by: David Foster <david at dafoster.net> Co-authored-by: ?ric <earaujo at caravan.coop> files: M Doc/library/http.client.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 9aeb07fade82..df99ab99826e 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -262,7 +262,10 @@ HTTPConnection Objects encode_chunked=False) This will send a request to the server using the HTTP request - method *method* and the selector *url*. + method *method* and the request URI *url*. The provided *url* must be + an absolute path to conform with :rfc:`RFC 2616 ?5.1.2 <2616#section-5.1.2>` + (unless connecting to an HTTP proxy server or using the ``OPTIONS`` or + ``CONNECT`` methods). If *body* is specified, the specified data is sent after the headers are finished. It may be a :class:`str`, a :term:`bytes-like object`, an @@ -277,7 +280,10 @@ HTTPConnection Objects iterable are sent as is until the iterable is exhausted. The *headers* argument should be a mapping of extra HTTP headers to send - with the request. + with the request. A :rfc:`Host header <2616#section-14.23>` + must be provided to conform with :rfc:`RFC 2616 ?5.1.2 <2616#section-5.1.2>` + (unless connecting to an HTTP proxy server or using the ``OPTIONS`` or + ``CONNECT`` methods). If *headers* contains neither Content-Length nor Transfer-Encoding, but there is a request body, one of those @@ -296,6 +302,16 @@ HTTPConnection Objects HTTPConnection object assumes that all encoding is handled by the calling code. If it is ``True``, the body will be chunk-encoded. + For example, to perform a ``GET`` request to ``https://docs.python.org/3/``:: + + >>> import http.client + >>> host = "docs.python.org" + >>> conn = http.client.HTTPSConnection(host) + >>> conn.request("GET", "/3/", headers={"Host": host}) + >>> response = conn.getresponse() + >>> print(response.status, response.reason) + 200 OK + .. note:: Chunked transfer encoding has been added to the HTTP protocol version 1.1. Unless the HTTP server is known to handle HTTP 1.1, From webhook-mailer at python.org Tue May 9 17:16:36 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 09 May 2023 21:16:36 -0000 Subject: [Python-checkins] gh-90953: Don't use deprecated AST nodes in clinic.py (#104322) Message-ID: <mailman.277.1683666997.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fe694a6db620062f467469bd2bb987315d72fd62 commit: fe694a6db620062f467469bd2bb987315d72fd62 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-09T22:16:22+01:00 summary: gh-90953: Don't use deprecated AST nodes in clinic.py (#104322) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index a6f330d1502d..2ae8a02aa6d2 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4701,10 +4701,8 @@ def bad_node(self, node): c_default = "NULL" elif (isinstance(expr, ast.BinOp) or (isinstance(expr, ast.UnaryOp) and - not (isinstance(expr.operand, ast.Num) or - (hasattr(ast, 'Constant') and - isinstance(expr.operand, ast.Constant) and - type(expr.operand.value) in (int, float, complex))) + not (isinstance(expr.operand, ast.Constant) and + type(expr.operand.value) in {int, float, complex}) )): c_default = kwargs.get("c_default") if not (isinstance(c_default, str) and c_default): @@ -4806,14 +4804,10 @@ def bad_node(self, node): self.function.parameters[key] = p def parse_converter(self, annotation): - if (hasattr(ast, 'Constant') and - isinstance(annotation, ast.Constant) and + if (isinstance(annotation, ast.Constant) and type(annotation.value) is str): return annotation.value, True, {} - if isinstance(annotation, ast.Str): - return annotation.s, True, {} - if isinstance(annotation, ast.Name): return annotation.id, False, {} From webhook-mailer at python.org Tue May 9 18:22:13 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 09 May 2023 22:22:13 -0000 Subject: [Python-checkins] [3.11] gh-48241: Clarify URL needs to be encoded when provided to urlopen and Request (GH-103855) (#103891) Message-ID: <mailman.278.1683670934.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2fa14d47af1a2f4a7edbec10c9cf6f21a695ffda commit: 2fa14d47af1a2f4a7edbec10c9cf6f21a695ffda branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-10T00:22:06+02:00 summary: [3.11] gh-48241: Clarify URL needs to be encoded when provided to urlopen and Request (GH-103855) (#103891) (cherry picked from commit 44010d0f1203134cd8f885ca574caaef373e80f6) Co-authored-by: Michael Blahay <mblahay at users.noreply.github.com> Co-authored-by: ?ukasz Langa <lukasz at langa.pl> files: A Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst M Doc/library/urllib.request.rst diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 64cc9c388ec3..1b05458280d8 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -28,8 +28,8 @@ The :mod:`urllib.request` module defines the following functions: .. function:: urlopen(url, data=None[, timeout], *, cafile=None, capath=None, cadefault=False, context=None) - Open the URL *url*, which can be either a string or a - :class:`Request` object. + Open *url*, which can be either a string containing a valid, properly + encoded URL, or a :class:`Request` object. *data* must be an object specifying additional data to be sent to the server, or ``None`` if no such data is needed. See :class:`Request` @@ -192,7 +192,7 @@ The following classes are provided: This class is an abstraction of a URL request. - *url* should be a string containing a valid URL. + *url* should be a string containing a valid, properly encoded URL. *data* must be an object specifying additional data to send to the server, or ``None`` if no such data is needed. Currently HTTP diff --git a/Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst b/Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst new file mode 100644 index 000000000000..619505cf6ee5 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst @@ -0,0 +1 @@ +Clarifying documentation about the url parameter to urllib.request.urlopen and urllib.request.Requst needing to be encoded properly. From webhook-mailer at python.org Tue May 9 19:09:16 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 09 May 2023 23:09:16 -0000 Subject: [Python-checkins] gh-101819: Refactor _io in preparation for module isolation (#104334) Message-ID: <mailman.279.1683673757.13550.python-checkins@python.org> https://github.com/python/cpython/commit/235b82721dbbe2bc5bf1f45a74e22b7185e5783e commit: 235b82721dbbe2bc5bf1f45a74e22b7185e5783e branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-09T23:09:03Z summary: gh-101819: Refactor _io in preparation for module isolation (#104334) - Replace query with parameter in bufferediobase_unsupported() - Replace query with parameter in iobase_unsupported() - Hide delegate: Add method wrapper for _PyIOBase_check_seekable - Hide delegate: Add method wraper for _PyIOBase_check_readable - Hide delegate: Add method wraper for _PyIOBase_check_writable - Replace query with parameter in _PyIOBase_check_seekable() - Replace query with parameter in _PyIOBase_check_readable() - Replace query with parameter in _PyIOBase_check_writable() files: M Modules/_io/_iomodule.h M Modules/_io/bufferedio.c M Modules/_io/iobase.c diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 1bf301c9cf0a..b3873ddf7e08 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -34,9 +34,13 @@ extern PyType_Spec winconsoleio_spec; * with args=NULL, and return a new reference. * BUT when args=Py_True is passed, they return a borrowed reference. */ -extern PyObject* _PyIOBase_check_readable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_writable(PyObject *self, PyObject *args); -extern PyObject* _PyIOBase_check_seekable(PyObject *self, PyObject *args); +typedef struct _io_state _PyIO_State; // Forward decl. +extern PyObject* _PyIOBase_check_readable(_PyIO_State *state, + PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_writable(_PyIO_State *state, + PyObject *self, PyObject *args); +extern PyObject* _PyIOBase_check_seekable(_PyIO_State *state, + PyObject *self, PyObject *args); extern PyObject* _PyIOBase_check_closed(PyObject *self, PyObject *args); /* Helper for finalization. @@ -140,7 +144,7 @@ extern Py_off_t PyNumber_AsOff_t(PyObject *item, PyObject *err); extern PyModuleDef _PyIO_Module; -typedef struct { +struct _io_state { int initialized; PyObject *unsupported_operation; @@ -161,7 +165,7 @@ typedef struct { #ifdef MS_WINDOWS PyTypeObject *PyWindowsConsoleIO_Type; #endif -} _PyIO_State; +}; #define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) #define IO_STATE() _PyIO_get_module_state() diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 723d16b47fef..172fafe6db8a 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -106,11 +106,9 @@ _io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer) } static PyObject * -bufferediobase_unsupported(const char *message) +bufferediobase_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -127,7 +125,8 @@ static PyObject * _io__BufferedIOBase_detach_impl(PyObject *self) /*[clinic end generated code: output=754977c8d10ed88c input=822427fb58fe4169]*/ { - return bufferediobase_unsupported("detach"); + _PyIO_State *state = IO_STATE(); + return bufferediobase_unsupported(state, "detach"); } PyDoc_STRVAR(bufferediobase_read_doc, @@ -151,7 +150,8 @@ PyDoc_STRVAR(bufferediobase_read_doc, static PyObject * bufferediobase_read(PyObject *self, PyObject *args) { - return bufferediobase_unsupported("read"); + _PyIO_State *state = IO_STATE(); + return bufferediobase_unsupported(state, "read"); } PyDoc_STRVAR(bufferediobase_read1_doc, @@ -164,7 +164,8 @@ PyDoc_STRVAR(bufferediobase_read1_doc, static PyObject * bufferediobase_read1(PyObject *self, PyObject *args) { - return bufferediobase_unsupported("read1"); + _PyIO_State *state = IO_STATE(); + return bufferediobase_unsupported(state, "read1"); } PyDoc_STRVAR(bufferediobase_write_doc, @@ -179,7 +180,8 @@ PyDoc_STRVAR(bufferediobase_write_doc, static PyObject * bufferediobase_write(PyObject *self, PyObject *args) { - return bufferediobase_unsupported("write"); + _PyIO_State *state = IO_STATE(); + return bufferediobase_unsupported(state, "write"); } @@ -1222,8 +1224,10 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) CHECK_CLOSED(self, "seek of closed file") - if (_PyIOBase_check_seekable(self->raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_seekable(state, self->raw, Py_True) == NULL) { return NULL; + } target = PyNumber_AsOff_t(targetobj, PyExc_ValueError); if (target == -1 && PyErr_Occurred()) @@ -1298,7 +1302,8 @@ _io__Buffered_truncate_impl(buffered *self, PyObject *pos) CHECK_INITIALIZED(self) CHECK_CLOSED(self, "truncate of closed file") if (!self->writable) { - return bufferediobase_unsupported("truncate"); + _PyIO_State *state = IO_STATE(); + return bufferediobase_unsupported(state, "truncate"); } if (!ENTER_BUFFERED(self)) return NULL; @@ -1419,8 +1424,10 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_readable(state, raw, Py_True) == NULL) { return -1; + } Py_XSETREF(self->raw, Py_NewRef(raw)); self->buffer_size = buffer_size; @@ -1431,7 +1438,6 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, return -1; _bufferedreader_reset_buf(self); - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = ( Py_IS_TYPE(self, state->PyBufferedReader_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type) @@ -1774,8 +1780,10 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_writable(state, raw, Py_True) == NULL) { return -1; + } Py_INCREF(raw); Py_XSETREF(self->raw, raw); @@ -1788,7 +1796,6 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = ( Py_IS_TYPE(self, state->PyBufferedWriter_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type) @@ -2092,12 +2099,14 @@ _io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, PyObject *writer, Py_ssize_t buffer_size) /*[clinic end generated code: output=327e73d1aee8f984 input=620d42d71f33a031]*/ { - if (_PyIOBase_check_readable(reader, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_readable(state, reader, Py_True) == NULL) { return -1; - if (_PyIOBase_check_writable(writer, Py_True) == NULL) + } + if (_PyIOBase_check_writable(state, writer, Py_True) == NULL) { return -1; + } - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->reader = (buffered *) PyObject_CallFunction( (PyObject *)state->PyBufferedReader_Type, "On", reader, buffer_size); @@ -2290,12 +2299,16 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, self->ok = 0; self->detached = 0; - if (_PyIOBase_check_seekable(raw, Py_True) == NULL) + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + if (_PyIOBase_check_seekable(state, raw, Py_True) == NULL) { return -1; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) + } + if (_PyIOBase_check_readable(state, raw, Py_True) == NULL) { return -1; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) + } + if (_PyIOBase_check_writable(state, raw, Py_True) == NULL) { return -1; + } Py_INCREF(raw); Py_XSETREF(self->raw, raw); @@ -2309,7 +2322,6 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, _bufferedwriter_reset_buf(self); self->pos = 0; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); self->fast_closed_checks = (Py_IS_TYPE(self, state->PyBufferedRandom_Type) && Py_IS_TYPE(raw, state->PyFileIO_Type)); diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 682ed000eb1f..ca13866c33fb 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -71,11 +71,9 @@ PyDoc_STRVAR(iobase_doc, /* Internal methods */ static PyObject * -iobase_unsupported(const char *message) +iobase_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -97,7 +95,8 @@ PyDoc_STRVAR(iobase_seek_doc, static PyObject * iobase_seek(PyObject *self, PyObject *args) { - return iobase_unsupported("seek"); + _PyIO_State *state = IO_STATE(); + return iobase_unsupported(state, "seek"); } /*[clinic input] @@ -122,7 +121,8 @@ PyDoc_STRVAR(iobase_truncate_doc, static PyObject * iobase_truncate(PyObject *self, PyObject *args) { - return iobase_unsupported("truncate"); + _PyIO_State *state = IO_STATE(); + return iobase_unsupported(state, "truncate"); } static int @@ -204,6 +204,27 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +iobase_check_seekable(PyObject *self, PyObject *args) +{ + _PyIO_State *state = IO_STATE(); + return _PyIOBase_check_seekable(state, self, args); +} + +static PyObject * +iobase_check_readable(PyObject *self, PyObject *args) +{ + _PyIO_State *state = IO_STATE(); + return _PyIOBase_check_readable(state, self, args); +} + +static PyObject * +iobase_check_writable(PyObject *self, PyObject *args) +{ + _PyIO_State *state = IO_STATE(); + return _PyIOBase_check_writable(state, self, args); +} + /* XXX: IOBase thinks it has to maintain its own internal state in `__IOBase_closed` and call flush() by itself, but it is redundant with whatever behaviour a non-trivial derived class will implement. */ @@ -372,14 +393,14 @@ _io__IOBase_seekable_impl(PyObject *self) } PyObject * -_PyIOBase_check_seekable(PyObject *self, PyObject *args) +_PyIOBase_check_seekable(_PyIO_State *state, PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(seekable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - iobase_unsupported("File or stream is not seekable."); + iobase_unsupported(state, "File or stream is not seekable."); return NULL; } if (args == Py_True) { @@ -405,14 +426,14 @@ _io__IOBase_readable_impl(PyObject *self) /* May be called with any object */ PyObject * -_PyIOBase_check_readable(PyObject *self, PyObject *args) +_PyIOBase_check_readable(_PyIO_State *state, PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(readable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - iobase_unsupported("File or stream is not readable."); + iobase_unsupported(state, "File or stream is not readable."); return NULL; } if (args == Py_True) { @@ -438,14 +459,14 @@ _io__IOBase_writable_impl(PyObject *self) /* May be called with any object */ PyObject * -_PyIOBase_check_writable(PyObject *self, PyObject *args) +_PyIOBase_check_writable(_PyIO_State *state, PyObject *self, PyObject *args) { PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(writable)); if (res == NULL) return NULL; if (res != Py_True) { Py_CLEAR(res); - iobase_unsupported("File or stream is not writable."); + iobase_unsupported(state, "File or stream is not writable."); return NULL; } if (args == Py_True) { @@ -487,7 +508,8 @@ static PyObject * _io__IOBase_fileno_impl(PyObject *self) /*[clinic end generated code: output=7cc0973f0f5f3b73 input=4e37028947dc1cc8]*/ { - return iobase_unsupported("fileno"); + _PyIO_State *state = IO_STATE(); + return iobase_unsupported(state, "fileno"); } /*[clinic input] @@ -798,9 +820,9 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_WRITABLE_METHODDEF {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, - {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS}, - {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS}, - {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS}, + {"_checkSeekable", iobase_check_seekable, METH_NOARGS}, + {"_checkReadable", iobase_check_readable, METH_NOARGS}, + {"_checkWritable", iobase_check_writable, METH_NOARGS}, _IO__IOBASE_FILENO_METHODDEF _IO__IOBASE_ISATTY_METHODDEF From webhook-mailer at python.org Tue May 9 19:50:02 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 09 May 2023 23:50:02 -0000 Subject: [Python-checkins] gh-74895: adjust tests to work on Solaris (#104326) Message-ID: <mailman.280.1683676203.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2c863b3871c6127a80aa7229033219f1cdcc8711 commit: 2c863b3871c6127a80aa7229033219f1cdcc8711 branch: main author: Jakub Kul?k <Kulikjak at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-09T16:49:55-07:00 summary: gh-74895: adjust tests to work on Solaris (#104326) Solaris is unusual here, but apparently everyone is happy when SOCK_STREAM is explicitly specified. files: M Lib/test/test_socket.py diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index bb7bf436d2d7..68cdc6eaa913 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1622,7 +1622,7 @@ def test_getaddrinfo_int_port_overflow(self): from _testcapi import ULONG_MAX, LONG_MAX, LONG_MIN try: - socket.getaddrinfo(None, ULONG_MAX + 1) + socket.getaddrinfo(None, ULONG_MAX + 1, type=socket.SOCK_STREAM) except OverflowError: # Platforms differ as to what values consitute a getaddrinfo() error # return. Some fail for LONG_MAX+1, others ULONG_MAX+1, and Windows @@ -1632,28 +1632,28 @@ def test_getaddrinfo_int_port_overflow(self): pass try: - socket.getaddrinfo(None, LONG_MAX + 1) + socket.getaddrinfo(None, LONG_MAX + 1, type=socket.SOCK_STREAM) except OverflowError: self.fail("Either no error or socket.gaierror expected.") except socket.gaierror: pass try: - socket.getaddrinfo(None, LONG_MAX - 0xffff + 1) + socket.getaddrinfo(None, LONG_MAX - 0xffff + 1, type=socket.SOCK_STREAM) except OverflowError: self.fail("Either no error or socket.gaierror expected.") except socket.gaierror: pass try: - socket.getaddrinfo(None, LONG_MIN - 1) + socket.getaddrinfo(None, LONG_MIN - 1, type=socket.SOCK_STREAM) except OverflowError: self.fail("Either no error or socket.gaierror expected.") except socket.gaierror: pass - socket.getaddrinfo(None, 0) # No error expected. - socket.getaddrinfo(None, 0xffff) # No error expected. + socket.getaddrinfo(None, 0, type=socket.SOCK_STREAM) # No error expected. + socket.getaddrinfo(None, 0xffff, type=socket.SOCK_STREAM) # No error expected. def test_getnameinfo(self): # only IP addresses are allowed From webhook-mailer at python.org Tue May 9 20:18:55 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 10 May 2023 00:18:55 -0000 Subject: [Python-checkins] gh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (#103849) Message-ID: <mailman.281.1683677936.13550.python-checkins@python.org> https://github.com/python/cpython/commit/29f348e232e82938ba2165843c448c2b291504c5 commit: 29f348e232e82938ba2165843c448c2b291504c5 branch: main author: JohnJamesUtley <81572567+JohnJamesUtley at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-10T00:18:35Z summary: gh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (#103849) * Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format --------- Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index dcdbb1cc64fd..e324babdd5ed 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1042,6 +1042,32 @@ def test_issue14072(self): self.assertEqual(p2.scheme, 'tel') self.assertEqual(p2.path, '+31641044153') + def test_invalid_bracketed_hosts(self): + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[192.0.2.146]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[important.com:8000]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123r.IP]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v12ae]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v.IP]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123.]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path') + + def test_splitting_bracketed_hosts(self): + p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') + self.assertEqual(p1.hostname, 'v6a.ip') + self.assertEqual(p1.username, 'user') + self.assertEqual(p1.path, '/path') + p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') + self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') + self.assertEqual(p2.username, 'user') + self.assertEqual(p2.path, '/path') + p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') + self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p3.username, 'user') + self.assertEqual(p3.path, '/path') + def test_port_casting_failure_message(self): message = "Port could not be cast to integer value as 'oracle'" p1 = urllib.parse.urlparse('http://Server=sde; Service=sde:oracle') diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 777b7c53efe5..da0073969bff 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -33,6 +33,7 @@ import re import types import warnings +import ipaddress __all__ = ["urlparse", "urlunparse", "urljoin", "urldefrag", "urlsplit", "urlunsplit", "urlencode", "parse_qs", @@ -427,6 +428,17 @@ def _checknetloc(netloc): raise ValueError("netloc '" + netloc + "' contains invalid " + "characters under NFKC normalization") +# Valid bracketed hosts are defined in +# https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ +def _check_bracketed_host(hostname): + if hostname.startswith('v'): + if not re.match(r"\Av[a-fA-F0-9]+\..+\Z", hostname): + raise ValueError(f"IPvFuture address is invalid") + else: + ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 + if isinstance(ip, ipaddress.IPv4Address): + raise ValueError(f"An IPv4 address cannot be in brackets") + # typed=True avoids BytesWarnings being emitted during cache key # comparison since this API supports both bytes and str input. @functools.lru_cache(typed=True) @@ -466,12 +478,14 @@ def urlsplit(url, scheme='', allow_fragments=True): break else: scheme, url = url[:i].lower(), url[i+1:] - if url[:2] == '//': netloc, url = _splitnetloc(url, 2) if (('[' in netloc and ']' not in netloc) or (']' in netloc and '[' not in netloc)): raise ValueError("Invalid IPv6 URL") + if '[' in netloc and ']' in netloc: + bracketed_host = netloc.partition('[')[2].partition(']')[0] + _check_bracketed_host(bracketed_host) if allow_fragments and '#' in url: url, fragment = url.split('#', 1) if '?' in url: diff --git a/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst b/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst new file mode 100644 index 000000000000..81e5904aa6cc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst @@ -0,0 +1,2 @@ +Add checks to ensure that ``[`` bracketed ``]`` hosts found by +:func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format. From webhook-mailer at python.org Tue May 9 20:59:11 2023 From: webhook-mailer at python.org (brettcannon) Date: Wed, 10 May 2023 00:59:11 -0000 Subject: [Python-checkins] gh-103247: clear the module cache in a test in test_importlib/extensions/test_loader.py (GH-104226) Message-ID: <mailman.282.1683680352.13550.python-checkins@python.org> https://github.com/python/cpython/commit/22f3425c3d3d896be0917d80d55e8abb08d99b18 commit: 22f3425c3d3d896be0917d80d55e8abb08d99b18 branch: main author: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> committer: brettcannon <brett at python.org> date: 2023-05-10T00:59:04Z summary: gh-103247: clear the module cache in a test in test_importlib/extensions/test_loader.py (GH-104226) files: M Lib/test/test_importlib/extension/test_loader.py diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 3a74b821eaee..a7c6245825ff 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -262,15 +262,16 @@ def test_reload(self): def test_try_registration(self): # Assert that the PyState_{Find,Add,Remove}Module C API doesn't work. - module = self.load_module() - with self.subTest('PyState_FindModule'): - self.assertEqual(module.call_state_registration_func(0), None) - with self.subTest('PyState_AddModule'): - with self.assertRaises(SystemError): - module.call_state_registration_func(1) - with self.subTest('PyState_RemoveModule'): - with self.assertRaises(SystemError): - module.call_state_registration_func(2) + with util.uncache(self.name): + module = self.load_module() + with self.subTest('PyState_FindModule'): + self.assertEqual(module.call_state_registration_func(0), None) + with self.subTest('PyState_AddModule'): + with self.assertRaises(SystemError): + module.call_state_registration_func(1) + with self.subTest('PyState_RemoveModule'): + with self.assertRaises(SystemError): + module.call_state_registration_func(2) def test_load_submodule(self): # Test loading a simulated submodule. From webhook-mailer at python.org Wed May 10 02:35:31 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 10 May 2023 06:35:31 -0000 Subject: [Python-checkins] [3.11] gh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (GH-103849) (#104349) Message-ID: <mailman.283.1683700532.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b2171a2fd41416cf68afd67460578631d755a550 commit: b2171a2fd41416cf68afd67460578631d755a550 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-10T06:35:24Z summary: [3.11] gh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (GH-103849) (#104349) gh-103848: Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format (GH-103849) * Adds checks to ensure that bracketed hosts found by urlsplit are of IPv6 or IPvFuture format --------- (cherry picked from commit 29f348e232e82938ba2165843c448c2b291504c5) Co-authored-by: JohnJamesUtley <81572567+JohnJamesUtley at users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index b4261107235f..6b23ba604cce 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1033,6 +1033,32 @@ def test_issue14072(self): self.assertEqual(p2.scheme, 'tel') self.assertEqual(p2.path, '+31641044153') + def test_invalid_bracketed_hosts(self): + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[192.0.2.146]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[important.com:8000]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123r.IP]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v12ae]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v.IP]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123.]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query') + self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path') + + def test_splitting_bracketed_hosts(self): + p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') + self.assertEqual(p1.hostname, 'v6a.ip') + self.assertEqual(p1.username, 'user') + self.assertEqual(p1.path, '/path') + p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query') + self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test') + self.assertEqual(p2.username, 'user') + self.assertEqual(p2.path, '/path') + p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query') + self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test') + self.assertEqual(p3.username, 'user') + self.assertEqual(p3.path, '/path') + def test_port_casting_failure_message(self): message = "Port could not be cast to integer value as 'oracle'" p1 = urllib.parse.urlparse('http://Server=sde; Service=sde:oracle') diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 69631cbb810b..2af4700a703e 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -33,6 +33,7 @@ import sys import types import warnings +import ipaddress __all__ = ["urlparse", "urlunparse", "urljoin", "urldefrag", "urlsplit", "urlunsplit", "urlencode", "parse_qs", @@ -427,6 +428,17 @@ def _checknetloc(netloc): raise ValueError("netloc '" + netloc + "' contains invalid " + "characters under NFKC normalization") +# Valid bracketed hosts are defined in +# https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/ +def _check_bracketed_host(hostname): + if hostname.startswith('v'): + if not re.match(r"\Av[a-fA-F0-9]+\..+\Z", hostname): + raise ValueError(f"IPvFuture address is invalid") + else: + ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4 + if isinstance(ip, ipaddress.IPv4Address): + raise ValueError(f"An IPv4 address cannot be in brackets") + # typed=True avoids BytesWarnings being emitted during cache key # comparison since this API supports both bytes and str input. @functools.lru_cache(typed=True) @@ -466,12 +478,14 @@ def urlsplit(url, scheme='', allow_fragments=True): break else: scheme, url = url[:i].lower(), url[i+1:] - if url[:2] == '//': netloc, url = _splitnetloc(url, 2) if (('[' in netloc and ']' not in netloc) or (']' in netloc and '[' not in netloc)): raise ValueError("Invalid IPv6 URL") + if '[' in netloc and ']' in netloc: + bracketed_host = netloc.partition('[')[2].partition(']')[0] + _check_bracketed_host(bracketed_host) if allow_fragments and '#' in url: url, fragment = url.split('#', 1) if '?' in url: diff --git a/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst b/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst new file mode 100644 index 000000000000..81e5904aa6cc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst @@ -0,0 +1,2 @@ +Add checks to ensure that ``[`` bracketed ``]`` hosts found by +:func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format. From webhook-mailer at python.org Wed May 10 06:59:42 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 10 May 2023 10:59:42 -0000 Subject: [Python-checkins] gh-101819: Clean up _io windows console io after gh-104197 (#104354) Message-ID: <mailman.284.1683716384.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2dcb289ed08980c8f97d538060b4ad8d5e82b56a commit: 2dcb289ed08980c8f97d538060b4ad8d5e82b56a branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-10T10:59:31Z summary: gh-101819: Clean up _io windows console io after gh-104197 (#104354) files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/winconsoleio.c diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 6c5ea2879642..ee4eca70e2af 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -772,7 +772,7 @@ PyInit__io(void) // PyRawIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, state->PyRawIOBase_Type); #endif diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index b3873ddf7e08..44d651338e69 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -162,7 +162,7 @@ struct _io_state { PyTypeObject *PyStringIO_Type; PyTypeObject *PyTextIOBase_Type; PyTypeObject *PyTextIOWrapper_Type; -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO PyTypeObject *PyWindowsConsoleIO_Type; #endif }; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index fdb57cff7c04..58d9f2963aa9 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -263,7 +263,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, int fd_is_own = 0; HANDLE handle = NULL; -#ifdef Py_DEBUG +#ifdef NDEBUG _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); assert(PyObject_TypeCheck(self, state->PyWindowsConsoleIO_Type)); #endif From webhook-mailer at python.org Wed May 10 06:59:43 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 10 May 2023 10:59:43 -0000 Subject: [Python-checkins] gh-101819: Harden _io init (#104352) Message-ID: <mailman.285.1683716384.13550.python-checkins@python.org> https://github.com/python/cpython/commit/68a8ca6dc10bdceb4efaac569081b78ec01c3a99 commit: 68a8ca6dc10bdceb4efaac569081b78ec01c3a99 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-10T12:59:03+02:00 summary: gh-101819: Harden _io init (#104352) Fix potential refleak if PyModule_AddObject() fails. files: M Modules/_io/_iomodule.c diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index c05407b5d618..6c5ea2879642 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -730,9 +730,11 @@ PyInit__io(void) "UnsupportedOperation", PyExc_OSError, PyExc_ValueError); if (state->unsupported_operation == NULL) goto fail; - if (PyModule_AddObject(m, "UnsupportedOperation", - Py_NewRef(state->unsupported_operation)) < 0) + if (PyModule_AddObjectRef(m, "UnsupportedOperation", + state->unsupported_operation) < 0) + { goto fail; + } /* BlockingIOError, for compatibility */ if (PyModule_AddObjectRef(m, "BlockingIOError", @@ -785,7 +787,6 @@ PyInit__io(void) return m; fail: - Py_XDECREF(state->unsupported_operation); Py_DECREF(m); return NULL; } From webhook-mailer at python.org Wed May 10 07:43:21 2023 From: webhook-mailer at python.org (encukou) Date: Wed, 10 May 2023 11:43:21 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E10=5D_gh-102950=3A_Implement_?= =?utf-8?q?PEP_706_=E2=80=93_Filter_for_tarfile=2Eextractall_=28GH-102953?= =?utf-8?q?=29_=28GH-104128=29?= Message-ID: <mailman.286.1683719002.13550.python-checkins@python.org> https://github.com/python/cpython/commit/425065bb002b9cbf9c12f61a6f3102f2ce2b8d14 commit: 425065bb002b9cbf9c12f61a6f3102f2ce2b8d14 branch: 3.10 author: Mat?j Cepl <mcepl at cepl.eu> committer: encukou <encukou at gmail.com> date: 2023-05-10T13:43:00+02:00 summary: [3.10] gh-102950: Implement PEP 706 ? Filter for tarfile.extractall (GH-102953) (GH-104128) - Backport b52ad18a766700be14382ba222033b2d75a33521 - Backport c8c3956d905e019101038b018129a4c90c9c9b8f - Remove the DeprecationWarning - Adjust docs - Remove new `__all__` entries Co-authored-by: Petr Viktorin <encukou at gmail.com> files: A Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst M Doc/library/shutil.rst M Doc/library/tarfile.rst M Doc/whatsnew/3.10.rst M Lib/shutil.py M Lib/tarfile.py M Lib/test/test_shutil.py M Lib/test/test_tarfile.py diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 311aae414aea..3cf73b4b3423 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -620,7 +620,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Remove the archive format *name* from the list of supported formats. -.. function:: unpack_archive(filename[, extract_dir[, format]]) +.. function:: unpack_archive(filename[, extract_dir[, format[, filter]]]) Unpack an archive. *filename* is the full path of the archive. @@ -634,6 +634,15 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. registered for that extension. In case none is found, a :exc:`ValueError` is raised. + The keyword-only *filter* argument, which was added in Python 3.10.12, + is passed to the underlying unpacking function. + For zip files, *filter* is not accepted. + For tar files, it is recommended to set it to ``'data'``, + unless using features specific to tar and UNIX-like filesystems. + (See :ref:`tarfile-extraction-filter` for details.) + The ``'data'`` filter will become the default for tar files + in Python 3.14. + .. audit-event:: shutil.unpack_archive filename,extract_dir,format shutil.unpack_archive .. warning:: @@ -646,6 +655,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. .. versionchanged:: 3.7 Accepts a :term:`path-like object` for *filename* and *extract_dir*. + .. versionchanged:: 3.10.12 + Added the *filter* argument. + .. function:: register_unpack_format(name, extensions, function[, extra_args[, description]]) Registers an unpack format. *name* is the name of the format and @@ -653,11 +665,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. ``.zip`` for Zip files. *function* is the callable that will be used to unpack archives. The - callable will receive the path of the archive, followed by the directory - the archive must be extracted to. - - When provided, *extra_args* is a sequence of ``(name, value)`` tuples that - will be passed as keywords arguments to the callable. + callable will receive: + + - the path of the archive, as a positional argument; + - the directory the archive must be extracted to, as a positional argument; + - possibly a *filter* keyword argument, if it was given to + :func:`unpack_archive`; + - additional keyword arguments, specified by *extra_args* as a sequence + of ``(name, value)`` tuples. *description* can be provided to describe the format, and will be returned by the :func:`get_unpack_formats` function. diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 226513f5fc16..bcec9ca3506f 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -206,6 +206,38 @@ The :mod:`tarfile` module defines the following exceptions: Is raised by :meth:`TarInfo.frombuf` if the buffer it gets is invalid. +.. exception:: FilterError + + Base class for members :ref:`refused <tarfile-extraction-refuse>` by + filters. + + .. attribute:: tarinfo + + Information about the member that the filter refused to extract, + as :ref:`TarInfo <tarinfo-objects>`. + +.. exception:: AbsolutePathError + + Raised to refuse extracting a member with an absolute path. + +.. exception:: OutsideDestinationError + + Raised to refuse extracting a member outside the destination directory. + +.. exception:: SpecialFileError + + Raised to refuse extracting a special file (e.g. a device or pipe). + +.. exception:: AbsoluteLinkError + + Raised to refuse extracting a symbolic link with an absolute path. + +.. exception:: LinkOutsideDestinationError + + Raised to refuse extracting a symbolic link pointing outside the destination + directory. + + The following constants are available at the module level: .. data:: ENCODING @@ -316,11 +348,8 @@ be finalized; only the internally used file object will be closed. See the *debug* can be set from ``0`` (no debug messages) up to ``3`` (all debug messages). The messages are written to ``sys.stderr``. - If *errorlevel* is ``0``, all errors are ignored when using :meth:`TarFile.extract`. - Nevertheless, they appear as error messages in the debug output, when debugging - is enabled. If ``1``, all *fatal* errors are raised as :exc:`OSError` - exceptions. If ``2``, all *non-fatal* errors are raised as :exc:`TarError` - exceptions as well. + *errorlevel* controls how extraction errors are handled, + see :attr:`the corresponding attribute <~TarFile.errorlevel>`. The *encoding* and *errors* arguments define the character encoding to be used for reading or writing the archive and how conversion errors are going @@ -387,7 +416,7 @@ be finalized; only the internally used file object will be closed. See the available. -.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False) +.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False, filter=None) Extract all members from the archive to the current working directory or directory *path*. If optional *members* is given, it must be a subset of the @@ -401,6 +430,12 @@ be finalized; only the internally used file object will be closed. See the are used to set the owner/group for the extracted files. Otherwise, the named values from the tarfile are used. + The *filter* argument, which was added in Python 3.10.12, specifies how + ``members`` are modified or rejected before extraction. + See :ref:`tarfile-extraction-filter` for details. + It is recommended to set this explicitly depending on which *tar* features + you need to support. + .. warning:: Never extract archives from untrusted sources without prior inspection. @@ -408,14 +443,20 @@ be finalized; only the internally used file object will be closed. See the that have absolute filenames starting with ``"/"`` or filenames with two dots ``".."``. + Set ``filter='data'`` to prevent the most dangerous security issues, + and read the :ref:`tarfile-extraction-filter` section for details. + .. versionchanged:: 3.5 Added the *numeric_owner* parameter. .. versionchanged:: 3.6 The *path* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.10.12 + Added the *filter* parameter. + -.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False) +.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False, filter=None) Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. *member* @@ -423,9 +464,8 @@ be finalized; only the internally used file object will be closed. See the directory using *path*. *path* may be a :term:`path-like object`. File attributes (owner, mtime, mode) are set unless *set_attrs* is false. - If *numeric_owner* is :const:`True`, the uid and gid numbers from the tarfile - are used to set the owner/group for the extracted files. Otherwise, the named - values from the tarfile are used. + The *numeric_owner* and *filter* arguments are the same as + for :meth:`extractall`. .. note:: @@ -436,6 +476,9 @@ be finalized; only the internally used file object will be closed. See the See the warning for :meth:`extractall`. + Set ``filter='data'`` to prevent the most dangerous security issues, + and read the :ref:`tarfile-extraction-filter` section for details. + .. versionchanged:: 3.2 Added the *set_attrs* parameter. @@ -445,6 +488,9 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.6 The *path* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.10.12 + Added the *filter* parameter. + .. method:: TarFile.extractfile(member) @@ -457,6 +503,57 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.3 Return an :class:`io.BufferedReader` object. +.. attribute:: TarFile.errorlevel + :type: int + + If *errorlevel* is ``0``, errors are ignored when using :meth:`TarFile.extract` + and :meth:`TarFile.extractall`. + Nevertheless, they appear as error messages in the debug output when + *debug* is greater than 0. + If ``1`` (the default), all *fatal* errors are raised as :exc:`OSError` or + :exc:`FilterError` exceptions. If ``2``, all *non-fatal* errors are raised + as :exc:`TarError` exceptions as well. + + Some exceptions, e.g. ones caused by wrong argument types or data + corruption, are always raised. + + Custom :ref:`extraction filters <tarfile-extraction-filter>` + should raise :exc:`FilterError` for *fatal* errors + and :exc:`ExtractError` for *non-fatal* ones. + + Note that when an exception is raised, the archive may be partially + extracted. It is the user?s responsibility to clean up. + +.. attribute:: TarFile.extraction_filter + + .. versionadded:: 3.10.12 + + The :ref:`extraction filter <tarfile-extraction-filter>` used + as a default for the *filter* argument of :meth:`~TarFile.extract` + and :meth:`~TarFile.extractall`. + + The attribute may be ``None`` or a callable. + String names are not allowed for this attribute, unlike the *filter* + argument to :meth:`~TarFile.extract`. + + If ``extraction_filter`` is ``None`` (the default), + calling an extraction method without a *filter* argument will + use the :func:`fully_trusted <fully_trusted_filter>` filter for + compatibility with previous Python versions. + + In Python 3.12+, leaving ``extraction_filter=None`` will emit a + ``DeprecationWarning``. + + In Python 3.14+, leaving ``extraction_filter=None`` will cause + extraction methods to use the :func:`data <data_filter>` filter by default. + + The attribute may be set on instances or overridden in subclasses. + It also is possible to set it on the ``TarFile`` class itself to set a + global default, although, since it affects all uses of *tarfile*, + it is best practice to only do so in top-level applications or + :mod:`site configuration <site>`. + To set a global default this way, a filter function needs to be wrapped in + :func:`staticmethod()` to prevent injection of a ``self`` argument. .. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None) @@ -532,7 +629,27 @@ permissions, owner etc.), it provides some useful methods to determine its type. It does *not* contain the file's data itself. :class:`TarInfo` objects are returned by :class:`TarFile`'s methods -:meth:`getmember`, :meth:`getmembers` and :meth:`gettarinfo`. +:meth:`~TarFile.getmember`, :meth:`~TarFile.getmembers` and +:meth:`~TarFile.gettarinfo`. + +Modifying the objects returned by :meth:`~!TarFile.getmember` or +:meth:`~!TarFile.getmembers` will affect all subsequent +operations on the archive. +For cases where this is unwanted, you can use :mod:`copy.copy() <copy>` or +call the :meth:`~TarInfo.replace` method to create a modified copy in one step. + +Several attributes can be set to ``None`` to indicate that a piece of metadata +is unused or unknown. +Different :class:`TarInfo` methods handle ``None`` differently: + +- The :meth:`~TarFile.extract` or :meth:`~TarFile.extractall` methods will + ignore the corresponding metadata, leaving it set to a default. +- :meth:`~TarFile.addfile` will fail. +- :meth:`~TarFile.list` will print a placeholder string. + + +.. versionchanged:: 3.10.12 + Added :meth:`~TarInfo.replace` and handling of ``None``. .. class:: TarInfo(name="") @@ -566,24 +683,39 @@ A ``TarInfo`` object has the following public data attributes: .. attribute:: TarInfo.name + :type: str Name of the archive member. .. attribute:: TarInfo.size + :type: int Size in bytes. .. attribute:: TarInfo.mtime + :type: int | float + + Time of last modification in seconds since the :ref:`epoch <epoch>`, + as in :attr:`os.stat_result.st_mtime`. - Time of last modification. + .. versionchanged:: 3.10.12 + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.mode + :type: int - Permission bits. + Permission bits, as for :func:`os.chmod`. + .. versionchanged:: 3.10.12 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.type @@ -595,35 +727,76 @@ A ``TarInfo`` object has the following public data attributes: .. attribute:: TarInfo.linkname + :type: str Name of the target file name, which is only present in :class:`TarInfo` objects of type :const:`LNKTYPE` and :const:`SYMTYPE`. .. attribute:: TarInfo.uid + :type: int User ID of the user who originally stored this member. + .. versionchanged:: 3.10.12 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.gid + :type: int Group ID of the user who originally stored this member. + .. versionchanged:: 3.10.12 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.uname + :type: str User name. + .. versionchanged:: 3.10.12 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.gname + :type: str Group name. + .. versionchanged:: 3.10.12 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.pax_headers + :type: dict A dictionary containing key-value pairs of an associated pax extended header. +.. method:: TarInfo.replace(name=..., mtime=..., mode=..., linkname=..., + uid=..., gid=..., uname=..., gname=..., + deep=True) + + .. versionadded:: 3.10.12 + + Return a *new* copy of the :class:`!TarInfo` object with the given attributes + changed. For example, to return a ``TarInfo`` with the group name set to + ``'staff'``, use:: + + new_tarinfo = old_tarinfo.replace(gname='staff') + + By default, a deep copy is made. + If *deep* is false, the copy is shallow, i.e. ``pax_headers`` + and any custom attributes are shared with the original ``TarInfo`` object. A :class:`TarInfo` object also provides some convenient query methods: @@ -673,9 +846,259 @@ A :class:`TarInfo` object also provides some convenient query methods: Return :const:`True` if it is one of character device, block device or FIFO. +.. _tarfile-extraction-filter: + +Extraction filters +------------------ + +.. versionadded:: 3.10.12 + +The *tar* format is designed to capture all details of a UNIX-like filesystem, +which makes it very powerful. +Unfortunately, the features make it easy to create tar files that have +unintended -- and possibly malicious -- effects when extracted. +For example, extracting a tar file can overwrite arbitrary files in various +ways (e.g. by using absolute paths, ``..`` path components, or symlinks that +affect later members). + +In most cases, the full functionality is not needed. +Therefore, *tarfile* supports extraction filters: a mechanism to limit +functionality, and thus mitigate some of the security issues. + +.. seealso:: + + :pep:`706` + Contains further motivation and rationale behind the design. + +The *filter* argument to :meth:`TarFile.extract` or :meth:`~TarFile.extractall` +can be: + +* the string ``'fully_trusted'``: Honor all metadata as specified in the + archive. + Should be used if the user trusts the archive completely, or implements + their own complex verification. + +* the string ``'tar'``: Honor most *tar*-specific features (i.e. features of + UNIX-like filesystems), but block features that are very likely to be + surprising or malicious. See :func:`tar_filter` for details. + +* the string ``'data'``: Ignore or block most features specific to UNIX-like + filesystems. Intended for extracting cross-platform data archives. + See :func:`data_filter` for details. + +* ``None`` (default): Use :attr:`TarFile.extraction_filter`. + + If that is also ``None`` (the default), the ``'fully_trusted'`` + filter will be used (for compatibility with earlier versions of Python). + + In Python 3.12, the default will emit a ``DeprecationWarning``. + + In Python 3.14, the ``'data'`` filter will become the default instead. + It's possible to switch earlier; see :attr:`TarFile.extraction_filter`. + +* A callable which will be called for each extracted member with a + :ref:`TarInfo <tarinfo-objects>` describing the member and the destination + path to where the archive is extracted (i.e. the same path is used for all + members):: + + filter(/, member: TarInfo, path: str) -> TarInfo | None + + The callable is called just before each member is extracted, so it can + take the current state of the disk into account. + It can: + + - return a :class:`TarInfo` object which will be used instead of the metadata + in the archive, or + - return ``None``, in which case the member will be skipped, or + - raise an exception to abort the operation or skip the member, + depending on :attr:`~TarFile.errorlevel`. + Note that when extraction is aborted, :meth:`~TarFile.extractall` may leave + the archive partially extracted. It does not attempt to clean up. + +Default named filters +~~~~~~~~~~~~~~~~~~~~~ + +The pre-defined, named filters are available as functions, so they can be +reused in custom filters: + +.. function:: fully_trusted_filter(/, member, path) + + Return *member* unchanged. + + This implements the ``'fully_trusted'`` filter. + +.. function:: tar_filter(/, member, path) + + Implements the ``'tar'`` filter. + + - Strip leading slashes (``/`` and :attr:`os.sep`) from filenames. + - :ref:`Refuse <tarfile-extraction-refuse>` to extract files with absolute + paths (in case the name is absolute + even after stripping slashes, e.g. ``C:/foo`` on Windows). + This raises :class:`~tarfile.AbsolutePathError`. + - :ref:`Refuse <tarfile-extraction-refuse>` to extract files whose absolute + path (after following symlinks) would end up outside the destination. + This raises :class:`~tarfile.OutsideDestinationError`. + - Clear high mode bits (setuid, setgid, sticky) and group/other write bits + (:attr:`~stat.S_IWGRP`|:attr:`~stat.S_IWOTH`). + + Return the modified ``TarInfo`` member. + +.. function:: data_filter(/, member, path) + + Implements the ``'data'`` filter. + In addition to what ``tar_filter`` does: + + - :ref:`Refuse <tarfile-extraction-refuse>` to extract links (hard or soft) + that link to absolute paths, or ones that link outside the destination. + + This raises :class:`~tarfile.AbsoluteLinkError` or + :class:`~tarfile.LinkOutsideDestinationError`. + + Note that such files are refused even on platforms that do not support + symbolic links. + + - :ref:`Refuse <tarfile-extraction-refuse>` to extract device files + (including pipes). + This raises :class:`~tarfile.SpecialFileError`. + + - For regular files, including hard links: + + - Set the owner read and write permissions + (:attr:`~stat.S_IRUSR`|:attr:`~stat.S_IWUSR`). + - Remove the group & other executable permission + (:attr:`~stat.S_IXGRP`|:attr:`~stat.S_IXOTH`) + if the owner doesn?t have it (:attr:`~stat.S_IXUSR`). + + - For other files (directories), set ``mode`` to ``None``, so + that extraction methods skip applying permission bits. + - Set user and group info (``uid``, ``gid``, ``uname``, ``gname``) + to ``None``, so that extraction methods skip setting it. + + Return the modified ``TarInfo`` member. + + +.. _tarfile-extraction-refuse: + +Filter errors +~~~~~~~~~~~~~ + +When a filter refuses to extract a file, it will raise an appropriate exception, +a subclass of :class:`~tarfile.FilterError`. +This will abort the extraction if :attr:`TarFile.errorlevel` is 1 or more. +With ``errorlevel=0`` the error will be logged and the member will be skipped, +but extraction will continue. + + +Hints for further verification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Even with ``filter='data'``, *tarfile* is not suited for extracting untrusted +files without prior inspection. +Among other issues, the pre-defined filters do not prevent denial-of-service +attacks. Users should do additional checks. + +Here is an incomplete list of things to consider: + +* Extract to a :func:`new temporary directory <tempfile.mkdtemp>` + to prevent e.g. exploiting pre-existing links, and to make it easier to + clean up after a failed extraction. +* When working with untrusted data, use external (e.g. OS-level) limits on + disk, memory and CPU usage. +* Check filenames against an allow-list of characters + (to filter out control characters, confusables, foreign path separators, + etc.). +* Check that filenames have expected extensions (discouraging files that + execute when you ?click on them?, or extension-less files like Windows special device names). +* Limit the number of extracted files, total size of extracted data, + filename length (including symlink length), and size of individual files. +* Check for files that would be shadowed on case-insensitive filesystems. + +Also note that: + +* Tar files may contain multiple versions of the same file. + Later ones are expected to overwrite any earlier ones. + This feature is crucial to allow updating tape archives, but can be abused + maliciously. +* *tarfile* does not protect against issues with ?live? data, + e.g. an attacker tinkering with the destination (or source) directory while + extraction (or archiving) is in progress. + + +Supporting older Python versions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extraction filters were added to Python 3.12, and are backported to older +versions as security updates. +To check whether the feature is available, use e.g. +``hasattr(tarfile, 'data_filter')`` rather than checking the Python version. + +The following examples show how to support Python versions with and without +the feature. +Note that setting ``extraction_filter`` will affect any subsequent operations. + +* Fully trusted archive:: + + my_tarfile.extraction_filter = (lambda member, path: member) + my_tarfile.extractall() + +* Use the ``'data'`` filter if available, but revert to Python 3.11 behavior + (``'fully_trusted'``) if this feature is not available:: + + my_tarfile.extraction_filter = getattr(tarfile, 'data_filter', + (lambda member, path: member)) + my_tarfile.extractall() + +* Use the ``'data'`` filter; *fail* if it is not available:: + + my_tarfile.extractall(filter=tarfile.data_filter) + + or:: + + my_tarfile.extraction_filter = tarfile.data_filter + my_tarfile.extractall() + +* Use the ``'data'`` filter; *warn* if it is not available:: + + if hasattr(tarfile, 'data_filter'): + my_tarfile.extractall(filter='data') + else: + # remove this when no longer needed + warn_the_user('Extracting may be unsafe; consider updating Python') + my_tarfile.extractall() + + +Stateful extraction filter example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While *tarfile*'s extraction methods take a simple *filter* callable, +custom filters may be more complex objects with an internal state. +It may be useful to write these as context managers, to be used like this:: + + with StatefulFilter() as filter_func: + tar.extractall(path, filter=filter_func) + +Such a filter can be written as, for example:: + + class StatefulFilter: + def __init__(self): + self.file_count = 0 + + def __enter__(self): + return self + + def __call__(self, member, path): + self.file_count += 1 + return member + + def __exit__(self, *exc_info): + print(f'{self.file_count} files extracted') + + .. _tarfile-commandline: .. program:: tarfile + Command-Line Interface ---------------------- @@ -745,6 +1168,15 @@ Command-line options Verbose output. +.. cmdoption:: --filter <filtername> + + Specifies the *filter* for ``--extract``. + See :ref:`tarfile-extraction-filter` for details. + Only string names are accepted (that is, ``fully_trusted``, ``tar``, + and ``data``). + + .. versionadded:: 3.10.12 + .. _tar-examples: Examples diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 47e38ae76bad..43da72aece9d 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -2332,3 +2332,19 @@ The deprecated :mod:`mailcap` module now refuses to inject unsafe text text, it will warn and act as if a match was not found (or for test commands, as if the test failed). (Contributed by Petr Viktorin in :gh:`98966`.) + +Notable Changes in 3.10.12 +========================== + +tarfile +------- + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile-extraction-filter` for details. + In Python 3.12, use without the *filter* argument will show a + :exc:`DeprecationWarning`. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) diff --git a/Lib/shutil.py b/Lib/shutil.py index b7bffa3ea41b..482ce95a7b23 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1222,7 +1222,7 @@ def _unpack_zipfile(filename, extract_dir): finally: zip.close() -def _unpack_tarfile(filename, extract_dir): +def _unpack_tarfile(filename, extract_dir, *, filter=None): """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` """ import tarfile # late import for breaking circular dependency @@ -1232,7 +1232,7 @@ def _unpack_tarfile(filename, extract_dir): raise ReadError( "%s is not a compressed or uncompressed tar file" % filename) try: - tarobj.extractall(extract_dir) + tarobj.extractall(extract_dir, filter=filter) finally: tarobj.close() @@ -1265,7 +1265,7 @@ def _find_unpack_format(filename): return name return None -def unpack_archive(filename, extract_dir=None, format=None): +def unpack_archive(filename, extract_dir=None, format=None, *, filter=None): """Unpack an archive. `filename` is the name of the archive. @@ -1279,6 +1279,9 @@ def unpack_archive(filename, extract_dir=None, format=None): was registered for that extension. In case none is found, a ValueError is raised. + + If `filter` is given, it is passed to the underlying + extraction function. """ sys.audit("shutil.unpack_archive", filename, extract_dir, format) @@ -1288,6 +1291,10 @@ def unpack_archive(filename, extract_dir=None, format=None): extract_dir = os.fspath(extract_dir) filename = os.fspath(filename) + if filter is None: + filter_kwargs = {} + else: + filter_kwargs = {'filter': filter} if format is not None: try: format_info = _UNPACK_FORMATS[format] @@ -1295,7 +1302,7 @@ def unpack_archive(filename, extract_dir=None, format=None): raise ValueError("Unknown unpack format '{0}'".format(format)) from None func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) + func(filename, extract_dir, **dict(format_info[2]), **filter_kwargs) else: # we need to look at the registered unpackers supported extensions format = _find_unpack_format(filename) @@ -1303,7 +1310,7 @@ def unpack_archive(filename, extract_dir=None, format=None): raise ReadError("Unknown archive format '{0}'".format(filename)) func = _UNPACK_FORMATS[format][1] - kwargs = dict(_UNPACK_FORMATS[format][2]) + kwargs = dict(_UNPACK_FORMATS[format][2]) | filter_kwargs func(filename, extract_dir, **kwargs) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index dea150e8dbbb..40599f27bce9 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -46,6 +46,7 @@ import struct import copy import re +import warnings try: import pwd @@ -71,6 +72,7 @@ "ENCODING", "USTAR_FORMAT", "GNU_FORMAT", "PAX_FORMAT", "DEFAULT_FORMAT", "open"] + #--------------------------------------------------------- # tar constants #--------------------------------------------------------- @@ -158,6 +160,8 @@ def stn(s, length, encoding, errors): """Convert a string to a null-terminated bytes object. """ + if s is None: + raise ValueError("metadata cannot contain None") s = s.encode(encoding, errors) return s[:length] + (length - len(s)) * NUL @@ -709,9 +713,127 @@ def __init__(self, tarfile, tarinfo): super().__init__(fileobj) #class ExFileObject + +#----------------------------- +# extraction filters (PEP 706) +#----------------------------- + +class FilterError(TarError): + pass + +class AbsolutePathError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'member {tarinfo.name!r} has an absolute path') + +class OutsideDestinationError(FilterError): + def __init__(self, tarinfo, path): + self.tarinfo = tarinfo + self._path = path + super().__init__(f'{tarinfo.name!r} would be extracted to {path!r}, ' + + 'which is outside the destination') + +class SpecialFileError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'{tarinfo.name!r} is a special file') + +class AbsoluteLinkError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'{tarinfo.name!r} is a symlink to an absolute path') + +class LinkOutsideDestinationError(FilterError): + def __init__(self, tarinfo, path): + self.tarinfo = tarinfo + self._path = path + super().__init__(f'{tarinfo.name!r} would link to {path!r}, ' + + 'which is outside the destination') + +def _get_filtered_attrs(member, dest_path, for_data=True): + new_attrs = {} + name = member.name + dest_path = os.path.realpath(dest_path) + # Strip leading / (tar's directory separator) from filenames. + # Include os.sep (target OS directory separator) as well. + if name.startswith(('/', os.sep)): + name = new_attrs['name'] = member.path.lstrip('/' + os.sep) + if os.path.isabs(name): + # Path is absolute even after stripping. + # For example, 'C:/foo' on Windows. + raise AbsolutePathError(member) + # Ensure we stay in the destination + target_path = os.path.realpath(os.path.join(dest_path, name)) + if os.path.commonpath([target_path, dest_path]) != dest_path: + raise OutsideDestinationError(member, target_path) + # Limit permissions (no high bits, and go-w) + mode = member.mode + if mode is not None: + # Strip high bits & group/other write bits + mode = mode & 0o755 + if for_data: + # For data, handle permissions & file types + if member.isreg() or member.islnk(): + if not mode & 0o100: + # Clear executable bits if not executable by user + mode &= ~0o111 + # Ensure owner can read & write + mode |= 0o600 + elif member.isdir() or member.issym(): + # Ignore mode for directories & symlinks + mode = None + else: + # Reject special files + raise SpecialFileError(member) + if mode != member.mode: + new_attrs['mode'] = mode + if for_data: + # Ignore ownership for 'data' + if member.uid is not None: + new_attrs['uid'] = None + if member.gid is not None: + new_attrs['gid'] = None + if member.uname is not None: + new_attrs['uname'] = None + if member.gname is not None: + new_attrs['gname'] = None + # Check link destination for 'data' + if member.islnk() or member.issym(): + if os.path.isabs(member.linkname): + raise AbsoluteLinkError(member) + target_path = os.path.realpath(os.path.join(dest_path, member.linkname)) + if os.path.commonpath([target_path, dest_path]) != dest_path: + raise LinkOutsideDestinationError(member, target_path) + return new_attrs + +def fully_trusted_filter(member, dest_path): + return member + +def tar_filter(member, dest_path): + new_attrs = _get_filtered_attrs(member, dest_path, False) + if new_attrs: + return member.replace(**new_attrs, deep=False) + return member + +def data_filter(member, dest_path): + new_attrs = _get_filtered_attrs(member, dest_path, True) + if new_attrs: + return member.replace(**new_attrs, deep=False) + return member + +_NAMED_FILTERS = { + "fully_trusted": fully_trusted_filter, + "tar": tar_filter, + "data": data_filter, +} + #------------------ # Exported Classes #------------------ + +# Sentinel for replace() defaults, meaning "don't change the attribute" +_KEEP = object() + class TarInfo(object): """Informational class which holds the details about an archive member given by a tar header block. @@ -792,12 +914,44 @@ def linkpath(self, linkname): def __repr__(self): return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) + def replace(self, *, + name=_KEEP, mtime=_KEEP, mode=_KEEP, linkname=_KEEP, + uid=_KEEP, gid=_KEEP, uname=_KEEP, gname=_KEEP, + deep=True, _KEEP=_KEEP): + """Return a deep copy of self with the given attributes replaced. + """ + if deep: + result = copy.deepcopy(self) + else: + result = copy.copy(self) + if name is not _KEEP: + result.name = name + if mtime is not _KEEP: + result.mtime = mtime + if mode is not _KEEP: + result.mode = mode + if linkname is not _KEEP: + result.linkname = linkname + if uid is not _KEEP: + result.uid = uid + if gid is not _KEEP: + result.gid = gid + if uname is not _KEEP: + result.uname = uname + if gname is not _KEEP: + result.gname = gname + return result + def get_info(self): """Return the TarInfo's attributes as a dictionary. """ + if self.mode is None: + mode = None + else: + mode = self.mode & 0o7777 info = { "name": self.name, - "mode": self.mode & 0o7777, + "mode": mode, "uid": self.uid, "gid": self.gid, "size": self.size, @@ -820,6 +974,9 @@ def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescap """Return a tar header as a string of 512 byte blocks. """ info = self.get_info() + for name, value in info.items(): + if value is None: + raise ValueError("%s may not be None" % name) if format == USTAR_FORMAT: return self.create_ustar_header(info, encoding, errors) @@ -950,6 +1107,12 @@ def _create_header(info, format, encoding, errors): devmajor = stn("", 8, encoding, errors) devminor = stn("", 8, encoding, errors) + # None values in metadata should cause ValueError. + # itn()/stn() do this for all fields except type. + filetype = info.get("type", REGTYPE) + if filetype is None: + raise ValueError("TarInfo.type must not be None") + parts = [ stn(info.get("name", ""), 100, encoding, errors), itn(info.get("mode", 0) & 0o7777, 8, format), @@ -958,7 +1121,7 @@ def _create_header(info, format, encoding, errors): itn(info.get("size", 0), 12, format), itn(info.get("mtime", 0), 12, format), b" ", # checksum field - info.get("type", REGTYPE), + filetype, stn(info.get("linkname", ""), 100, encoding, errors), info.get("magic", POSIX_MAGIC), stn(info.get("uname", ""), 32, encoding, errors), @@ -1468,6 +1631,8 @@ class TarFile(object): fileobject = ExFileObject # The file-object for extractfile(). + extraction_filter = None # The default filter for extraction. + def __init__(self, name=None, mode="r", fileobj=None, format=None, tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, errors="surrogateescape", pax_headers=None, debug=None, @@ -1940,7 +2105,10 @@ def list(self, verbose=True, *, members=None): members = self for tarinfo in members: if verbose: - _safe_print(stat.filemode(tarinfo.mode)) + if tarinfo.mode is None: + _safe_print("??????????") + else: + _safe_print(stat.filemode(tarinfo.mode)) _safe_print("%s/%s" % (tarinfo.uname or tarinfo.uid, tarinfo.gname or tarinfo.gid)) if tarinfo.ischr() or tarinfo.isblk(): @@ -1948,8 +2116,11 @@ def list(self, verbose=True, *, members=None): ("%d,%d" % (tarinfo.devmajor, tarinfo.devminor))) else: _safe_print("%10d" % tarinfo.size) - _safe_print("%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6]) + if tarinfo.mtime is None: + _safe_print("????-??-?? ??:??:??") + else: + _safe_print("%d-%02d-%02d %02d:%02d:%02d" \ + % time.localtime(tarinfo.mtime)[:6]) _safe_print(tarinfo.name + ("/" if tarinfo.isdir() else "")) @@ -2036,32 +2207,58 @@ def addfile(self, tarinfo, fileobj=None): self.members.append(tarinfo) - def extractall(self, path=".", members=None, *, numeric_owner=False): + def _get_filter_function(self, filter): + if filter is None: + filter = self.extraction_filter + if filter is None: + return fully_trusted_filter + if isinstance(filter, str): + raise TypeError( + 'String names are not supported for ' + + 'TarFile.extraction_filter. Use a function such as ' + + 'tarfile.data_filter directly.') + return filter + if callable(filter): + return filter + try: + return _NAMED_FILTERS[filter] + except KeyError: + raise ValueError(f"filter {filter!r} not found") from None + + def extractall(self, path=".", members=None, *, numeric_owner=False, + filter=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on directories afterwards. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by getmembers(). If `numeric_owner` is True, only the numbers for user/group names are used and not the names. + + The `filter` function will be called on each member just + before extraction. + It can return a changed TarInfo or None to skip the member. + String names of common filters are accepted. """ directories = [] + filter_function = self._get_filter_function(filter) if members is None: members = self - for tarinfo in members: + for member in members: + tarinfo = self._get_extract_tarinfo(member, filter_function, path) + if tarinfo is None: + continue if tarinfo.isdir(): - # Extract directories with a safe mode. + # For directories, delay setting attributes until later, + # since permissions can interfere with extraction and + # extracting contents can reset mtime. directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0o700 - # Do not set_attrs directories, as we will do that further down - self.extract(tarinfo, path, set_attrs=not tarinfo.isdir(), - numeric_owner=numeric_owner) + self._extract_one(tarinfo, path, set_attrs=not tarinfo.isdir(), + numeric_owner=numeric_owner) # Reverse sort directories. - directories.sort(key=lambda a: a.name) - directories.reverse() + directories.sort(key=lambda a: a.name, reverse=True) # Set correct owner, mtime and filemode on directories. for tarinfo in directories: @@ -2071,12 +2268,10 @@ def extractall(self, path=".", members=None, *, numeric_owner=False): self.utime(tarinfo, dirpath) self.chmod(tarinfo, dirpath) except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) + self._handle_nonfatal_error(e) - def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): + def extract(self, member, path="", set_attrs=True, *, numeric_owner=False, + filter=None): """Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. `member' may be a filename or a TarInfo object. You can @@ -2084,35 +2279,70 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): mtime, mode) are set unless `set_attrs' is False. If `numeric_owner` is True, only the numbers for user/group names are used and not the names. + + The `filter` function will be called before extraction. + It can return a changed TarInfo or None to skip the member. + String names of common filters are accepted. """ - self._check("r") + filter_function = self._get_filter_function(filter) + tarinfo = self._get_extract_tarinfo(member, filter_function, path) + if tarinfo is not None: + self._extract_one(tarinfo, path, set_attrs, numeric_owner) + def _get_extract_tarinfo(self, member, filter_function, path): + """Get filtered TarInfo (or None) from member, which might be a str""" if isinstance(member, str): tarinfo = self.getmember(member) else: tarinfo = member + unfiltered = tarinfo + try: + tarinfo = filter_function(tarinfo, path) + except (OSError, FilterError) as e: + self._handle_fatal_error(e) + except ExtractError as e: + self._handle_nonfatal_error(e) + if tarinfo is None: + self._dbg(2, "tarfile: Excluded %r" % unfiltered.name) + return None # Prepare the link target for makelink(). if tarinfo.islnk(): + tarinfo = copy.copy(tarinfo) tarinfo._link_target = os.path.join(path, tarinfo.linkname) + return tarinfo + + def _extract_one(self, tarinfo, path, set_attrs, numeric_owner): + """Extract from filtered tarinfo to disk""" + self._check("r") try: self._extract_member(tarinfo, os.path.join(path, tarinfo.name), set_attrs=set_attrs, numeric_owner=numeric_owner) except OSError as e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + self._handle_fatal_error(e) except ExtractError as e: - if self.errorlevel > 1: - raise + self._handle_nonfatal_error(e) + + def _handle_nonfatal_error(self, e): + """Handle non-fatal error (ExtractError) according to errorlevel""" + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def _handle_fatal_error(self, e): + """Handle "fatal" error according to self.errorlevel""" + if self.errorlevel > 0: + raise + elif isinstance(e, OSError): + if e.filename is None: + self._dbg(1, "tarfile: %s" % e.strerror) else: - self._dbg(1, "tarfile: %s" % e) + self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + else: + self._dbg(1, "tarfile: %s %s" % (type(e).__name__, e)) def extractfile(self, member): """Extract a member from the archive as a file object. `member' may be @@ -2199,9 +2429,13 @@ def makedir(self, tarinfo, targetpath): """Make a directory called targetpath. """ try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0o700) + if tarinfo.mode is None: + # Use the system's default mode + os.mkdir(targetpath) + else: + # Use a safe mode for the directory, the real mode is set + # later in _extract_member(). + os.mkdir(targetpath, 0o700) except FileExistsError: pass @@ -2244,6 +2478,9 @@ def makedev(self, tarinfo, targetpath): raise ExtractError("special devices not supported by system") mode = tarinfo.mode + if mode is None: + # Use mknod's default + mode = 0o600 if tarinfo.isblk(): mode |= stat.S_IFBLK else: @@ -2265,7 +2502,6 @@ def makelink(self, tarinfo, targetpath): os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: - # See extract(). if os.path.exists(tarinfo._link_target): os.link(tarinfo._link_target, targetpath) else: @@ -2290,15 +2526,19 @@ def chown(self, tarinfo, targetpath, numeric_owner): u = tarinfo.uid if not numeric_owner: try: - if grp: + if grp and tarinfo.gname: g = grp.getgrnam(tarinfo.gname)[2] except KeyError: pass try: - if pwd: + if pwd and tarinfo.uname: u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: pass + if g is None: + g = -1 + if u is None: + u = -1 try: if tarinfo.issym() and hasattr(os, "lchown"): os.lchown(targetpath, u, g) @@ -2310,6 +2550,8 @@ def chown(self, tarinfo, targetpath, numeric_owner): def chmod(self, tarinfo, targetpath): """Set file permissions of targetpath according to tarinfo. """ + if tarinfo.mode is None: + return try: os.chmod(targetpath, tarinfo.mode) except OSError as e: @@ -2318,10 +2560,13 @@ def chmod(self, tarinfo, targetpath): def utime(self, tarinfo, targetpath): """Set modification time of targetpath according to tarinfo. """ + mtime = tarinfo.mtime + if mtime is None: + return if not hasattr(os, 'utime'): return try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) + os.utime(targetpath, (mtime, mtime)) except OSError as e: raise ExtractError("could not change modification time") from e @@ -2397,13 +2642,26 @@ def _getmember(self, name, tarinfo=None, normalize=False): members = self.getmembers() # Limit the member search list up to tarinfo. + skipping = False if tarinfo is not None: - members = members[:members.index(tarinfo)] + try: + index = members.index(tarinfo) + except ValueError: + # The given starting point might be a (modified) copy. + # We'll later skip members until we find an equivalent. + skipping = True + else: + # Happy fast path + members = members[:index] if normalize: name = os.path.normpath(name) for member in reversed(members): + if skipping: + if tarinfo.offset == member.offset: + skipping = False + continue if normalize: member_name = os.path.normpath(member.name) else: @@ -2412,6 +2670,10 @@ def _getmember(self, name, tarinfo=None, normalize=False): if name == member_name: return member + if skipping: + # Starting point was not found + raise ValueError(tarinfo) + def _load(self): """Read through the entire archive file and look for readable members. @@ -2504,6 +2766,7 @@ def __exit__(self, type, value, traceback): #-------------------- # exported functions #-------------------- + def is_tarfile(name): """Return True if name points to a tar archive that we are able to handle, else return False. @@ -2530,6 +2793,10 @@ def main(): parser = argparse.ArgumentParser(description=description) parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose output') + parser.add_argument('--filter', metavar='<filtername>', + choices=_NAMED_FILTERS, + help='Filter for extraction') + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-l', '--list', metavar='<tarfile>', help='Show listing of a tarfile') @@ -2541,8 +2808,12 @@ def main(): help='Create tarfile from sources') group.add_argument('-t', '--test', metavar='<tarfile>', help='Test if a tarfile is valid') + args = parser.parse_args() + if args.filter and args.extract is None: + parser.exit(1, '--filter is only valid for extraction\n') + if args.test is not None: src = args.test if is_tarfile(src): @@ -2573,7 +2844,7 @@ def main(): if is_tarfile(src): with TarFile.open(src, 'r:*') as tf: - tf.extractall(path=curdir) + tf.extractall(path=curdir, filter=args.filter) if args.verbose: if curdir == '.': msg = '{!r} file is extracted.'.format(src) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 0935b60d4c26..72fb3afcbef5 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -32,6 +32,7 @@ from test import support from test.support import os_helper from test.support.os_helper import TESTFN, FakePath +from test.support import warnings_helper TESTFN2 = TESTFN + "2" TESTFN_SRC = TESTFN + "_SRC" @@ -1610,12 +1611,14 @@ def test_register_archive_format(self): ### shutil.unpack_archive - def check_unpack_archive(self, format): - self.check_unpack_archive_with_converter(format, lambda path: path) - self.check_unpack_archive_with_converter(format, pathlib.Path) - self.check_unpack_archive_with_converter(format, FakePath) + def check_unpack_archive(self, format, **kwargs): + self.check_unpack_archive_with_converter( + format, lambda path: path, **kwargs) + self.check_unpack_archive_with_converter( + format, pathlib.Path, **kwargs) + self.check_unpack_archive_with_converter(format, FakePath, **kwargs) - def check_unpack_archive_with_converter(self, format, converter): + def check_unpack_archive_with_converter(self, format, converter, **kwargs): root_dir, base_dir = self._create_files() expected = rlistdir(root_dir) expected.remove('outer') @@ -1625,36 +1628,47 @@ def check_unpack_archive_with_converter(self, format, converter): # let's try to unpack it now tmpdir2 = self.mkdtemp() - unpack_archive(converter(filename), converter(tmpdir2)) + unpack_archive(converter(filename), converter(tmpdir2), **kwargs) self.assertEqual(rlistdir(tmpdir2), expected) # and again, this time with the format specified tmpdir3 = self.mkdtemp() - unpack_archive(converter(filename), converter(tmpdir3), format=format) + unpack_archive(converter(filename), converter(tmpdir3), format=format, + **kwargs) self.assertEqual(rlistdir(tmpdir3), expected) - self.assertRaises(shutil.ReadError, unpack_archive, converter(TESTFN)) - self.assertRaises(ValueError, unpack_archive, converter(TESTFN), format='xxx') + with self.assertRaises(shutil.ReadError): + unpack_archive(converter(TESTFN), **kwargs) + with self.assertRaises(ValueError): + unpack_archive(converter(TESTFN), format='xxx', **kwargs) + + def check_unpack_tarball(self, format): + self.check_unpack_archive(format, filter='fully_trusted') + self.check_unpack_archive(format, filter='data') + with warnings_helper.check_no_warnings(self): + self.check_unpack_archive(format) def test_unpack_archive_tar(self): - self.check_unpack_archive('tar') + self.check_unpack_tarball('tar') @support.requires_zlib() def test_unpack_archive_gztar(self): - self.check_unpack_archive('gztar') + self.check_unpack_tarball('gztar') @support.requires_bz2() def test_unpack_archive_bztar(self): - self.check_unpack_archive('bztar') + self.check_unpack_tarball('bztar') @support.requires_lzma() @unittest.skipIf(AIX and not _maxdataOK(), "AIX MAXDATA must be 0x20000000 or larger") def test_unpack_archive_xztar(self): - self.check_unpack_archive('xztar') + self.check_unpack_tarball('xztar') @support.requires_zlib() def test_unpack_archive_zip(self): self.check_unpack_archive('zip') + with self.assertRaises(TypeError): + self.check_unpack_archive('zip', filter='data') def test_unpack_registry(self): diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 89f5a561b4aa..4bc32b71d15d 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -5,6 +5,10 @@ from contextlib import contextmanager from random import Random import pathlib +import shutil +import re +import warnings +import stat import unittest import unittest.mock @@ -13,6 +17,7 @@ from test import support from test.support import os_helper from test.support import script_helper +from test.support import warnings_helper # Check for our compression modules. try: @@ -108,7 +113,7 @@ def test_fileobj_regular_file(self): "regular file extraction failed") def test_fileobj_readlines(self): - self.tar.extract("ustar/regtype", TEMPDIR) + self.tar.extract("ustar/regtype", TEMPDIR, filter='data') tarinfo = self.tar.getmember("ustar/regtype") with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1: lines1 = fobj1.readlines() @@ -126,7 +131,7 @@ def test_fileobj_readlines(self): "fileobj.readlines() failed") def test_fileobj_iter(self): - self.tar.extract("ustar/regtype", TEMPDIR) + self.tar.extract("ustar/regtype", TEMPDIR, filter='data') tarinfo = self.tar.getmember("ustar/regtype") with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1: lines1 = fobj1.readlines() @@ -136,7 +141,8 @@ def test_fileobj_iter(self): "fileobj.__iter__() failed") def test_fileobj_seek(self): - self.tar.extract("ustar/regtype", TEMPDIR) + self.tar.extract("ustar/regtype", TEMPDIR, + filter='data') with open(os.path.join(TEMPDIR, "ustar/regtype"), "rb") as fobj: data = fobj.read() @@ -455,7 +461,7 @@ def test_premature_end_of_archive(self): t = tar.next() with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): - tar.extract(t, TEMPDIR) + tar.extract(t, TEMPDIR, filter='data') with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"): tar.extractfile(t).read() @@ -610,16 +616,16 @@ def test_find_members(self): def test_extract_hardlink(self): # Test hardlink extraction (e.g. bug #857297). with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar: - tar.extract("ustar/regtype", TEMPDIR) + tar.extract("ustar/regtype", TEMPDIR, filter='data') self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/regtype")) - tar.extract("ustar/lnktype", TEMPDIR) + tar.extract("ustar/lnktype", TEMPDIR, filter='data') self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/lnktype")) with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f: data = f.read() self.assertEqual(sha256sum(data), sha256_regtype) - tar.extract("ustar/symtype", TEMPDIR) + tar.extract("ustar/symtype", TEMPDIR, filter='data') self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/symtype")) with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f: data = f.read() @@ -633,13 +639,14 @@ def test_extractall(self): os.mkdir(DIR) try: directories = [t for t in tar if t.isdir()] - tar.extractall(DIR, directories) + tar.extractall(DIR, directories, filter='fully_trusted') for tarinfo in directories: path = os.path.join(DIR, tarinfo.name) if sys.platform != "win32": # Win32 has no support for fine grained permissions. self.assertEqual(tarinfo.mode & 0o777, - os.stat(path).st_mode & 0o777) + os.stat(path).st_mode & 0o777, + tarinfo.name) def format_mtime(mtime): if isinstance(mtime, float): return "{} ({})".format(mtime, mtime.hex()) @@ -662,7 +669,7 @@ def test_extract_directory(self): try: with tarfile.open(tarname, encoding="iso8859-1") as tar: tarinfo = tar.getmember(dirtype) - tar.extract(tarinfo, path=DIR) + tar.extract(tarinfo, path=DIR, filter='fully_trusted') extracted = os.path.join(DIR, dirtype) self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime) if sys.platform != "win32": @@ -675,7 +682,7 @@ def test_extractall_pathlike_name(self): with os_helper.temp_dir(DIR), \ tarfile.open(tarname, encoding="iso8859-1") as tar: directories = [t for t in tar if t.isdir()] - tar.extractall(DIR, directories) + tar.extractall(DIR, directories, filter='fully_trusted') for tarinfo in directories: path = DIR / tarinfo.name self.assertEqual(os.path.getmtime(path), tarinfo.mtime) @@ -686,7 +693,7 @@ def test_extract_pathlike_name(self): with os_helper.temp_dir(DIR), \ tarfile.open(tarname, encoding="iso8859-1") as tar: tarinfo = tar.getmember(dirtype) - tar.extract(tarinfo, path=DIR) + tar.extract(tarinfo, path=DIR, filter='fully_trusted') extracted = DIR / dirtype self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime) @@ -1042,7 +1049,7 @@ class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase): # an all platforms, and after that a test that will work only on # platforms/filesystems that prove to support sparse files. def _test_sparse_file(self, name): - self.tar.extract(name, TEMPDIR) + self.tar.extract(name, TEMPDIR, filter='data') filename = os.path.join(TEMPDIR, name) with open(filename, "rb") as fobj: data = fobj.read() @@ -1409,7 +1416,8 @@ def test_extractall_symlinks(self): with tarfile.open(temparchive, errorlevel=2) as tar: # this should not raise OSError: [Errno 17] File exists try: - tar.extractall(path=tempdir) + tar.extractall(path=tempdir, + filter='fully_trusted') except OSError: self.fail("extractall failed with symlinked files") finally: @@ -2406,7 +2414,12 @@ def test__all__(self): 'PAX_NUMBER_FIELDS', 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 'copyfileobj', 'filemode', 'EmptyHeaderError', 'TruncatedHeaderError', 'EOFHeaderError', 'InvalidHeaderError', - 'SubsequentHeaderError', 'ExFileObject', 'main'} + 'SubsequentHeaderError', 'ExFileObject', 'main', + "fully_trusted_filter", "data_filter", + "tar_filter", "FilterError", "AbsoluteLinkError", + "OutsideDestinationError", "SpecialFileError", "AbsolutePathError", + "LinkOutsideDestinationError", + } support.check__all__(self, tarfile, not_exported=not_exported) def test_useful_error_message_when_modules_missing(self): @@ -2441,6 +2454,15 @@ def make_simple_tarfile(self, tar_name): for tardata in files: tf.add(tardata, arcname=os.path.basename(tardata)) + def make_evil_tarfile(self, tar_name): + files = [support.findfile('tokenize_tests.txt')] + self.addCleanup(os_helper.unlink, tar_name) + with tarfile.open(tar_name, 'w') as tf: + benign = tarfile.TarInfo('benign') + tf.addfile(benign, fileobj=io.BytesIO(b'')) + evil = tarfile.TarInfo('../evil') + tf.addfile(evil, fileobj=io.BytesIO(b'')) + def test_bad_use(self): rc, out, err = self.tarfilecmd_failure() self.assertEqual(out, b'') @@ -2597,6 +2619,25 @@ def test_extract_command_verbose(self): finally: os_helper.rmtree(tarextdir) + def test_extract_command_filter(self): + self.make_evil_tarfile(tmpname) + # Make an inner directory, so the member named '../evil' + # is still extracted into `tarextdir` + destdir = os.path.join(tarextdir, 'dest') + os.mkdir(tarextdir) + try: + with os_helper.temp_cwd(destdir): + self.tarfilecmd_failure('-e', tmpname, + '-v', + '--filter', 'data') + out = self.tarfilecmd('-e', tmpname, + '-v', + '--filter', 'fully_trusted', + PYTHONIOENCODING='utf-8') + self.assertIn(b' file is extracted.', out) + finally: + os_helper.rmtree(tarextdir) + def test_extract_command_different_directory(self): self.make_simple_tarfile(tmpname) try: @@ -2680,7 +2721,7 @@ class LinkEmulationTest(ReadTest, unittest.TestCase): # symbolic or hard links tarfile tries to extract these types of members # as the regular files they point to. def _test_link_extraction(self, name): - self.tar.extract(name, TEMPDIR) + self.tar.extract(name, TEMPDIR, filter='fully_trusted') with open(os.path.join(TEMPDIR, name), "rb") as f: data = f.read() self.assertEqual(sha256sum(data), sha256_regtype) @@ -2812,8 +2853,10 @@ def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod, mock_chown): with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, filename_2): - tarfl.extract(filename_1, TEMPDIR, numeric_owner=True) - tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True) + tarfl.extract(filename_1, TEMPDIR, numeric_owner=True, + filter='fully_trusted') + tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True, + filter='fully_trusted') # convert to filesystem paths f_filename_1 = os.path.join(TEMPDIR, filename_1) @@ -2831,7 +2874,8 @@ def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod, mock_chown): with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1, filename_2): - tarfl.extractall(TEMPDIR, numeric_owner=True) + tarfl.extractall(TEMPDIR, numeric_owner=True, + filter='fully_trusted') # convert to filesystem paths f_filename_1 = os.path.join(TEMPDIR, filename_1) @@ -2856,7 +2900,8 @@ def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod, def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod, mock_chown): with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _): - tarfl.extract(filename_1, TEMPDIR, numeric_owner=False) + tarfl.extract(filename_1, TEMPDIR, numeric_owner=False, + filter='fully_trusted') # convert to filesystem paths f_filename_1 = os.path.join(TEMPDIR, filename_1) @@ -2870,6 +2915,893 @@ def test_keyword_only(self, mock_geteuid): tarfl.extract, filename_1, TEMPDIR, False, True) +class ReplaceTests(ReadTest, unittest.TestCase): + def test_replace_name(self): + member = self.tar.getmember('ustar/regtype') + replaced = member.replace(name='misc/other') + self.assertEqual(replaced.name, 'misc/other') + self.assertEqual(member.name, 'ustar/regtype') + self.assertEqual(self.tar.getmember('ustar/regtype').name, + 'ustar/regtype') + + def test_replace_deep(self): + member = self.tar.getmember('pax/regtype1') + replaced = member.replace() + replaced.pax_headers['gname'] = 'not-bar' + self.assertEqual(member.pax_headers['gname'], 'bar') + self.assertEqual( + self.tar.getmember('pax/regtype1').pax_headers['gname'], 'bar') + + def test_replace_shallow(self): + member = self.tar.getmember('pax/regtype1') + replaced = member.replace(deep=False) + replaced.pax_headers['gname'] = 'not-bar' + self.assertEqual(member.pax_headers['gname'], 'not-bar') + self.assertEqual( + self.tar.getmember('pax/regtype1').pax_headers['gname'], 'not-bar') + + def test_replace_all(self): + member = self.tar.getmember('ustar/regtype') + for attr_name in ('name', 'mtime', 'mode', 'linkname', + 'uid', 'gid', 'uname', 'gname'): + with self.subTest(attr_name=attr_name): + replaced = member.replace(**{attr_name: None}) + self.assertEqual(getattr(replaced, attr_name), None) + self.assertNotEqual(getattr(member, attr_name), None) + + def test_replace_internal(self): + member = self.tar.getmember('ustar/regtype') + with self.assertRaises(TypeError): + member.replace(offset=123456789) + + +class NoneInfoExtractTests(ReadTest): + # These mainly check that all kinds of members are extracted successfully + # if some metadata is None. + # Some of the methods do additional spot checks. + + # We also test that the default filters can deal with None. + + extraction_filter = None + + @classmethod + def setUpClass(cls): + tar = tarfile.open(tarname, mode='r', encoding="iso8859-1") + cls.control_dir = pathlib.Path(TEMPDIR) / "extractall_ctrl" + tar.errorlevel = 0 + tar.extractall(cls.control_dir, filter=cls.extraction_filter) + tar.close() + cls.control_paths = set( + p.relative_to(cls.control_dir) + for p in pathlib.Path(cls.control_dir).glob('**/*')) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.control_dir) + + def check_files_present(self, directory): + got_paths = set( + p.relative_to(directory) + for p in pathlib.Path(directory).glob('**/*')) + self.assertEqual(self.control_paths, got_paths) + + @contextmanager + def extract_with_none(self, *attr_names): + DIR = pathlib.Path(TEMPDIR) / "extractall_none" + self.tar.errorlevel = 0 + for member in self.tar.getmembers(): + for attr_name in attr_names: + setattr(member, attr_name, None) + with os_helper.temp_dir(DIR): + self.tar.extractall(DIR, filter='fully_trusted') + self.check_files_present(DIR) + yield DIR + + def test_extractall_none_mtime(self): + # mtimes of extracted files should be later than 'now' -- the mtime + # of a previously created directory. + now = pathlib.Path(TEMPDIR).stat().st_mtime + with self.extract_with_none('mtime') as DIR: + for path in pathlib.Path(DIR).glob('**/*'): + with self.subTest(path=path): + try: + mtime = path.stat().st_mtime + except OSError: + # Some systems can't stat symlinks, ignore those + if not path.is_symlink(): + raise + else: + self.assertGreaterEqual(path.stat().st_mtime, now) + + def test_extractall_none_mode(self): + # modes of directories and regular files should match the mode + # of a "normally" created directory or regular file + dir_mode = pathlib.Path(TEMPDIR).stat().st_mode + regular_file = pathlib.Path(TEMPDIR) / 'regular_file' + regular_file.write_text('') + regular_file_mode = regular_file.stat().st_mode + with self.extract_with_none('mode') as DIR: + for path in pathlib.Path(DIR).glob('**/*'): + with self.subTest(path=path): + if path.is_dir(): + self.assertEqual(path.stat().st_mode, dir_mode) + elif path.is_file(): + self.assertEqual(path.stat().st_mode, + regular_file_mode) + + def test_extractall_none_uid(self): + with self.extract_with_none('uid'): + pass + + def test_extractall_none_gid(self): + with self.extract_with_none('gid'): + pass + + def test_extractall_none_uname(self): + with self.extract_with_none('uname'): + pass + + def test_extractall_none_gname(self): + with self.extract_with_none('gname'): + pass + + def test_extractall_none_ownership(self): + with self.extract_with_none('uid', 'gid', 'uname', 'gname'): + pass + +class NoneInfoExtractTests_Data(NoneInfoExtractTests, unittest.TestCase): + extraction_filter = 'data' + +class NoneInfoExtractTests_FullyTrusted(NoneInfoExtractTests, + unittest.TestCase): + extraction_filter = 'fully_trusted' + +class NoneInfoExtractTests_Tar(NoneInfoExtractTests, unittest.TestCase): + extraction_filter = 'tar' + +class NoneInfoExtractTests_Default(NoneInfoExtractTests, + unittest.TestCase): + extraction_filter = None + +class NoneInfoTests_Misc(unittest.TestCase): + def test_add(self): + # When addfile() encounters None metadata, it raises a ValueError + bio = io.BytesIO() + for tarformat in (tarfile.USTAR_FORMAT, tarfile.GNU_FORMAT, + tarfile.PAX_FORMAT): + with self.subTest(tarformat=tarformat): + tar = tarfile.open(fileobj=bio, mode='w', format=tarformat) + tarinfo = tar.gettarinfo(tarname) + try: + tar.addfile(tarinfo) + except Exception: + if tarformat == tarfile.USTAR_FORMAT: + # In the old, limited format, adding might fail for + # reasons like the UID being too large + pass + else: + raise + else: + for attr_name in ('mtime', 'mode', 'uid', 'gid', + 'uname', 'gname'): + with self.subTest(attr_name=attr_name): + replaced = tarinfo.replace(**{attr_name: None}) + with self.assertRaisesRegex(ValueError, + f"{attr_name}"): + tar.addfile(replaced) + + def test_list(self): + # Change some metadata to None, then compare list() output + # word-for-word. We want list() to not raise, and to only change + # printout for the affected piece of metadata. + # (n.b.: some contents of the test archive are hardcoded.) + for attr_names in ({'mtime'}, {'mode'}, {'uid'}, {'gid'}, + {'uname'}, {'gname'}, + {'uid', 'uname'}, {'gid', 'gname'}): + with (self.subTest(attr_names=attr_names), + tarfile.open(tarname, encoding="iso8859-1") as tar): + tio_prev = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') + with support.swap_attr(sys, 'stdout', tio_prev): + tar.list() + for member in tar.getmembers(): + for attr_name in attr_names: + setattr(member, attr_name, None) + tio_new = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') + with support.swap_attr(sys, 'stdout', tio_new): + tar.list() + for expected, got in zip(tio_prev.detach().getvalue().split(), + tio_new.detach().getvalue().split()): + if attr_names == {'mtime'} and re.match(rb'2003-01-\d\d', expected): + self.assertEqual(got, b'????-??-??') + elif attr_names == {'mtime'} and re.match(rb'\d\d:\d\d:\d\d', expected): + self.assertEqual(got, b'??:??:??') + elif attr_names == {'mode'} and re.match( + rb'.([r-][w-][x-]){3}', expected): + self.assertEqual(got, b'??????????') + elif attr_names == {'uname'} and expected.startswith( + (b'tarfile/', b'lars/', b'foo/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertRegex(got_user, b'[0-9]+') + elif attr_names == {'gname'} and expected.endswith( + (b'/tarfile', b'/users', b'/bar')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertRegex(got_group, b'[0-9]+') + elif attr_names == {'uid'} and expected.startswith( + (b'1000/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertEqual(got_user, b'None') + elif attr_names == {'gid'} and expected.endswith((b'/100')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertEqual(got_group, b'None') + elif attr_names == {'uid', 'uname'} and expected.startswith( + (b'tarfile/', b'lars/', b'foo/', b'1000/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertEqual(got_user, b'None') + elif attr_names == {'gname', 'gid'} and expected.endswith( + (b'/tarfile', b'/users', b'/bar', b'/100')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertEqual(got_group, b'None') + else: + # In other cases the output should be the same + self.assertEqual(expected, got) + +def _filemode_to_int(mode): + """Inverse of `stat.filemode` (for permission bits) + + Using mode strings rather than numbers makes the later tests more readable. + """ + str_mode = mode[1:] + result = ( + {'r': stat.S_IRUSR, '-': 0}[str_mode[0]] + | {'w': stat.S_IWUSR, '-': 0}[str_mode[1]] + | {'x': stat.S_IXUSR, '-': 0, + 's': stat.S_IXUSR | stat.S_ISUID, + 'S': stat.S_ISUID}[str_mode[2]] + | {'r': stat.S_IRGRP, '-': 0}[str_mode[3]] + | {'w': stat.S_IWGRP, '-': 0}[str_mode[4]] + | {'x': stat.S_IXGRP, '-': 0, + 's': stat.S_IXGRP | stat.S_ISGID, + 'S': stat.S_ISGID}[str_mode[5]] + | {'r': stat.S_IROTH, '-': 0}[str_mode[6]] + | {'w': stat.S_IWOTH, '-': 0}[str_mode[7]] + | {'x': stat.S_IXOTH, '-': 0, + 't': stat.S_IXOTH | stat.S_ISVTX, + 'T': stat.S_ISVTX}[str_mode[8]] + ) + # check we did this right + assert stat.filemode(result)[1:] == mode[1:] + + return result + +class ArchiveMaker: + """Helper to create a tar file with specific contents + + Usage: + + with ArchiveMaker() as t: + t.add('filename', ...) + + with t.open() as tar: + ... # `tar` is now a TarFile with 'filename' in it! + """ + def __init__(self): + self.bio = io.BytesIO() + + def __enter__(self): + self.tar_w = tarfile.TarFile(mode='w', fileobj=self.bio) + return self + + def __exit__(self, *exc): + self.tar_w.close() + self.contents = self.bio.getvalue() + self.bio = None + + def add(self, name, *, type=None, symlink_to=None, hardlink_to=None, + mode=None, **kwargs): + """Add a member to the test archive. Call within `with`.""" + name = str(name) + tarinfo = tarfile.TarInfo(name).replace(**kwargs) + if mode: + tarinfo.mode = _filemode_to_int(mode) + if symlink_to is not None: + type = tarfile.SYMTYPE + tarinfo.linkname = str(symlink_to) + if hardlink_to is not None: + type = tarfile.LNKTYPE + tarinfo.linkname = str(hardlink_to) + if name.endswith('/') and type is None: + type = tarfile.DIRTYPE + if type is not None: + tarinfo.type = type + if tarinfo.isreg(): + fileobj = io.BytesIO(bytes(tarinfo.size)) + else: + fileobj = None + self.tar_w.addfile(tarinfo, fileobj) + + def open(self, **kwargs): + """Open the resulting archive as TarFile. Call after `with`.""" + bio = io.BytesIO(self.contents) + return tarfile.open(fileobj=bio, **kwargs) + + +class TestExtractionFilters(unittest.TestCase): + + # A temporary directory for the extraction results. + # All files that "escape" the destination path should still end + # up in this directory. + outerdir = pathlib.Path(TEMPDIR) / 'outerdir' + + # The destination for the extraction, within `outerdir` + destdir = outerdir / 'dest' + + @contextmanager + def check_context(self, tar, filter): + """Extracts `tar` to `self.destdir` and allows checking the result + + If an error occurs, it must be checked using `expect_exception` + + Otherwise, all resulting files must be checked using `expect_file`, + except the destination directory itself and parent directories of + other files. + When checking directories, do so before their contents. + """ + with os_helper.temp_dir(self.outerdir): + try: + tar.extractall(self.destdir, filter=filter) + except Exception as exc: + self.raised_exception = exc + self.expected_paths = set() + else: + self.raised_exception = None + self.expected_paths = set(self.outerdir.glob('**/*')) + self.expected_paths.discard(self.destdir) + try: + yield + finally: + tar.close() + if self.raised_exception: + raise self.raised_exception + self.assertEqual(self.expected_paths, set()) + + def expect_file(self, name, type=None, symlink_to=None, mode=None): + """Check a single file. See check_context.""" + if self.raised_exception: + raise self.raised_exception + # use normpath() rather than resolve() so we don't follow symlinks + path = pathlib.Path(os.path.normpath(self.destdir / name)) + self.assertIn(path, self.expected_paths) + self.expected_paths.remove(path) + + # When checking mode, ignore Windows (which can only set user read and + # user write bits). Newer versions of Python use `os_helper.can_chmod()` + # instead of hardcoding Windows. + if mode is not None and sys.platform != 'win32': + got = stat.filemode(stat.S_IMODE(path.stat().st_mode)) + self.assertEqual(got, mode) + + if type is None and isinstance(name, str) and name.endswith('/'): + type = tarfile.DIRTYPE + if symlink_to is not None: + got = (self.destdir / name).readlink() + expected = pathlib.Path(symlink_to) + # The symlink might be the same (textually) as what we expect, + # but some systems change the link to an equivalent path, so + # we fall back to samefile(). + if expected != got: + self.assertTrue(got.samefile(expected)) + elif type == tarfile.REGTYPE or type is None: + self.assertTrue(path.is_file()) + elif type == tarfile.DIRTYPE: + self.assertTrue(path.is_dir()) + elif type == tarfile.FIFOTYPE: + self.assertTrue(path.is_fifo()) + else: + raise NotImplementedError(type) + for parent in path.parents: + self.expected_paths.discard(parent) + + def expect_exception(self, exc_type, message_re='.'): + with self.assertRaisesRegex(exc_type, message_re): + if self.raised_exception is not None: + raise self.raised_exception + self.raised_exception = None + + def test_benign_file(self): + with ArchiveMaker() as arc: + arc.add('benign.txt') + for filter in 'fully_trusted', 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_file('benign.txt') + + def test_absolute(self): + # Test handling a member with an absolute path + # Inspired by 'absolute1' in https://github.com/jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add(self.outerdir / 'escaped.evil') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('../escaped.evil') + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + if str(self.outerdir).startswith('/'): + # We strip leading slashes, as e.g. GNU tar does + # (without --absolute-filenames). + outerdir_stripped = str(self.outerdir).lstrip('/') + self.expect_file(f'{outerdir_stripped}/escaped.evil') + else: + # On this system, absolute paths don't have leading + # slashes. + # So, there's nothing to strip. We refuse to unpack + # to an absolute path, nonetheless. + self.expect_exception( + tarfile.AbsolutePathError, + """['"].*escaped.evil['"] has an absolute path""") + + def test_parent_symlink(self): + # Test interplaying symlinks + # Inspired by 'dirsymlink2a' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('current', symlink_to='.') + arc.add('parent', symlink_to='current/..') + arc.add('parent/evil') + + if os_helper.can_symlink(): + with self.check_context(arc.open(), 'fully_trusted'): + if self.raised_exception is not None: + # Windows will refuse to create a file that's a symlink to itself + # (and tarfile doesn't swallow that exception) + self.expect_exception(FileExistsError) + # The other cases will fail with this error too. + # Skip the rest of this test. + return + else: + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='current/..') + self.expect_file('../evil') + + with self.check_context(arc.open(), 'tar'): + self.expect_exception( + tarfile.OutsideDestinationError, + """'parent/evil' would be extracted to ['"].*evil['"], """ + + "which is outside the destination") + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'parent' would link to ['"].*outerdir['"], """ + + "which is outside the destination") + + else: + # No symlink support. The symlinks are ignored. + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('parent/evil') + with self.check_context(arc.open(), 'tar'): + self.expect_file('parent/evil') + with self.check_context(arc.open(), 'data'): + self.expect_file('parent/evil') + + def test_parent_symlink2(self): + # Test interplaying symlinks + # Inspired by 'dirsymlink2b' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('current', symlink_to='.') + arc.add('current/parent', symlink_to='..') + arc.add('parent/evil') + + with self.check_context(arc.open(), 'fully_trusted'): + if os_helper.can_symlink(): + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='..') + self.expect_file('../evil') + else: + self.expect_file('current/') + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'tar'): + if os_helper.can_symlink(): + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + self.expect_file('current/') + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'current/parent' would link to ['"].*['"], """ + + "which is outside the destination") + + def test_absolute_symlink(self): + # Test symlink to an absolute path + # Inspired by 'dirsymlink' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('parent', symlink_to=self.outerdir) + arc.add('parent/evil') + + with self.check_context(arc.open(), 'fully_trusted'): + if os_helper.can_symlink(): + self.expect_file('parent', symlink_to=self.outerdir) + self.expect_file('../evil') + else: + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'tar'): + if os_helper.can_symlink(): + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.AbsoluteLinkError, + "'parent' is a symlink to an absolute path") + + def test_sly_relative0(self): + # Inspired by 'relative0' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('../moo', symlink_to='..//tmp/moo') + + try: + with self.check_context(arc.open(), filter='fully_trusted'): + if os_helper.can_symlink(): + if isinstance(self.raised_exception, FileExistsError): + # XXX TarFile happens to fail creating a parent + # directory. + # This might be a bug, but fixing it would hurt + # security. + # Note that e.g. GNU `tar` rejects '..' components, + # so you could argue this is an invalid archive and we + # just raise an bad type of exception. + self.expect_exception(FileExistsError) + else: + self.expect_file('../moo', symlink_to='..//tmp/moo') + else: + # The symlink can't be extracted and is ignored + pass + except FileExistsError: + pass + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_exception( + tarfile.OutsideDestinationError, + "'../moo' would be extracted to " + + "'.*moo', which is outside " + + "the destination") + + def test_sly_relative2(self): + # Inspired by 'relative2' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('tmp/') + arc.add('tmp/../../moo', symlink_to='tmp/../..//tmp/moo') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('tmp', type=tarfile.DIRTYPE) + if os_helper.can_symlink(): + self.expect_file('../moo', symlink_to='tmp/../../tmp/moo') + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_exception( + tarfile.OutsideDestinationError, + "'tmp/../../moo' would be extracted to " + + """['"].*moo['"], which is outside the """ + + "destination") + + def test_modes(self): + # Test how file modes are extracted + # (Note that the modes are ignored on platforms without working chmod) + with ArchiveMaker() as arc: + arc.add('all_bits', mode='?rwsrwsrwt') + arc.add('perm_bits', mode='?rwxrwxrwx') + arc.add('exec_group_other', mode='?rw-rwxrwx') + arc.add('read_group_only', mode='?---r-----') + arc.add('no_bits', mode='?---------') + arc.add('dir/', mode='?---rwsrwt') + + # On some systems, setting the sticky bit is a no-op. + # Check if that's the case. + tmp_filename = os.path.join(TEMPDIR, "tmp.file") + with open(tmp_filename, 'w'): + pass + os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) + have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + os.unlink(tmp_filename) + + os.mkdir(tmp_filename) + os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) + have_sticky_dirs = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + os.rmdir(tmp_filename) + + with self.check_context(arc.open(), 'fully_trusted'): + if have_sticky_files: + self.expect_file('all_bits', mode='?rwsrwsrwt') + else: + self.expect_file('all_bits', mode='?rwsrwsrwx') + self.expect_file('perm_bits', mode='?rwxrwxrwx') + self.expect_file('exec_group_other', mode='?rw-rwxrwx') + self.expect_file('read_group_only', mode='?---r-----') + self.expect_file('no_bits', mode='?---------') + if have_sticky_dirs: + self.expect_file('dir/', mode='?---rwsrwt') + else: + self.expect_file('dir/', mode='?---rwsrwx') + + with self.check_context(arc.open(), 'tar'): + self.expect_file('all_bits', mode='?rwxr-xr-x') + self.expect_file('perm_bits', mode='?rwxr-xr-x') + self.expect_file('exec_group_other', mode='?rw-r-xr-x') + self.expect_file('read_group_only', mode='?---r-----') + self.expect_file('no_bits', mode='?---------') + self.expect_file('dir/', mode='?---r-xr-x') + + with self.check_context(arc.open(), 'data'): + normal_dir_mode = stat.filemode(stat.S_IMODE( + self.outerdir.stat().st_mode)) + self.expect_file('all_bits', mode='?rwxr-xr-x') + self.expect_file('perm_bits', mode='?rwxr-xr-x') + self.expect_file('exec_group_other', mode='?rw-r--r--') + self.expect_file('read_group_only', mode='?rw-r-----') + self.expect_file('no_bits', mode='?rw-------') + self.expect_file('dir/', mode=normal_dir_mode) + + def test_pipe(self): + # Test handling of a special file + with ArchiveMaker() as arc: + arc.add('foo', type=tarfile.FIFOTYPE) + + for filter in 'fully_trusted', 'tar': + with self.check_context(arc.open(), filter): + if hasattr(os, 'mkfifo'): + self.expect_file('foo', type=tarfile.FIFOTYPE) + else: + # The pipe can't be extracted and is skipped. + pass + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.SpecialFileError, + "'foo' is a special file") + + def test_special_files(self): + # Creating device files is tricky. Instead of attempting that let's + # only check the filter result. + for special_type in tarfile.FIFOTYPE, tarfile.CHRTYPE, tarfile.BLKTYPE: + tarinfo = tarfile.TarInfo('foo') + tarinfo.type = special_type + trusted = tarfile.fully_trusted_filter(tarinfo, '') + self.assertIs(trusted, tarinfo) + tar = tarfile.tar_filter(tarinfo, '') + self.assertEqual(tar.type, special_type) + with self.assertRaises(tarfile.SpecialFileError) as cm: + tarfile.data_filter(tarinfo, '') + self.assertIsInstance(cm.exception.tarinfo, tarfile.TarInfo) + self.assertEqual(cm.exception.tarinfo.name, 'foo') + + def test_fully_trusted_filter(self): + # The 'fully_trusted' filter returns the original TarInfo objects. + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + filtered = tarfile.fully_trusted_filter(tarinfo, '') + self.assertIs(filtered, tarinfo) + + def test_tar_filter(self): + # The 'tar' filter returns TarInfo objects with the same name/type. + # (It can also fail for particularly "evil" input, but we don't have + # that in the test archive.) + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + filtered = tarfile.tar_filter(tarinfo, '') + self.assertIs(filtered.name, tarinfo.name) + self.assertIs(filtered.type, tarinfo.type) + + def test_data_filter(self): + # The 'data' filter either raises, or returns TarInfo with the same + # name/type. + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + try: + filtered = tarfile.data_filter(tarinfo, '') + except tarfile.FilterError: + continue + self.assertIs(filtered.name, tarinfo.name) + self.assertIs(filtered.type, tarinfo.type) + + def test_default_filter_warns_not(self): + """Ensure the default filter does not warn (like in 3.12)""" + with ArchiveMaker() as arc: + arc.add('foo') + with warnings_helper.check_no_warnings(self): + with self.check_context(arc.open(), None): + self.expect_file('foo') + + def test_change_default_filter_on_instance(self): + tar = tarfile.TarFile(tarname, 'r') + def strict_filter(tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + tar.extraction_filter = strict_filter + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_on_class(self): + def strict_filter(tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + tar = tarfile.TarFile(tarname, 'r') + with support.swap_attr(tarfile.TarFile, 'extraction_filter', + staticmethod(strict_filter)): + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_on_subclass(self): + class TarSubclass(tarfile.TarFile): + def extraction_filter(self, tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + + tar = TarSubclass(tarname, 'r') + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_to_string(self): + tar = tarfile.TarFile(tarname, 'r') + tar.extraction_filter = 'data' + with self.check_context(tar, None): + self.expect_exception(TypeError) + + def test_custom_filter(self): + def custom_filter(tarinfo, path): + self.assertIs(path, self.destdir) + if tarinfo.name == 'move_this': + return tarinfo.replace(name='moved') + if tarinfo.name == 'ignore_this': + return None + return tarinfo + + with ArchiveMaker() as arc: + arc.add('move_this') + arc.add('ignore_this') + arc.add('keep') + with self.check_context(arc.open(), custom_filter): + self.expect_file('moved') + self.expect_file('keep') + + def test_bad_filter_name(self): + with ArchiveMaker() as arc: + arc.add('foo') + with self.check_context(arc.open(), 'bad filter name'): + self.expect_exception(ValueError) + + def test_stateful_filter(self): + # Stateful filters should be possible. + # (This doesn't really test tarfile. Rather, it demonstrates + # that third parties can implement a stateful filter.) + class StatefulFilter: + def __enter__(self): + self.num_files_processed = 0 + return self + + def __call__(self, tarinfo, path): + try: + tarinfo = tarfile.data_filter(tarinfo, path) + except tarfile.FilterError: + return None + self.num_files_processed += 1 + return tarinfo + + def __exit__(self, *exc_info): + self.done = True + + with ArchiveMaker() as arc: + arc.add('good') + arc.add('bad', symlink_to='/') + arc.add('good') + with StatefulFilter() as custom_filter: + with self.check_context(arc.open(), custom_filter): + self.expect_file('good') + self.assertEqual(custom_filter.num_files_processed, 2) + self.assertEqual(custom_filter.done, True) + + def test_errorlevel(self): + def extracterror_filter(tarinfo, path): + raise tarfile.ExtractError('failed with ExtractError') + def filtererror_filter(tarinfo, path): + raise tarfile.FilterError('failed with FilterError') + def oserror_filter(tarinfo, path): + raise OSError('failed with OSError') + def tarerror_filter(tarinfo, path): + raise tarfile.TarError('failed with base TarError') + def valueerror_filter(tarinfo, path): + raise ValueError('failed with ValueError') + + with ArchiveMaker() as arc: + arc.add('file') + + # If errorlevel is 0, errors affected by errorlevel are ignored + + with self.check_context(arc.open(errorlevel=0), extracterror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), filtererror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), oserror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=0), valueerror_filter): + self.expect_exception(ValueError) + + # If 1, all fatal errors are raised + + with self.check_context(arc.open(errorlevel=1), extracterror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=1), filtererror_filter): + self.expect_exception(tarfile.FilterError) + + with self.check_context(arc.open(errorlevel=1), oserror_filter): + self.expect_exception(OSError) + + with self.check_context(arc.open(errorlevel=1), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=1), valueerror_filter): + self.expect_exception(ValueError) + + # If 2, all non-fatal errors are raised as well. + + with self.check_context(arc.open(errorlevel=2), extracterror_filter): + self.expect_exception(tarfile.ExtractError) + + with self.check_context(arc.open(errorlevel=2), filtererror_filter): + self.expect_exception(tarfile.FilterError) + + with self.check_context(arc.open(errorlevel=2), oserror_filter): + self.expect_exception(OSError) + + with self.check_context(arc.open(errorlevel=2), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=2), valueerror_filter): + self.expect_exception(ValueError) + + # We only handle ExtractionError, FilterError & OSError specially. + + with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter): + self.expect_exception(TypeError) # errorlevel is not int + + def setUpModule(): os_helper.unlink(TEMPDIR) os.makedirs(TEMPDIR) diff --git a/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst new file mode 100644 index 000000000000..48a105a4a17b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst @@ -0,0 +1,4 @@ +The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, +have a new a *filter* argument that allows limiting tar features than may be +surprising or dangerous, such as creating files outside the destination +directory. See :ref:`tarfile-extraction-filter` for details. From webhook-mailer at python.org Wed May 10 09:29:23 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 10 May 2023 13:29:23 -0000 Subject: [Python-checkins] gh-104252: Immortalize Py_EMPTY_KEYS (gh-104253) Message-ID: <mailman.287.1683725365.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b8f7ab5783b370004757af5a4c6e70c63dc5fe7a commit: b8f7ab5783b370004757af5a4c6e70c63dc5fe7a branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-10T07:28:40-06:00 summary: gh-104252: Immortalize Py_EMPTY_KEYS (gh-104253) This was missed in gh-19474. It matters for with a per-interpreter GIL since PyDictKeysObject.dk_refcnt breaks isolation and leads to races. files: M Include/internal/pycore_dict_state.h M Include/internal/pycore_runtime_init.h M Objects/dictobject.c diff --git a/Include/internal/pycore_dict_state.h b/Include/internal/pycore_dict_state.h index d608088ed2d7..ece0f10ca251 100644 --- a/Include/internal/pycore_dict_state.h +++ b/Include/internal/pycore_dict_state.h @@ -38,6 +38,11 @@ struct _Py_dict_state { PyDict_WatchCallback watchers[DICT_MAX_WATCHERS]; }; +#define _dict_state_INIT \ + { \ + .next_keys_version = 2, \ + } + #ifdef __cplusplus } diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index a48461c07428..3b1444f3429b 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -107,9 +107,7 @@ extern PyTypeObject _PyExc_MemoryError; }, \ }, \ .dtoa = _dtoa_state_INIT(&(INTERP)), \ - .dict_state = { \ - .next_keys_version = 2, \ - }, \ + .dict_state = _dict_state_INIT, \ .func_state = { \ .next_version = 1, \ }, \ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 2ef520044340..7436c113f37c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -300,9 +300,19 @@ _PyDict_DebugMallocStats(FILE *out) static void free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys); +/* PyDictKeysObject has refcounts like PyObject does, so we have the + following two functions to mirror what Py_INCREF() and Py_DECREF() do. + (Keep in mind that PyDictKeysObject isn't actually a PyObject.) + Likewise a PyDictKeysObject can be immortal (e.g. Py_EMPTY_KEYS), + so we apply a naive version of what Py_INCREF() and Py_DECREF() do + for immortal objects. */ + static inline void dictkeys_incref(PyDictKeysObject *dk) { + if (dk->dk_refcnt == _Py_IMMORTAL_REFCNT) { + return; + } #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); #endif @@ -312,6 +322,9 @@ dictkeys_incref(PyDictKeysObject *dk) static inline void dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) { + if (dk->dk_refcnt == _Py_IMMORTAL_REFCNT) { + return; + } assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG _Py_DecRefTotal(_PyInterpreterState_GET()); @@ -447,7 +460,7 @@ estimate_log2_keysize(Py_ssize_t n) * (which cannot fail and thus can do no allocation). */ static PyDictKeysObject empty_keys_struct = { - 1, /* dk_refcnt */ + _Py_IMMORTAL_REFCNT, /* dk_refcnt */ 0, /* dk_log2_size */ 0, /* dk_log2_index_bytes */ DICT_KEYS_UNICODE, /* dk_kind */ @@ -779,6 +792,7 @@ clone_combined_dict_keys(PyDictObject *orig) assert(PyDict_Check(orig)); assert(Py_TYPE(orig)->tp_iter == (getiterfunc)dict_iter); assert(orig->ma_values == NULL); + assert(orig->ma_keys != Py_EMPTY_KEYS); assert(orig->ma_keys->dk_refcnt == 1); size_t keys_size = _PyDict_KeysSize(orig->ma_keys); @@ -833,7 +847,7 @@ PyObject * PyDict_New(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); - dictkeys_incref(Py_EMPTY_KEYS); + /* We don't incref Py_EMPTY_KEYS here because it is immortal. */ return new_dict(interp, Py_EMPTY_KEYS, NULL, 0, 0); } @@ -1331,7 +1345,7 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp, Py_DECREF(value); return -1; } - dictkeys_decref(interp, Py_EMPTY_KEYS); + /* We don't decref Py_EMPTY_KEYS here because it is immortal. */ mp->ma_keys = newkeys; mp->ma_values = NULL; @@ -1529,14 +1543,10 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp, // We can not use free_keys_object here because key's reference // are moved already. + if (oldkeys != Py_EMPTY_KEYS) { #ifdef Py_REF_DEBUG - _Py_DecRefTotal(_PyInterpreterState_GET()); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif - if (oldkeys == Py_EMPTY_KEYS) { - oldkeys->dk_refcnt--; - assert(oldkeys->dk_refcnt > 0); - } - else { assert(oldkeys->dk_kind != DICT_KEYS_SPLIT); assert(oldkeys->dk_refcnt == 1); #if PyDict_MAXFREELIST > 0 @@ -2080,8 +2090,8 @@ PyDict_Clear(PyObject *op) dictkeys_decref(interp, oldkeys); } else { - assert(oldkeys->dk_refcnt == 1); - dictkeys_decref(interp, oldkeys); + assert(oldkeys->dk_refcnt == 1); + dictkeys_decref(interp, oldkeys); } ASSERT_CONSISTENT(mp); } From webhook-mailer at python.org Wed May 10 09:46:45 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 10 May 2023 13:46:45 -0000 Subject: [Python-checkins] gh-103960: Dark mode: invert image brightness (#103983) Message-ID: <mailman.288.1683726406.13550.python-checkins@python.org> https://github.com/python/cpython/commit/13ac1766bca7969a6c142c9176db901dd29c3519 commit: 13ac1766bca7969a6c142c9176db901dd29c3519 branch: main author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-10T16:46:37+03:00 summary: gh-103960: Dark mode: invert image brightness (#103983) files: M Doc/howto/logging.rst M Doc/library/hashlib.rst M Doc/library/pathlib.rst diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index 145449b2dfbd..a72e9a820ef3 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -418,6 +418,7 @@ The flow of log event information in loggers and handlers is illustrated in the following diagram. .. image:: logging_flow.png + :class: invert-in-dark-mode Loggers ^^^^^^^ diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index 6275f96f7d4d..797870b9d7e2 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -430,6 +430,7 @@ Constructor functions also accept the following tree hashing parameters: .. figure:: hashlib-blake2-tree.png :alt: Explanation of tree mode parameters. + :class: invert-in-dark-mode See section 2.10 in `BLAKE2 specification <https://www.blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 5ffa33d4e61f..93af07ae5ac1 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -21,6 +21,7 @@ inherit from pure paths but also provide I/O operations. .. image:: pathlib-inheritance.png :align: center + :class: invert-in-dark-mode If you've never used this module before or just aren't sure which class is right for your task, :class:`Path` is most likely what you need. It instantiates From webhook-mailer at python.org Wed May 10 10:19:45 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 10 May 2023 14:19:45 -0000 Subject: [Python-checkins] [3.11] gh-103960: Dark mode: invert image brightness (GH-103983) (#104358) Message-ID: <mailman.289.1683728386.13550.python-checkins@python.org> https://github.com/python/cpython/commit/03abac239cbd94962e44a5ae06ff583de6917f80 commit: 03abac239cbd94962e44a5ae06ff583de6917f80 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-10T14:19:38Z summary: [3.11] gh-103960: Dark mode: invert image brightness (GH-103983) (#104358) Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> files: M Doc/howto/logging.rst M Doc/library/hashlib.rst M Doc/library/pathlib.rst diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst index e2cf1b4fc392..f3ed98fd85a0 100644 --- a/Doc/howto/logging.rst +++ b/Doc/howto/logging.rst @@ -415,6 +415,7 @@ The flow of log event information in loggers and handlers is illustrated in the following diagram. .. image:: logging_flow.png + :class: invert-in-dark-mode Loggers ^^^^^^^ diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst index bea862d7967c..034b23c5364c 100644 --- a/Doc/library/hashlib.rst +++ b/Doc/library/hashlib.rst @@ -436,6 +436,7 @@ Constructor functions also accept the following tree hashing parameters: .. figure:: hashlib-blake2-tree.png :alt: Explanation of tree mode parameters. + :class: invert-in-dark-mode See section 2.10 in `BLAKE2 specification <https://www.blake2.net/blake2_20130129.pdf>`_ for comprehensive review of tree diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index abdeea248a31..974ab424a57f 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -21,6 +21,7 @@ inherit from pure paths but also provide I/O operations. .. image:: pathlib-inheritance.png :align: center + :class: invert-in-dark-mode If you've never used this module before or just aren't sure which class is right for your task, :class:`Path` is most likely what you need. It instantiates From webhook-mailer at python.org Wed May 10 10:23:08 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 10 May 2023 14:23:08 -0000 Subject: [Python-checkins] gh-101819: Adapt _io._BufferedIOBase_Type methods to Argument Clinic (#104355) Message-ID: <mailman.290.1683728588.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ce8d3db25660b029fa589a2072f4daf2a8723c50 commit: ce8d3db25660b029fa589a2072f4daf2a8723c50 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-10T16:22:55+02:00 summary: gh-101819: Adapt _io._BufferedIOBase_Type methods to Argument Clinic (#104355) Make sure the defining class is passed to all methods, so we can easily fetch module state from them in the future. files: M Modules/_io/bufferedio.c M Modules/_io/clinic/bufferedio.c.h diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 172fafe6db8a..c7ae60281c2f 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -115,6 +115,9 @@ bufferediobase_unsupported(_PyIO_State *state, const char *message) /*[clinic input] _io._BufferedIOBase.detach + cls: defining_class + / + Disconnect this buffer from its underlying raw stream and return it. After the raw stream has been detached, the buffer is in an unusable @@ -122,63 +125,89 @@ state. [clinic start generated code]*/ static PyObject * -_io__BufferedIOBase_detach_impl(PyObject *self) -/*[clinic end generated code: output=754977c8d10ed88c input=822427fb58fe4169]*/ +_io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=b87b135d67cd4448 input=0b61a7b4357c1ea7]*/ { _PyIO_State *state = IO_STATE(); return bufferediobase_unsupported(state, "detach"); } -PyDoc_STRVAR(bufferediobase_read_doc, - "Read and return up to n bytes.\n" - "\n" - "If the argument is omitted, None, or negative, reads and\n" - "returns all data until EOF.\n" - "\n" - "If the argument is positive, and the underlying raw stream is\n" - "not 'interactive', multiple raw reads may be issued to satisfy\n" - "the byte count (unless EOF is reached first). But for\n" - "interactive raw streams (as well as sockets and pipes), at most\n" - "one raw read will be issued, and a short result does not imply\n" - "that EOF is imminent.\n" - "\n" - "Returns an empty bytes object on EOF.\n" - "\n" - "Returns None if the underlying raw stream was open in non-blocking\n" - "mode and no data is available at the moment.\n"); +/*[clinic input] +_io._BufferedIOBase.read + + cls: defining_class + / + *args: object + +Read and return up to n bytes. + +If the argument is omitted, None, or negative, read and +return all data until EOF. + +If the argument is positive, and the underlying raw stream is +not 'interactive', multiple raw reads may be issued to satisfy +the byte count (unless EOF is reached first). +However, for interactive raw streams (as well as sockets and pipes), +at most one raw read will be issued, and a short result does not +imply that EOF is imminent. + +Return an empty bytes object on EOF. + +Return None if the underlying raw stream was open in non-blocking +mode and no data is available at the moment. +[clinic start generated code]*/ static PyObject * -bufferediobase_read(PyObject *self, PyObject *args) +_io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=4521b30940fd7b67 input=390205758adc8510]*/ { _PyIO_State *state = IO_STATE(); return bufferediobase_unsupported(state, "read"); } -PyDoc_STRVAR(bufferediobase_read1_doc, - "Read and return up to n bytes, with at most one read() call\n" - "to the underlying raw stream. A short result does not imply\n" - "that EOF is imminent.\n" - "\n" - "Returns an empty bytes object on EOF.\n"); +/*[clinic input] +_io._BufferedIOBase.read1 + + cls: defining_class + / + *args: object + +Read and return up to n bytes, with at most one read() call to the underlying raw stream. + +Return an empty bytes object on EOF. +A short result does not imply that EOF is imminent. +[clinic start generated code]*/ static PyObject * -bufferediobase_read1(PyObject *self, PyObject *args) +_io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=636fd241c21e050a input=ef546a1238c5b41c]*/ { _PyIO_State *state = IO_STATE(); return bufferediobase_unsupported(state, "read1"); } -PyDoc_STRVAR(bufferediobase_write_doc, - "Write the given buffer to the IO stream.\n" - "\n" - "Returns the number of bytes written, which is always the length of b\n" - "in bytes.\n" - "\n" - "Raises BlockingIOError if the buffer is full and the\n" - "underlying raw stream cannot accept more data at the moment.\n"); +/*[clinic input] +_io._BufferedIOBase.write + + cls: defining_class + / + *args: object + +Write the given buffer to the IO stream. + +Return the number of bytes written, which is always +the length of b in bytes. + +Raise BlockingIOError if the buffer is full and the +underlying raw stream cannot accept more data at the moment. +[clinic start generated code]*/ static PyObject * -bufferediobase_write(PyObject *self, PyObject *args) +_io__BufferedIOBase_write_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=d51feea4bcac9892 input=f79b72c4dccb3dc2]*/ { _PyIO_State *state = IO_STATE(); return bufferediobase_unsupported(state, "write"); @@ -2336,11 +2365,11 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, static PyMethodDef bufferediobase_methods[] = { _IO__BUFFEREDIOBASE_DETACH_METHODDEF - {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc}, - {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc}, + _IO__BUFFEREDIOBASE_READ_METHODDEF + _IO__BUFFEREDIOBASE_READ1_METHODDEF _IO__BUFFEREDIOBASE_READINTO_METHODDEF _IO__BUFFEREDIOBASE_READINTO1_METHODDEF - {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc}, + _IO__BUFFEREDIOBASE_WRITE_METHODDEF {NULL, NULL} }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index d44321bb8b96..a898b01899ba 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -92,15 +92,178 @@ PyDoc_STRVAR(_io__BufferedIOBase_detach__doc__, "state."); #define _IO__BUFFEREDIOBASE_DETACH_METHODDEF \ - {"detach", (PyCFunction)_io__BufferedIOBase_detach, METH_NOARGS, _io__BufferedIOBase_detach__doc__}, + {"detach", _PyCFunction_CAST(_io__BufferedIOBase_detach), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__BufferedIOBase_detach__doc__}, static PyObject * -_io__BufferedIOBase_detach_impl(PyObject *self); +_io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_io__BufferedIOBase_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) +_io__BufferedIOBase_detach(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__BufferedIOBase_detach_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "detach() takes no arguments"); + return NULL; + } + return _io__BufferedIOBase_detach_impl(self, cls); +} + +PyDoc_STRVAR(_io__BufferedIOBase_read__doc__, +"read($self, /, *args)\n" +"--\n" +"\n" +"Read and return up to n bytes.\n" +"\n" +"If the argument is omitted, None, or negative, read and\n" +"return all data until EOF.\n" +"\n" +"If the argument is positive, and the underlying raw stream is\n" +"not \'interactive\', multiple raw reads may be issued to satisfy\n" +"the byte count (unless EOF is reached first).\n" +"However, for interactive raw streams (as well as sockets and pipes),\n" +"at most one raw read will be issued, and a short result does not\n" +"imply that EOF is imminent.\n" +"\n" +"Return an empty bytes object on EOF.\n" +"\n" +"Return None if the underlying raw stream was open in non-blocking\n" +"mode and no data is available at the moment."); + +#define _IO__BUFFEREDIOBASE_READ_METHODDEF \ + {"read", _PyCFunction_CAST(_io__BufferedIOBase_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__BufferedIOBase_read__doc__}, + +static PyObject * +_io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__BufferedIOBase_read(PyObject *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 = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__BufferedIOBase_read_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +PyDoc_STRVAR(_io__BufferedIOBase_read1__doc__, +"read1($self, /, *args)\n" +"--\n" +"\n" +"Read and return up to n bytes, with at most one read() call to the underlying raw stream.\n" +"\n" +"Return an empty bytes object on EOF.\n" +"A short result does not imply that EOF is imminent."); + +#define _IO__BUFFEREDIOBASE_READ1_METHODDEF \ + {"read1", _PyCFunction_CAST(_io__BufferedIOBase_read1), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__BufferedIOBase_read1__doc__}, + +static PyObject * +_io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__BufferedIOBase_read1(PyObject *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 = "read1", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__BufferedIOBase_read1_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +PyDoc_STRVAR(_io__BufferedIOBase_write__doc__, +"write($self, /, *args)\n" +"--\n" +"\n" +"Write the given buffer to the IO stream.\n" +"\n" +"Return the number of bytes written, which is always\n" +"the length of b in bytes.\n" +"\n" +"Raise BlockingIOError if the buffer is full and the\n" +"underlying raw stream cannot accept more data at the moment."); + +#define _IO__BUFFEREDIOBASE_WRITE_METHODDEF \ + {"write", _PyCFunction_CAST(_io__BufferedIOBase_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__BufferedIOBase_write__doc__}, + +static PyObject * +_io__BufferedIOBase_write_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__BufferedIOBase_write(PyObject *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 = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__BufferedIOBase_write_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; } PyDoc_STRVAR(_io__Buffered_peek__doc__, @@ -714,4 +877,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=8412b10c04259bb8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c4ea041ccc91b5d2 input=a9049054013a1b77]*/ From webhook-mailer at python.org Wed May 10 10:49:03 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 10 May 2023 14:49:03 -0000 Subject: [Python-checkins] gh-104010: Separate and improve docs for `typing.get_origin` and `typing.get_args` (#104013) Message-ID: <mailman.291.1683730144.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a7a2dbbf72aceef61bfb50901bfa39bfb8d6d229 commit: a7a2dbbf72aceef61bfb50901bfa39bfb8d6d229 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-10T07:48:55-07:00 summary: gh-104010: Separate and improve docs for `typing.get_origin` and `typing.get_args` (#104013) * separate documentation and examples for both functions * add examples demonstrating behaviour with unsupported types * document return value of `get_origin` for `ParamSpecArgs` and `ParamSpecKwargs` instances Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index ebab1389f07e..fb1c916b141a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2876,24 +2876,37 @@ Introspection helpers if a default value equal to ``None`` was set. Now the annotation is returned unchanged. -.. function:: get_args(tp) .. function:: get_origin(tp) - Provide basic introspection for generic types and special typing forms. - - For a typing object of the form ``X[Y, Z, ...]`` these functions return - ``X`` and ``(Y, Z, ...)``. If ``X`` is a generic alias for a builtin or + Get the unsubscripted version of a type: for a typing object of the form + ``X[Y, Z, ...]`` return ``X``. If ``X`` is a generic alias for a builtin or :mod:`collections` class, it gets normalized to the original class. + If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, + return the underlying :class:`ParamSpec`. + Return ``None`` for unsupported objects. + Examples:: + + assert get_origin(str) is None + assert get_origin(Dict[str, int]) is dict + assert get_origin(Union[int, str]) is Union + P = ParamSpec('P') + assert get_origin(P.args) is P + assert get_origin(P.kwargs) is P + + .. versionadded:: 3.8 + +.. function:: get_args(tp) + + Get type arguments with all substitutions performed: for a typing object + of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. If ``X`` is a union or :class:`Literal` contained in another generic type, the order of ``(Y, Z, ...)`` may be different from the order of the original arguments ``[Y, Z, ...]`` due to type caching. - For unsupported objects return ``None`` and ``()`` correspondingly. + Return ``()`` for unsupported objects. Examples:: - assert get_origin(Dict[str, int]) is dict + assert get_args(int) == () assert get_args(Dict[int, str]) == (int, str) - - assert get_origin(Union[int, str]) is Union assert get_args(Union[int, str]) == (int, str) .. versionadded:: 3.8 From webhook-mailer at python.org Wed May 10 10:49:56 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 10 May 2023 14:49:56 -0000 Subject: [Python-checkins] [3.11] gh-104010: Separate and improve docs for `typing.get_origin` and `typing.get_args` (GH-104013) (#104359) Message-ID: <mailman.292.1683730197.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a8e902d2c2e90255c838bd99e833cef2c674c1f0 commit: a8e902d2c2e90255c838bd99e833cef2c674c1f0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-10T07:49:49-07:00 summary: [3.11] gh-104010: Separate and improve docs for `typing.get_origin` and `typing.get_args` (GH-104013) (#104359) * separate documentation and examples for both functions * add examples demonstrating behaviour with unsupported types * document return value of `get_origin` for `ParamSpecArgs` and `ParamSpecKwargs` instances (cherry picked from commit a7a2dbbf72aceef61bfb50901bfa39bfb8d6d229) Co-authored-by: chgnrdv <52372310+chgnrdv at users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 2a53df4b746d..a99a35a7664f 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2790,24 +2790,37 @@ Introspection helpers if a default value equal to ``None`` was set. Now the annotation is returned unchanged. -.. function:: get_args(tp) .. function:: get_origin(tp) - Provide basic introspection for generic types and special typing forms. - - For a typing object of the form ``X[Y, Z, ...]`` these functions return - ``X`` and ``(Y, Z, ...)``. If ``X`` is a generic alias for a builtin or + Get the unsubscripted version of a type: for a typing object of the form + ``X[Y, Z, ...]`` return ``X``. If ``X`` is a generic alias for a builtin or :mod:`collections` class, it gets normalized to the original class. + If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, + return the underlying :class:`ParamSpec`. + Return ``None`` for unsupported objects. + Examples:: + + assert get_origin(str) is None + assert get_origin(Dict[str, int]) is dict + assert get_origin(Union[int, str]) is Union + P = ParamSpec('P') + assert get_origin(P.args) is P + assert get_origin(P.kwargs) is P + + .. versionadded:: 3.8 + +.. function:: get_args(tp) + + Get type arguments with all substitutions performed: for a typing object + of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. If ``X`` is a union or :class:`Literal` contained in another generic type, the order of ``(Y, Z, ...)`` may be different from the order of the original arguments ``[Y, Z, ...]`` due to type caching. - For unsupported objects return ``None`` and ``()`` correspondingly. + Return ``()`` for unsupported objects. Examples:: - assert get_origin(Dict[str, int]) is dict + assert get_args(int) == () assert get_args(Dict[int, str]) == (int, str) - - assert get_origin(Union[int, str]) is Union assert get_args(Union[int, str]) == (int, str) .. versionadded:: 3.8 From webhook-mailer at python.org Wed May 10 10:53:26 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 10 May 2023 14:53:26 -0000 Subject: [Python-checkins] [3.11] gh-103247: clear the module cache in a test in test_importlib/extensions/test_loader.py (GH-104226) (#104345) Message-ID: <mailman.293.1683730407.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1cbf844875969da679f03ee4e9e27fff306fcf3d commit: 1cbf844875969da679f03ee4e9e27fff306fcf3d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-10T07:53:19-07:00 summary: [3.11] gh-103247: clear the module cache in a test in test_importlib/extensions/test_loader.py (GH-104226) (#104345) gh-103247: clear the module cache in a test in test_importlib/extensions/test_loader.py (GH-104226) (cherry picked from commit 22f3425c3d3d896be0917d80d55e8abb08d99b18) Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> files: M Lib/test/test_importlib/extension/test_loader.py diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 8570c6bc90cd..8e2b58d12a39 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -179,15 +179,16 @@ def test_reload(self): def test_try_registration(self): # Assert that the PyState_{Find,Add,Remove}Module C API doesn't work. - module = self.load_module() - with self.subTest('PyState_FindModule'): - self.assertEqual(module.call_state_registration_func(0), None) - with self.subTest('PyState_AddModule'): - with self.assertRaises(SystemError): - module.call_state_registration_func(1) - with self.subTest('PyState_RemoveModule'): - with self.assertRaises(SystemError): - module.call_state_registration_func(2) + with util.uncache(self.name): + module = self.load_module() + with self.subTest('PyState_FindModule'): + self.assertEqual(module.call_state_registration_func(0), None) + with self.subTest('PyState_AddModule'): + with self.assertRaises(SystemError): + module.call_state_registration_func(1) + with self.subTest('PyState_RemoveModule'): + with self.assertRaises(SystemError): + module.call_state_registration_func(2) def test_load_submodule(self): # Test loading a simulated submodule. From webhook-mailer at python.org Wed May 10 12:45:14 2023 From: webhook-mailer at python.org (mdickinson) Date: Wed, 10 May 2023 16:45:14 -0000 Subject: [Python-checkins] gh-104263: Rely on Py_NAN and introduce Py_INFINITY (GH-104202) Message-ID: <mailman.294.1683737115.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7a3b03509e5e3e72d8c47137579cccb52548a318 commit: 7a3b03509e5e3e72d8c47137579cccb52548a318 branch: main author: Sebastian Berg <sebastianb at nvidia.com> committer: mdickinson <dickinsm at gmail.com> date: 2023-05-10T17:44:52+01:00 summary: gh-104263: Rely on Py_NAN and introduce Py_INFINITY (GH-104202) This PR removes `_Py_dg_stdnan` and `_Py_dg_infinity` in favour of using the standard `NAN` and `INFINITY` macros provided by C99. This change has the side-effect of fixing a bug on MIPS where the hard-coded value used by `_Py_dg_stdnan` gave a signalling NaN rather than a quiet NaN. --------- Co-authored-by: Mark Dickinson <dickinsm at gmail.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst M Include/internal/pycore_dtoa.h M Include/pymath.h M Lib/test/test_cmath.py M Lib/test/test_complex.py M Lib/test/test_float.py M Lib/test/test_math.py M Modules/cmathmodule.c M Modules/mathmodule.c M Objects/floatobject.c M Python/dtoa.c M Python/pystrtod.c diff --git a/Include/internal/pycore_dtoa.h b/Include/internal/pycore_dtoa.h index fb524770efed..4d9681d59a64 100644 --- a/Include/internal/pycore_dtoa.h +++ b/Include/internal/pycore_dtoa.h @@ -64,8 +64,6 @@ PyAPI_FUNC(double) _Py_dg_strtod(const char *str, char **ptr); PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); PyAPI_FUNC(void) _Py_dg_freedtoa(char *s); -PyAPI_FUNC(double) _Py_dg_stdnan(int sign); -PyAPI_FUNC(double) _Py_dg_infinity(int sign); #endif // _PY_SHORT_FLOAT_REPR == 1 diff --git a/Include/pymath.h b/Include/pymath.h index 772b67e49775..4c1e3d998489 100644 --- a/Include/pymath.h +++ b/Include/pymath.h @@ -39,27 +39,24 @@ // Return 1 if float or double arg is neither infinite nor NAN, else 0. #define Py_IS_FINITE(X) isfinite(X) -/* HUGE_VAL is supposed to expand to a positive double infinity. Python - * uses Py_HUGE_VAL instead because some platforms are broken in this - * respect. We used to embed code in pyport.h to try to worm around that, - * but different platforms are broken in conflicting ways. If you're on - * a platform where HUGE_VAL is defined incorrectly, fiddle your Python - * config to #define Py_HUGE_VAL to something that works on your platform. +// Py_INFINITY: Value that evaluates to a positive double infinity. +#ifndef Py_INFINITY +# define Py_INFINITY ((double)INFINITY) +#endif + +/* Py_HUGE_VAL should always be the same as Py_INFINITY. But historically + * this was not reliable and Python did not require IEEE floats and C99 + * conformity. Prefer Py_INFINITY for new code. */ #ifndef Py_HUGE_VAL # define Py_HUGE_VAL HUGE_VAL #endif -// Py_NAN: Value that evaluates to a quiet Not-a-Number (NaN). +/* Py_NAN: Value that evaluates to a quiet Not-a-Number (NaN). The sign is + * undefined and normally not relevant, but e.g. fixed for float("nan"). + */ #if !defined(Py_NAN) -# if _Py__has_builtin(__builtin_nan) - // Built-in implementation of the ISO C99 function nan(): quiet NaN. -# define Py_NAN (__builtin_nan("")) -#else - // Use C99 NAN constant: quiet Not-A-Number. - // NAN is a float, Py_NAN is a double: cast to double. # define Py_NAN ((double)NAN) -# endif #endif #endif /* Py_PYMATH_H */ diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py index cd2c6939105d..57f80d5d8cd0 100644 --- a/Lib/test/test_cmath.py +++ b/Lib/test/test_cmath.py @@ -166,6 +166,11 @@ def test_infinity_and_nan_constants(self): self.assertEqual(cmath.nan.imag, 0.0) self.assertEqual(cmath.nanj.real, 0.0) self.assertTrue(math.isnan(cmath.nanj.imag)) + # Also check that the sign of all of these is positive: + self.assertEqual(math.copysign(1., cmath.nan.real), 1.) + self.assertEqual(math.copysign(1., cmath.nan.imag), 1.) + self.assertEqual(math.copysign(1., cmath.nanj.real), 1.) + self.assertEqual(math.copysign(1., cmath.nanj.imag), 1.) # Check consistency with reprs. self.assertEqual(repr(cmath.inf), "inf") diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py index 51ba151505fb..9180cca62b28 100644 --- a/Lib/test/test_complex.py +++ b/Lib/test/test_complex.py @@ -529,6 +529,12 @@ class complex2(complex): self.assertFloatsAreIdentical(z.real, x) self.assertFloatsAreIdentical(z.imag, y) + def test_constructor_negative_nans_from_string(self): + self.assertEqual(copysign(1., complex("-nan").real), -1.) + self.assertEqual(copysign(1., complex("-nanj").imag), -1.) + self.assertEqual(copysign(1., complex("-nan-nanj").real), -1.) + self.assertEqual(copysign(1., complex("-nan-nanj").imag), -1.) + def test_underscores(self): # check underscores for lit in VALID_UNDERSCORE_LITERALS: @@ -569,6 +575,7 @@ def test(v, expected, test_fn=self.assertEqual): test(complex(NAN, 1), "(nan+1j)") test(complex(1, NAN), "(1+nanj)") test(complex(NAN, NAN), "(nan+nanj)") + test(complex(-NAN, -NAN), "(nan+nanj)") test(complex(0, INF), "infj") test(complex(0, -INF), "-infj") diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py index f8350c1e4caa..c4ee1e08251d 100644 --- a/Lib/test/test_float.py +++ b/Lib/test/test_float.py @@ -1040,11 +1040,8 @@ def test_inf_signs(self): self.assertEqual(copysign(1.0, float('inf')), 1.0) self.assertEqual(copysign(1.0, float('-inf')), -1.0) - @unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short', - "applies only when using short float repr style") def test_nan_signs(self): - # When using the dtoa.c code, the sign of float('nan') should - # be predictable. + # The sign of float('nan') should be predictable. self.assertEqual(copysign(1.0, float('nan')), 1.0) self.assertEqual(copysign(1.0, float('-nan')), -1.0) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 433161c2dd41..f282434c9a33 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1881,11 +1881,11 @@ def testIsinf(self): self.assertFalse(math.isinf(0.)) self.assertFalse(math.isinf(1.)) - @requires_IEEE_754 def test_nan_constant(self): + # `math.nan` must be a quiet NaN with positive sign bit self.assertTrue(math.isnan(math.nan)) + self.assertEqual(math.copysign(1., math.nan), 1.) - @requires_IEEE_754 def test_inf_constant(self): self.assertTrue(math.isinf(math.inf)) self.assertGreater(math.inf, 0.0) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst new file mode 100644 index 000000000000..342467cfcd4e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst @@ -0,0 +1,6 @@ +Fix ``float("nan")`` to produce a quiet NaN on platforms (like MIPS) where +the meaning of the signalling / quiet bit is inverted from its usual +meaning. Also introduce a new macro ``Py_INFINITY`` matching C99's +``INFINITY``, and refactor internals to rely on C99's ``NAN`` and +``INFINITY`` macros instead of hard-coding bit patterns for infinities and +NaNs. Thanks Sebastian Berg. diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 914a697f8e17..1a31bdc824bb 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -8,7 +8,6 @@ #include "Python.h" #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR -#include "pycore_dtoa.h" // _Py_dg_stdnan() /* we need DBL_MAX, DBL_MIN, DBL_EPSILON, DBL_MANT_DIG and FLT_RADIX from float.h. We assume that FLT_RADIX is either 2 or 16. */ #include <float.h> @@ -88,53 +87,6 @@ else { #endif #define CM_SCALE_DOWN (-(CM_SCALE_UP+1)/2) -/* Constants cmath.inf, cmath.infj, cmath.nan, cmath.nanj. - cmath.nan and cmath.nanj are defined only when either - _PY_SHORT_FLOAT_REPR is 1 (which should be - the most common situation on machines using an IEEE 754 - representation), or Py_NAN is defined. */ - -static double -m_inf(void) -{ -#if _PY_SHORT_FLOAT_REPR == 1 - return _Py_dg_infinity(0); -#else - return Py_HUGE_VAL; -#endif -} - -static Py_complex -c_infj(void) -{ - Py_complex r; - r.real = 0.0; - r.imag = m_inf(); - return r; -} - -#if _PY_SHORT_FLOAT_REPR == 1 - -static double -m_nan(void) -{ -#if _PY_SHORT_FLOAT_REPR == 1 - return _Py_dg_stdnan(0); -#else - return Py_NAN; -#endif -} - -static Py_complex -c_nanj(void) -{ - Py_complex r; - r.real = 0.0; - r.imag = m_nan(); - return r; -} - -#endif /* forward declarations */ static Py_complex cmath_asinh_impl(PyObject *, Py_complex); @@ -1274,23 +1226,22 @@ cmath_exec(PyObject *mod) if (PyModule_AddObject(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_AddObject(mod, "inf", PyFloat_FromDouble(m_inf())) < 0) { + if (PyModule_AddObject(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { return -1; } + Py_complex infj = {0.0, Py_INFINITY}; if (PyModule_AddObject(mod, "infj", - PyComplex_FromCComplex(c_infj())) < 0) { + PyComplex_FromCComplex(infj)) < 0) { return -1; } -#if _PY_SHORT_FLOAT_REPR == 1 - if (PyModule_AddObject(mod, "nan", PyFloat_FromDouble(m_nan())) < 0) { + if (PyModule_AddObject(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } - if (PyModule_AddObject(mod, "nanj", - PyComplex_FromCComplex(c_nanj())) < 0) { + Py_complex nanj = {0.0, fabs(Py_NAN)}; + if (PyModule_AddObject(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) { return -1; } -#endif /* initialize special value tables */ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 3737a9654575..f369b2c45ce3 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -59,7 +59,6 @@ raised for division by zero and mod by zero. #include "Python.h" #include "pycore_bitutils.h" // _Py_bit_length() #include "pycore_call.h" // _PyObject_CallNoArgs() -#include "pycore_dtoa.h" // _Py_dg_infinity() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_object.h" // _PyObject_LookupSpecial() @@ -389,34 +388,6 @@ lanczos_sum(double x) return num/den; } -/* Constant for +infinity, generated in the same way as float('inf'). */ - -static double -m_inf(void) -{ -#if _PY_SHORT_FLOAT_REPR == 1 - return _Py_dg_infinity(0); -#else - return Py_HUGE_VAL; -#endif -} - -/* Constant nan value, generated in the same way as float('nan'). */ -/* We don't currently assume that Py_NAN is defined everywhere. */ - -#if _PY_SHORT_FLOAT_REPR == 1 - -static double -m_nan(void) -{ -#if _PY_SHORT_FLOAT_REPR == 1 - return _Py_dg_stdnan(0); -#else - return Py_NAN; -#endif -} - -#endif static double m_tgamma(double x) @@ -435,7 +406,7 @@ m_tgamma(double x) if (x == 0.0) { errno = EDOM; /* tgamma(+-0.0) = +-inf, divide-by-zero */ - return copysign(Py_HUGE_VAL, x); + return copysign(Py_INFINITY, x); } /* integer arguments */ @@ -3938,7 +3909,7 @@ math_ulp_impl(PyObject *module, double x) if (Py_IS_INFINITY(x)) { return x; } - double inf = m_inf(); + double inf = Py_INFINITY; double x2 = nextafter(x, inf); if (Py_IS_INFINITY(x2)) { /* special case: x is the largest positive representable float */ @@ -3975,14 +3946,12 @@ math_exec(PyObject *module) if (PyModule_AddObject(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_AddObject(module, "inf", PyFloat_FromDouble(m_inf())) < 0) { + if (PyModule_AddObject(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { return -1; } -#if _PY_SHORT_FLOAT_REPR == 1 - if (PyModule_AddObject(module, "nan", PyFloat_FromDouble(m_nan())) < 0) { + if (PyModule_AddObject(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } -#endif return 0; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index d257857d9c61..83a263c0d9c6 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -2424,25 +2424,14 @@ PyFloat_Unpack2(const char *data, int le) f |= *p; if (e == 0x1f) { -#if _PY_SHORT_FLOAT_REPR == 0 if (f == 0) { /* Infinity */ return sign ? -Py_HUGE_VAL : Py_HUGE_VAL; } else { /* NaN */ - return sign ? -Py_NAN : Py_NAN; + return sign ? -fabs(Py_NAN) : fabs(Py_NAN); } -#else // _PY_SHORT_FLOAT_REPR == 1 - if (f == 0) { - /* Infinity */ - return _Py_dg_infinity(sign); - } - else { - /* NaN */ - return _Py_dg_stdnan(sign); - } -#endif // _PY_SHORT_FLOAT_REPR == 1 } x = (double)f / 1024.0; diff --git a/Python/dtoa.c b/Python/dtoa.c index 6ea60ac9946e..c5e343b82f74 100644 --- a/Python/dtoa.c +++ b/Python/dtoa.c @@ -273,11 +273,6 @@ typedef union { double d; ULong L[2]; } U; #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff -/* Standard NaN used by _Py_dg_stdnan. */ - -#define NAN_WORD0 0x7ff80000 -#define NAN_WORD1 0 - /* Bits of the representation of positive infinity. */ #define POSINF_WORD0 0x7ff00000 @@ -1399,35 +1394,6 @@ bigcomp(U *rv, const char *s0, BCinfo *bc) return 0; } -/* Return a 'standard' NaN value. - - There are exactly two quiet NaNs that don't arise by 'quieting' signaling - NaNs (see IEEE 754-2008, section 6.2.1). If sign == 0, return the one whose - sign bit is cleared. Otherwise, return the one whose sign bit is set. -*/ - -double -_Py_dg_stdnan(int sign) -{ - U rv; - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; - if (sign) - word0(&rv) |= Sign_bit; - return dval(&rv); -} - -/* Return positive or negative infinity, according to the given sign (0 for - * positive infinity, 1 for negative infinity). */ - -double -_Py_dg_infinity(int sign) -{ - U rv; - word0(&rv) = POSINF_WORD0; - word1(&rv) = POSINF_WORD1; - return sign ? -dval(&rv) : dval(&rv); -} double _Py_dg_strtod(const char *s00, char **se) diff --git a/Python/pystrtod.c b/Python/pystrtod.c index d77b846f0403..9bb060e3d119 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -23,44 +23,6 @@ case_insensitive_match(const char *s, const char *t) return the NaN or Infinity as a double and set *endptr to point just beyond the successfully parsed portion of the string. On failure, return -1.0 and set *endptr to point to the start of the string. */ - -#if _PY_SHORT_FLOAT_REPR == 1 - -double -_Py_parse_inf_or_nan(const char *p, char **endptr) -{ - double retval; - const char *s; - int negate = 0; - - s = p; - if (*s == '-') { - negate = 1; - s++; - } - else if (*s == '+') { - s++; - } - if (case_insensitive_match(s, "inf")) { - s += 3; - if (case_insensitive_match(s, "inity")) - s += 5; - retval = _Py_dg_infinity(negate); - } - else if (case_insensitive_match(s, "nan")) { - s += 3; - retval = _Py_dg_stdnan(negate); - } - else { - s = p; - retval = -1.0; - } - *endptr = (char *)s; - return retval; -} - -#else - double _Py_parse_inf_or_nan(const char *p, char **endptr) { @@ -84,7 +46,7 @@ _Py_parse_inf_or_nan(const char *p, char **endptr) } else if (case_insensitive_match(s, "nan")) { s += 3; - retval = negate ? -Py_NAN : Py_NAN; + retval = negate ? -fabs(Py_NAN) : fabs(Py_NAN); } else { s = p; @@ -94,7 +56,6 @@ _Py_parse_inf_or_nan(const char *p, char **endptr) return retval; } -#endif /** * _PyOS_ascii_strtod: From webhook-mailer at python.org Wed May 10 13:17:15 2023 From: webhook-mailer at python.org (barneygale) Date: Wed, 10 May 2023 17:17:15 -0000 Subject: [Python-checkins] GH-87695: Fix OSError from `pathlib.Path.glob()` (GH-104292) Message-ID: <mailman.295.1683739035.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a33ce66dca57d4c36b1022fdf3b7e322f3203468 commit: a33ce66dca57d4c36b1022fdf3b7e322f3203468 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-10T17:17:08Z summary: GH-87695: Fix OSError from `pathlib.Path.glob()` (GH-104292) Fix issue where `pathlib.Path.glob()` raised `OSError` when it encountered a symlink to an overly long path. files: A Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 20ec1ce9d803..25863c76f308 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -178,11 +178,11 @@ def _iterate_directories(self, parent_path, scandir): for entry in entries: entry_is_dir = False try: - entry_is_dir = entry.is_dir() + entry_is_dir = entry.is_dir(follow_symlinks=False) except OSError as e: if not _ignore_error(e): raise - if entry_is_dir and not entry.is_symlink(): + if entry_is_dir: path = parent_path._make_child_relpath(entry.name) for p in self._iterate_directories(path, scandir): yield p diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index ee0ef9a34c38..10dd604138a6 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1977,6 +1977,15 @@ def my_scandir(path): subdir.chmod(000) self.assertEqual(len(set(base.glob("*"))), 4) + @os_helper.skip_unless_symlink + def test_glob_long_symlink(self): + # See gh-87695 + base = self.cls(BASE) / 'long_symlink' + base.mkdir() + bad_link = base / 'bad_link' + bad_link.symlink_to("bad" * 200) + self.assertEqual(sorted(base.glob('**/*')), [bad_link]) + def _check_resolve(self, p, expected, strict=True): q = p.resolve(strict) self.assertEqual(q, expected) diff --git a/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst b/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst new file mode 100644 index 000000000000..7b677656bea3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst @@ -0,0 +1,2 @@ +Fix issue where :meth:`pathlib.Path.glob` raised :exc:`OSError` when it +encountered a symlink to an overly long path. From webhook-mailer at python.org Wed May 10 14:53:20 2023 From: webhook-mailer at python.org (zware) Date: Wed, 10 May 2023 18:53:20 -0000 Subject: [Python-checkins] gh-103538: Remove unused TK_AQUA code (GH-103539) Message-ID: <mailman.296.1683744802.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e464ec9f4c4af6c2fdb6db9a3fa70ffd703ae01f commit: e464ec9f4c4af6c2fdb6db9a3fa70ffd703ae01f branch: main author: Christopher Chavez <chrischavez at gmx.us> committer: zware <zachary.ware at gmail.com> date: 2023-05-10T18:53:13Z summary: gh-103538: Remove unused TK_AQUA code (GH-103539) files: A Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst M Modules/_tkinter.c M Modules/tkappinit.c diff --git a/Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst b/Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst new file mode 100644 index 000000000000..32788307d6f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst @@ -0,0 +1,3 @@ +Remove ``_tkinter`` module code guarded by definition of the ``TK_AQUA`` macro +which was only needed for Tk 8.4.7 or earlier and was never actually defined by +any build system or documented for manual use. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 385a05932a77..4dada0b28f05 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3283,20 +3283,6 @@ PyInit__tkinter(void) } PyTclObject_Type = o; -#ifdef TK_AQUA - /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems - * start waking up. Note that Tcl_FindExecutable will do this, this - * code must be above it! The original warning from - * tkMacOSXAppInit.c is copied below. - * - * NB - You have to swap in the Tk Notifier BEFORE you start up the - * Tcl interpreter for now. It probably should work to do this - * in the other order, but for now it doesn't seem to. - * - */ - Tk_MacOSXSetupTkNotifier(); -#endif - /* This helps the dynamic loader; in Unicode aware Tcl versions it also helps Tcl find its encodings. */ diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c index 67d6250318c6..4c4081e43a8e 100644 --- a/Modules/tkappinit.c +++ b/Modules/tkappinit.c @@ -23,54 +23,9 @@ Tcl_AppInit(Tcl_Interp *interp) { const char *_tkinter_skip_tk_init; -#ifdef TK_AQUA -#ifndef MAX_PATH_LEN -#define MAX_PATH_LEN 1024 -#endif - char tclLibPath[MAX_PATH_LEN], tkLibPath[MAX_PATH_LEN]; - Tcl_Obj* pathPtr; - - /* pre- Tcl_Init code copied from tkMacOSXAppInit.c */ - Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tcllibrary", - tclLibPath, MAX_PATH_LEN, 0); - - if (tclLibPath[0] != '\0') { - Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); - } - - if (tclLibPath[0] != '\0') { - Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); - Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); - } -#endif if (Tcl_Init (interp) == TCL_ERROR) return TCL_ERROR; -#ifdef TK_AQUA - /* pre- Tk_Init code copied from tkMacOSXAppInit.c */ - Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tklibrary", - tkLibPath, MAX_PATH_LEN, 1); - - if (tclLibPath[0] != '\0') { - pathPtr = Tcl_NewStringObj(tclLibPath, -1); - } else { - Tcl_Obj *pathPtr = TclGetLibraryPath(); - } - - if (tkLibPath[0] != '\0') { - Tcl_Obj *objPtr; - - Tcl_SetVar(interp, "tk_library", tkLibPath, TCL_GLOBAL_ONLY); - objPtr = Tcl_NewStringObj(tkLibPath, -1); - Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); - } - - TclSetLibraryPath(pathPtr); -#endif - #ifdef WITH_XXX /* Initialize modules that don't require Tk */ #endif @@ -88,11 +43,6 @@ Tcl_AppInit(Tcl_Interp *interp) Tk_MainWindow(interp); -#ifdef TK_AQUA - TkMacOSXInitAppleEvents(interp); - TkMacOSXInitMenus(interp); -#endif - #ifdef WITH_PIL /* 0.2b5 and later -- not yet released as of May 14 */ { extern void TkImaging_Init(Tcl_Interp *); From webhook-mailer at python.org Wed May 10 17:44:02 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 10 May 2023 21:44:02 -0000 Subject: [Python-checkins] gh-103000: Optimise `dataclasses.asdict` for the common case (#104364) Message-ID: <mailman.297.1683755044.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7b8d7f56b64ab4370fea77e77ea4984dd2a73979 commit: 7b8d7f56b64ab4370fea77e77ea4984dd2a73979 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-10T22:43:51+01:00 summary: gh-103000: Optimise `dataclasses.asdict` for the common case (#104364) Co-authored-by: David Ellis <ducksual at gmail.com> files: A Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst M Lib/dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index b0b8a773b759..3eacba840db4 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1324,11 +1324,18 @@ def _asdict_inner(obj, dict_factory): 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) - result.append((f.name, value)) - return dict_factory(result) + # fast path for the common case + if dict_factory is dict: + return { + f.name: _asdict_inner(getattr(obj, f.name), dict) + for f in fields(obj) + } + else: + result = [] + for f in fields(obj): + value = _asdict_inner(getattr(obj, f.name), dict_factory) + result.append((f.name, value)) + return dict_factory(result) elif isinstance(obj, tuple) and hasattr(obj, '_fields'): # obj is a namedtuple. Recurse into it, but the returned # object is another namedtuple of the same type. This is diff --git a/Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst b/Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst new file mode 100644 index 000000000000..f84ec5c8b3ca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst @@ -0,0 +1,2 @@ +Improve performance of :func:`dataclasses.asdict` for the common case where +*dict_factory* is ``dict``. Patch by David C Ellis. From webhook-mailer at python.org Wed May 10 18:41:06 2023 From: webhook-mailer at python.org (brandtbucher) Date: Wed, 10 May 2023 22:41:06 -0000 Subject: [Python-checkins] GH-102181: Improve specialization stats for SEND (GH-102182) Message-ID: <mailman.298.1683758466.13550.python-checkins@python.org> https://github.com/python/cpython/commit/373bca0cc5256dc512ffc22bdff4424f7ee8baa2 commit: 373bca0cc5256dc512ffc22bdff4424f7ee8baa2 branch: main author: penguin_wwy <940375606 at qq.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-10T22:40:59Z summary: GH-102181: Improve specialization stats for SEND (GH-102182) files: M Include/cpython/genobject.h M Objects/genobject.c M Python/specialize.c M Tools/scripts/summarize_stats.py diff --git a/Include/cpython/genobject.h b/Include/cpython/genobject.h index 18b8ce913e6e..7856481b5db3 100644 --- a/Include/cpython/genobject.h +++ b/Include/cpython/genobject.h @@ -77,6 +77,8 @@ PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *, #define PyAsyncGen_CheckExact(op) Py_IS_TYPE((op), &PyAsyncGen_Type) +#define PyAsyncGenASend_CheckExact(op) Py_IS_TYPE((op), &_PyAsyncGenASend_Type) + #undef _PyGenObject_HEAD diff --git a/Objects/genobject.c b/Objects/genobject.c index 937d497753e9..9252c6549345 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1406,9 +1406,6 @@ typedef struct _PyAsyncGenWrappedValue { #define _PyAsyncGenWrappedValue_CheckExact(o) \ Py_IS_TYPE(o, &_PyAsyncGenWrappedValue_Type) -#define PyAsyncGenASend_CheckExact(o) \ - Py_IS_TYPE(o, &_PyAsyncGenASend_Type) - static int async_gen_traverse(PyAsyncGenObject *gen, visitproc visit, void *arg) diff --git a/Python/specialize.c b/Python/specialize.c index 2ccca3a2802c..45f1cb412db2 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -436,27 +436,28 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 21 #define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 22 -/* FOR_ITER */ -#define SPEC_FAIL_FOR_ITER_GENERATOR 10 -#define SPEC_FAIL_FOR_ITER_COROUTINE 11 -#define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12 -#define SPEC_FAIL_FOR_ITER_LIST 13 -#define SPEC_FAIL_FOR_ITER_TUPLE 14 -#define SPEC_FAIL_FOR_ITER_SET 15 -#define SPEC_FAIL_FOR_ITER_STRING 16 -#define SPEC_FAIL_FOR_ITER_BYTES 17 -#define SPEC_FAIL_FOR_ITER_RANGE 18 -#define SPEC_FAIL_FOR_ITER_ITERTOOLS 19 -#define SPEC_FAIL_FOR_ITER_DICT_KEYS 20 -#define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21 -#define SPEC_FAIL_FOR_ITER_DICT_VALUES 22 -#define SPEC_FAIL_FOR_ITER_ENUMERATE 23 -#define SPEC_FAIL_FOR_ITER_MAP 24 -#define SPEC_FAIL_FOR_ITER_ZIP 25 -#define SPEC_FAIL_FOR_ITER_SEQ_ITER 26 -#define SPEC_FAIL_FOR_ITER_REVERSED_LIST 27 -#define SPEC_FAIL_FOR_ITER_CALLABLE 28 -#define SPEC_FAIL_FOR_ITER_ASCII_STRING 29 +/* FOR_ITER and SEND */ +#define SPEC_FAIL_ITER_GENERATOR 10 +#define SPEC_FAIL_ITER_COROUTINE 11 +#define SPEC_FAIL_ITER_ASYNC_GENERATOR 12 +#define SPEC_FAIL_ITER_LIST 13 +#define SPEC_FAIL_ITER_TUPLE 14 +#define SPEC_FAIL_ITER_SET 15 +#define SPEC_FAIL_ITER_STRING 16 +#define SPEC_FAIL_ITER_BYTES 17 +#define SPEC_FAIL_ITER_RANGE 18 +#define SPEC_FAIL_ITER_ITERTOOLS 19 +#define SPEC_FAIL_ITER_DICT_KEYS 20 +#define SPEC_FAIL_ITER_DICT_ITEMS 21 +#define SPEC_FAIL_ITER_DICT_VALUES 22 +#define SPEC_FAIL_ITER_ENUMERATE 23 +#define SPEC_FAIL_ITER_MAP 24 +#define SPEC_FAIL_ITER_ZIP 25 +#define SPEC_FAIL_ITER_SEQ_ITER 26 +#define SPEC_FAIL_ITER_REVERSED_LIST 27 +#define SPEC_FAIL_ITER_CALLABLE 28 +#define SPEC_FAIL_ITER_ASCII_STRING 29 +#define SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND 30 // UNPACK_SEQUENCE @@ -2122,66 +2123,69 @@ int _PySpecialization_ClassifyIterator(PyObject *iter) { if (PyGen_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_GENERATOR; + return SPEC_FAIL_ITER_GENERATOR; } if (PyCoro_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_COROUTINE; + return SPEC_FAIL_ITER_COROUTINE; } if (PyAsyncGen_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR; + return SPEC_FAIL_ITER_ASYNC_GENERATOR; + } + if (PyAsyncGenASend_CheckExact(iter)) { + return SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND; } PyTypeObject *t = Py_TYPE(iter); if (t == &PyListIter_Type) { - return SPEC_FAIL_FOR_ITER_LIST; + return SPEC_FAIL_ITER_LIST; } if (t == &PyTupleIter_Type) { - return SPEC_FAIL_FOR_ITER_TUPLE; + return SPEC_FAIL_ITER_TUPLE; } if (t == &PyDictIterKey_Type) { - return SPEC_FAIL_FOR_ITER_DICT_KEYS; + return SPEC_FAIL_ITER_DICT_KEYS; } if (t == &PyDictIterValue_Type) { - return SPEC_FAIL_FOR_ITER_DICT_VALUES; + return SPEC_FAIL_ITER_DICT_VALUES; } if (t == &PyDictIterItem_Type) { - return SPEC_FAIL_FOR_ITER_DICT_ITEMS; + return SPEC_FAIL_ITER_DICT_ITEMS; } if (t == &PySetIter_Type) { - return SPEC_FAIL_FOR_ITER_SET; + return SPEC_FAIL_ITER_SET; } if (t == &PyUnicodeIter_Type) { - return SPEC_FAIL_FOR_ITER_STRING; + return SPEC_FAIL_ITER_STRING; } if (t == &PyBytesIter_Type) { - return SPEC_FAIL_FOR_ITER_BYTES; + return SPEC_FAIL_ITER_BYTES; } if (t == &PyRangeIter_Type) { - return SPEC_FAIL_FOR_ITER_RANGE; + return SPEC_FAIL_ITER_RANGE; } if (t == &PyEnum_Type) { - return SPEC_FAIL_FOR_ITER_ENUMERATE; + return SPEC_FAIL_ITER_ENUMERATE; } if (t == &PyMap_Type) { - return SPEC_FAIL_FOR_ITER_MAP; + return SPEC_FAIL_ITER_MAP; } if (t == &PyZip_Type) { - return SPEC_FAIL_FOR_ITER_ZIP; + return SPEC_FAIL_ITER_ZIP; } if (t == &PySeqIter_Type) { - return SPEC_FAIL_FOR_ITER_SEQ_ITER; + return SPEC_FAIL_ITER_SEQ_ITER; } if (t == &PyListRevIter_Type) { - return SPEC_FAIL_FOR_ITER_REVERSED_LIST; + return SPEC_FAIL_ITER_REVERSED_LIST; } if (t == &_PyUnicodeASCIIIter_Type) { - return SPEC_FAIL_FOR_ITER_ASCII_STRING; + return SPEC_FAIL_ITER_ASCII_STRING; } const char *name = t->tp_name; if (strncmp(name, "itertools", 9) == 0) { - return SPEC_FAIL_FOR_ITER_ITERTOOLS; + return SPEC_FAIL_ITER_ITERTOOLS; } if (strncmp(name, "callable_iterator", 17) == 0) { - return SPEC_FAIL_FOR_ITER_CALLABLE; + return SPEC_FAIL_ITER_CALLABLE; } return SPEC_FAIL_OTHER; } diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index ce25374f3a9a..4f25ba36d866 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -228,6 +228,8 @@ def kind_to_text(kind, defines, opname): return pretty(defines[kind][0]) if opname.endswith("ATTR"): opname = "ATTR" + if opname in ("FOR_ITER", "SEND"): + opname = "ITER" if opname.endswith("SUBSCR"): opname = "SUBSCR" for name in defines[kind]: From webhook-mailer at python.org Wed May 10 19:19:56 2023 From: webhook-mailer at python.org (barneygale) Date: Wed, 10 May 2023 23:19:56 -0000 Subject: [Python-checkins] [3.11] GH-87695: Fix OSError from `pathlib.Path.glob()` (GH-104292) (GH-104362) Message-ID: <mailman.299.1683760797.13550.python-checkins@python.org> https://github.com/python/cpython/commit/846a23d0b8f08e62a90682c51ce01301eb923f2e commit: 846a23d0b8f08e62a90682c51ce01301eb923f2e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-10T23:19:49Z summary: [3.11] GH-87695: Fix OSError from `pathlib.Path.glob()` (GH-104292) (GH-104362) Fix issue where `pathlib.Path.glob()` raised `OSError` when it encountered a symlink to an overly long path. (cherry picked from commit a33ce66dca57d4c36b1022fdf3b7e322f3203468) Co-authored-by: Barney Gale <barney.gale at gmail.com> files: A Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 9d40d88ef5f2..ecb1e8a40d8c 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -388,11 +388,11 @@ def _iterate_directories(self, parent_path, is_dir, scandir): for entry in entries: entry_is_dir = False try: - entry_is_dir = entry.is_dir() + entry_is_dir = entry.is_dir(follow_symlinks=False) except OSError as e: if not _ignore_error(e): raise - if entry_is_dir and not entry.is_symlink(): + if entry_is_dir: path = parent_path._make_child_relpath(entry.name) for p in self._iterate_directories(path, is_dir, scandir): yield p diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 3b88c0848a04..bd5170651d53 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1790,6 +1790,15 @@ def my_scandir(path): subdir.chmod(000) self.assertEqual(len(set(base.glob("*"))), 4) + @os_helper.skip_unless_symlink + def test_glob_long_symlink(self): + # See gh-87695 + base = self.cls(BASE) / 'long_symlink' + base.mkdir() + bad_link = base / 'bad_link' + bad_link.symlink_to("bad" * 200) + self.assertEqual(sorted(base.glob('**/*')), [bad_link]) + def _check_resolve(self, p, expected, strict=True): q = p.resolve(strict) self.assertEqual(q, expected) diff --git a/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst b/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst new file mode 100644 index 000000000000..7b677656bea3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst @@ -0,0 +1,2 @@ +Fix issue where :meth:`pathlib.Path.glob` raised :exc:`OSError` when it +encountered a symlink to an overly long path. From webhook-mailer at python.org Wed May 10 20:02:03 2023 From: webhook-mailer at python.org (barneygale) Date: Thu, 11 May 2023 00:02:03 -0000 Subject: [Python-checkins] GH-90208: Suppress OSError exceptions from `pathlib.Path.glob()` (GH-104141) Message-ID: <mailman.300.1683763324.13550.python-checkins@python.org> https://github.com/python/cpython/commit/94f30c75576bb8a20724b2ac758fa33af089a522 commit: 94f30c75576bb8a20724b2ac758fa33af089a522 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-11T01:01:39+01:00 summary: GH-90208: Suppress OSError exceptions from `pathlib.Path.glob()` (GH-104141) `pathlib.Path.glob()` now suppresses all OSError exceptions, except those raised from calling `is_dir()` on the top-level path. Previously, `glob()` suppressed ENOENT, ENOTDIR, EBADF and ELOOP errors and their Windows equivalents. PermissionError was also suppressed unless it occurred when calling `is_dir()` on the top-level path. However, the selector would abort prematurely if a PermissionError was raised, and so `glob()` could return incomplete results. files: A Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 25863c76f308..40b72930e1f0 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -142,25 +142,21 @@ def _select_from(self, parent_path, scandir): # avoid exhausting file descriptors when globbing deep trees. with scandir(parent_path) as scandir_it: entries = list(scandir_it) + except OSError: + pass + else: for entry in entries: if self.dironly: try: - # "entry.is_dir()" can raise PermissionError - # in some cases (see bpo-38894), which is not - # among the errors ignored by _ignore_error() if not entry.is_dir(): continue - except OSError as e: - if not _ignore_error(e): - raise + except OSError: continue name = entry.name if self.match(name): path = parent_path._make_child_relpath(name) for p in self.successor._select_from(path, scandir): yield p - except PermissionError: - return class _RecursiveWildcardSelector(_Selector): @@ -175,28 +171,25 @@ def _iterate_directories(self, parent_path, scandir): # avoid exhausting file descriptors when globbing deep trees. with scandir(parent_path) as scandir_it: entries = list(scandir_it) + except OSError: + pass + else: for entry in entries: entry_is_dir = False try: entry_is_dir = entry.is_dir(follow_symlinks=False) - except OSError as e: - if not _ignore_error(e): - raise + except OSError: + pass if entry_is_dir: path = parent_path._make_child_relpath(entry.name) for p in self._iterate_directories(path, scandir): yield p - except PermissionError: - return def _select_from(self, parent_path, scandir): - try: - successor_select = self.successor._select_from - for starting_point in self._iterate_directories(parent_path, scandir): - for p in successor_select(starting_point, scandir): - yield p - except PermissionError: - return + successor_select = self.successor._select_from + for starting_point in self._iterate_directories(parent_path, scandir): + for p in successor_select(starting_point, scandir): + yield p class _DoubleRecursiveWildcardSelector(_RecursiveWildcardSelector): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 10dd604138a6..67ca4795962b 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1949,33 +1949,19 @@ def test_glob_permissions(self): P = self.cls base = P(BASE) / 'permissions' base.mkdir() + self.addCleanup(os_helper.rmtree, base) - file1 = base / "file1" - file1.touch() - file2 = base / "file2" - file2.touch() - - subdir = base / "subdir" - - file3 = base / "file3" - file3.symlink_to(subdir / "other") - - # Patching is needed to avoid relying on the filesystem - # to return the order of the files as the error will not - # happen if the symlink is the last item. - real_scandir = os.scandir - def my_scandir(path): - with real_scandir(path) as scandir_it: - entries = list(scandir_it) - entries.sort(key=lambda entry: entry.name) - return contextlib.nullcontext(entries) - - with mock.patch("os.scandir", my_scandir): - self.assertEqual(len(set(base.glob("*"))), 3) - subdir.mkdir() - self.assertEqual(len(set(base.glob("*"))), 4) - subdir.chmod(000) - self.assertEqual(len(set(base.glob("*"))), 4) + for i in range(100): + link = base / f"link{i}" + if i % 2: + link.symlink_to(P(BASE, "dirE", "nonexistent")) + else: + link.symlink_to(P(BASE, "dirC")) + + self.assertEqual(len(set(base.glob("*"))), 100) + self.assertEqual(len(set(base.glob("*/"))), 50) + self.assertEqual(len(set(base.glob("*/fileC"))), 50) + self.assertEqual(len(set(base.glob("*/file*"))), 50) @os_helper.skip_unless_symlink def test_glob_long_symlink(self): diff --git a/Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst b/Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst new file mode 100644 index 000000000000..1fd9588bebd5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst @@ -0,0 +1,4 @@ +Fixed issue where :meth:`pathlib.Path.glob` returned incomplete results when +it encountered a :exc:`PermissionError`. This method now suppresses all +:exc:`OSError` exceptions, except those raised from calling +:meth:`~pathlib.Path.is_dir` on the top-level path. From webhook-mailer at python.org Wed May 10 21:08:47 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 11 May 2023 01:08:47 -0000 Subject: [Python-checkins] gh-104357: fix inlined comprehensions that close over iteration var (#104368) Message-ID: <mailman.301.1683767328.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fcd5fb49b1d71165f3c503c3d2e74a082ddb2f21 commit: fcd5fb49b1d71165f3c503c3d2e74a082ddb2f21 branch: main author: Carl Meyer <carl at oddbird.net> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-10T18:08:40-07:00 summary: gh-104357: fix inlined comprehensions that close over iteration var (#104368) files: M Lib/test/test_listcomps.py M Python/symtable.c diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 92fed98dd000..1cc202bb599a 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -163,6 +163,16 @@ def test_inner_cell_shadows_outer(self): outputs = {"y": [4, 4, 4, 4, 4], "i": 20} self._check_in_scopes(code, outputs) + def test_inner_cell_shadows_outer_no_store(self): + code = """ + def f(x): + return [lambda: x for x in range(x)], x + fns, x = f(2) + y = [fn() for fn in fns] + """ + outputs = {"y": [1, 1], "x": 2} + self._check_in_scopes(code, outputs) + def test_closure_can_jump_over_comp_scope(self): code = """ items = [(lambda: y) for i in range(5)] diff --git a/Python/symtable.c b/Python/symtable.c index 6e74d764245a..9361674bf165 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -607,12 +607,19 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, SET_SCOPE(scopes, k, scope); } else { - // free vars in comprehension that are locals in outer scope can - // now simply be locals, unless they are free in comp children - if ((PyLong_AsLong(existing) & DEF_BOUND) && - !is_free_in_any_child(comp, k)) { - if (PySet_Discard(comp_free, k) < 0) { - return 0; + if (PyLong_AsLong(existing) & DEF_BOUND) { + // cell vars in comprehension that are locals in outer scope + // must be promoted to cell so u_cellvars isn't wrong + if (scope == CELL && ste->ste_type == FunctionBlock) { + SET_SCOPE(scopes, k, scope); + } + + // free vars in comprehension that are locals in outer scope can + // now simply be locals, unless they are free in comp children + if (!is_free_in_any_child(comp, k)) { + if (PySet_Discard(comp_free, k) < 0) { + return 0; + } } } } From webhook-mailer at python.org Thu May 11 03:25:56 2023 From: webhook-mailer at python.org (gpshead) Date: Thu, 11 May 2023 07:25:56 -0000 Subject: [Python-checkins] GH-92184: Convert os.altsep to '/' in filenames when creating ZipInfo objects (#92185) Message-ID: <mailman.302.1683789958.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4abfe6a14b5be5decbaa3142d9e2549cf2d86c34 commit: 4abfe6a14b5be5decbaa3142d9e2549cf2d86c34 branch: main author: Carey Metcalfe <carey at cmetcalfe.ca> committer: gpshead <greg at krypto.org> date: 2023-05-11T07:25:16Z summary: GH-92184: Convert os.altsep to '/' in filenames when creating ZipInfo objects (#92185) This causes the zipfile module to also consider the character defined by `os.altsep` (if there is one) to be a path separator and convert it to a forward slash, as defined by the zip specification. A logical no-op on all known platforms today as os.altsep is currently only set to a meaningful value on Windows (where it is "/"). files: A Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst M Lib/zipfile/__init__.py diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 95c047991f87..116b939e55fe 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -352,6 +352,8 @@ def _sanitize_filename(filename): # ZIP format specification. if os.sep != "/" and os.sep in filename: filename = filename.replace(os.sep, "/") + if os.altsep and os.altsep != "/" and os.altsep in filename: + filename = filename.replace(os.altsep, "/") return filename diff --git a/Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst b/Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst new file mode 100644 index 000000000000..65dbdc9f6037 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst @@ -0,0 +1,3 @@ +When creating zip files using :mod:`zipfile`, ``os.altsep``, if not ``None``, +will always be treated as a path separator even when it is not ``/``. +Patch by Carey Metcalfe. From webhook-mailer at python.org Thu May 11 04:45:17 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 11 May 2023 08:45:17 -0000 Subject: [Python-checkins] gh-101117: Improve accuracy of sqlite3.Cursor.rowcount docs (#104287) Message-ID: <mailman.303.1683794719.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7470321f8171dce96a604ba2c24176837f999ca0 commit: 7470321f8171dce96a604ba2c24176837f999ca0 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-11T10:44:31+02:00 summary: gh-101117: Improve accuracy of sqlite3.Cursor.rowcount docs (#104287) The SQLite C API sqlite3_changes() can only be relied upon when the current active statement has been run to completion. files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 89673b8006ae..e7129fb3e4de 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1694,7 +1694,10 @@ Cursor objects ``INSERT``, ``UPDATE``, ``DELETE``, and ``REPLACE`` statements; is ``-1`` for other statements, including :abbr:`CTE (Common Table Expression)` queries. - It is only updated by the :meth:`execute` and :meth:`executemany` methods. + It is only updated by the :meth:`execute` and :meth:`executemany` methods, + after the statement has run to completion. + This means that any resulting rows must be fetched in order for + :attr:`!rowcount` to be updated. .. attribute:: row_factory From webhook-mailer at python.org Thu May 11 05:10:11 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 11 May 2023 09:10:11 -0000 Subject: [Python-checkins] [3.11] gh-101117: Improve accuracy of sqlite3.Cursor.rowcount docs (#104287) (#104381) Message-ID: <mailman.304.1683796212.13550.python-checkins@python.org> https://github.com/python/cpython/commit/705508850026dd13121b469290e27c29bd8ef20c commit: 705508850026dd13121b469290e27c29bd8ef20c branch: 3.11 author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-11T11:09:46+02:00 summary: [3.11] gh-101117: Improve accuracy of sqlite3.Cursor.rowcount docs (#104287) (#104381) The SQLite C API sqlite3_changes() can only be relied upon when the current active statement has been run to completion. files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 4dbbfe21ff66..249d29ce8993 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -1516,7 +1516,10 @@ Cursor objects ``INSERT``, ``UPDATE``, ``DELETE``, and ``REPLACE`` statements; is ``-1`` for other statements, including :abbr:`CTE (Common Table Expression)` queries. - It is only updated by the :meth:`execute` and :meth:`executemany` methods. + It is only updated by the :meth:`execute` and :meth:`executemany` methods, + after the statement has run to completion. + This means that any resulting rows must be fetched in order for + :attr:`!rowcount` to be updated. .. attribute:: row_factory From webhook-mailer at python.org Thu May 11 06:19:38 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 11 May 2023 10:19:38 -0000 Subject: [Python-checkins] gh-101819: Adapt _io.TextIOBase methods to Argument Clinic (#104383) Message-ID: <mailman.305.1683800379.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7dabb35f833b50bdca0afc1e065b44eb3b7954c8 commit: 7dabb35f833b50bdca0afc1e065b44eb3b7954c8 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-11T15:49:22+05:30 summary: gh-101819: Adapt _io.TextIOBase methods to Argument Clinic (#104383) files: M Modules/_io/clinic/textio.c.h M Modules/_io/textio.c diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index db968e884cc8..01965013ec6a 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -8,6 +8,171 @@ preserve #endif +PyDoc_STRVAR(_io__TextIOBase_detach__doc__, +"detach($self, /)\n" +"--\n" +"\n" +"Separate the underlying buffer from the TextIOBase and return it.\n" +"\n" +"After the underlying buffer has been detached, the TextIO is in an unusable state."); + +#define _IO__TEXTIOBASE_DETACH_METHODDEF \ + {"detach", _PyCFunction_CAST(_io__TextIOBase_detach), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_detach__doc__}, + +static PyObject * +_io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls); + +static PyObject * +_io__TextIOBase_detach(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs) { + PyErr_SetString(PyExc_TypeError, "detach() takes no arguments"); + return NULL; + } + return _io__TextIOBase_detach_impl(self, cls); +} + +PyDoc_STRVAR(_io__TextIOBase_read__doc__, +"read($self, /, *args)\n" +"--\n" +"\n" +"Read at most size characters from stream.\n" +"\n" +"Read from underlying buffer until we have size characters or we hit EOF.\n" +"If size is negative or omitted, read until EOF."); + +#define _IO__TEXTIOBASE_READ_METHODDEF \ + {"read", _PyCFunction_CAST(_io__TextIOBase_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_read__doc__}, + +static PyObject * +_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args); + +static PyObject * +_io__TextIOBase_read(PyObject *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 = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__TextIOBase_read_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +PyDoc_STRVAR(_io__TextIOBase_readline__doc__, +"readline($self, /, *args)\n" +"--\n" +"\n" +"Read until newline or EOF.\n" +"\n" +"Return an empty string if EOF is hit immediately."); + +#define _IO__TEXTIOBASE_READLINE_METHODDEF \ + {"readline", _PyCFunction_CAST(_io__TextIOBase_readline), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_readline__doc__}, + +static PyObject * +_io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, + PyObject *args); + +static PyObject * +_io__TextIOBase_readline(PyObject *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 = "readline", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__TextIOBase_readline_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +PyDoc_STRVAR(_io__TextIOBase_write__doc__, +"write($self, /, *args)\n" +"--\n" +"\n" +"Write string to stream.\n" +"\n" +"Return the number of characters written\n" +"(which is always equal to the length of the string)."); + +#define _IO__TEXTIOBASE_WRITE_METHODDEF \ + {"write", _PyCFunction_CAST(_io__TextIOBase_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_write__doc__}, + +static PyObject * +_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args); + +static PyObject * +_io__TextIOBase_write(PyObject *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 = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__TextIOBase_write_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(_io_IncrementalNewlineDecoder___init____doc__, "IncrementalNewlineDecoder(decoder, translate, errors=\'strict\')\n" "--\n" @@ -769,4 +934,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=73f84b13c343b34b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d800e5a8a50d6720 input=a9049054013a1b77]*/ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 070687a83d1b..96f5e0c45f51 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -20,8 +20,16 @@ module _io class _io.IncrementalNewlineDecoder "nldecoder_object *" "clinic_state()->PyIncrementalNewlineDecoder_Type" class _io.TextIOWrapper "textio *" "clinic_state()->TextIOWrapper_Type" +class _io._TextIOBase "PyObject *" "&PyTextIOBase_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81f67cf54eaa6001]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8b7f24fa13bfdd7f]*/ + +typedef struct nldecoder_object nldecoder_object; +typedef struct textio textio; + +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) +#include "clinic/textio.c.h" +#undef clinic_state /* TextIOBase */ @@ -42,52 +50,76 @@ _unsupported(const char *message) return NULL; } -PyDoc_STRVAR(textiobase_detach_doc, - "Separate the underlying buffer from the TextIOBase and return it.\n" - "\n" - "After the underlying buffer has been detached, the TextIO is in an\n" - "unusable state.\n" - ); +/*[clinic input] +_io._TextIOBase.detach + cls: defining_class + / + +Separate the underlying buffer from the TextIOBase and return it. + +After the underlying buffer has been detached, the TextIO is in an unusable state. +[clinic start generated code]*/ static PyObject * -textiobase_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) +_io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=50915f40c609eaa4 input=987ca3640d0a3776]*/ { return _unsupported("detach"); } -PyDoc_STRVAR(textiobase_read_doc, - "Read at most size characters from stream.\n" - "\n" - "Read from underlying buffer until we have size characters or we hit EOF.\n" - "If size is negative or omitted, read until EOF.\n" - ); +/*[clinic input] +_io._TextIOBase.read + cls: defining_class + / + *args: object + +Read at most size characters from stream. + +Read from underlying buffer until we have size characters or we hit EOF. +If size is negative or omitted, read until EOF. +[clinic start generated code]*/ static PyObject * -textiobase_read(PyObject *self, PyObject *args) +_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args) +/*[clinic end generated code: output=3adf28998831f461 input=cee1e84664a20de0]*/ { return _unsupported("read"); } -PyDoc_STRVAR(textiobase_readline_doc, - "Read until newline or EOF.\n" - "\n" - "Returns an empty string if EOF is hit immediately.\n" - ); +/*[clinic input] +_io._TextIOBase.readline + cls: defining_class + / + *args: object + +Read until newline or EOF. + +Return an empty string if EOF is hit immediately. +[clinic start generated code]*/ static PyObject * -textiobase_readline(PyObject *self, PyObject *args) +_io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, + PyObject *args) +/*[clinic end generated code: output=3073a948d02319f3 input=58f801259f7ff3ef]*/ { return _unsupported("readline"); } -PyDoc_STRVAR(textiobase_write_doc, - "Write string to stream.\n" - "Returns the number of characters written (which is always equal to\n" - "the length of the string).\n" - ); +/*[clinic input] +_io._TextIOBase.write + cls: defining_class + / + *args: object + +Write string to stream. + +Return the number of characters written +(which is always equal to the length of the string). +[clinic start generated code]*/ static PyObject * -textiobase_write(PyObject *self, PyObject *args) +_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args) +/*[clinic end generated code: output=5d985eb529472bc4 input=21b6961b5cba9496]*/ { return _unsupported("write"); } @@ -132,10 +164,10 @@ textiobase_errors_get(PyObject *self, void *context) static PyMethodDef textiobase_methods[] = { - {"detach", textiobase_detach, METH_NOARGS, textiobase_detach_doc}, - {"read", textiobase_read, METH_VARARGS, textiobase_read_doc}, - {"readline", textiobase_readline, METH_VARARGS, textiobase_readline_doc}, - {"write", textiobase_write, METH_VARARGS, textiobase_write_doc}, + _IO__TEXTIOBASE_DETACH_METHODDEF + _IO__TEXTIOBASE_READ_METHODDEF + _IO__TEXTIOBASE_READLINE_METHODDEF + _IO__TEXTIOBASE_WRITE_METHODDEF {NULL, NULL} }; @@ -200,14 +232,14 @@ PyTypeObject PyTextIOBase_Type = { /* IncrementalNewlineDecoder */ -typedef struct { +struct nldecoder_object { PyObject_HEAD PyObject *decoder; PyObject *errors; unsigned int pendingcr: 1; unsigned int translate: 1; unsigned int seennl: 3; -} nldecoder_object; +}; /*[clinic input] _io.IncrementalNewlineDecoder.__init__ @@ -645,7 +677,7 @@ incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context) typedef PyObject * (*encodefunc_t)(PyObject *, PyObject *); -typedef struct +struct textio { PyObject_HEAD int ok; /* initialized? */ @@ -704,7 +736,7 @@ typedef struct PyObject *dict; _PyIO_State *state; -} textio; +}; static void textiowrapper_set_decoded_chars(textio *self, PyObject *chars); @@ -3179,10 +3211,6 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) return 0; } -#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) -#include "clinic/textio.c.h" -#undef clinic_state - static PyMethodDef incrementalnewlinedecoder_methods[] = { _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF From webhook-mailer at python.org Thu May 11 06:26:41 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 11 May 2023 10:26:41 -0000 Subject: [Python-checkins] gh-101819: Refactor `_io` futher in preparation for module isolation (#104369) Message-ID: <mailman.306.1683800802.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d0a738c6df6f3f2d9e82e48733c64d9fbd810043 commit: d0a738c6df6f3f2d9e82e48733c64d9fbd810043 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-11T15:56:30+05:30 summary: gh-101819: Refactor `_io` futher in preparation for module isolation (#104369) files: M Modules/_io/clinic/fileio.c.h M Modules/_io/clinic/winconsoleio.c.h M Modules/_io/fileio.c M Modules/_io/textio.c M Modules/_io/winconsoleio.c diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index dfad8a58c472..33a37a389d22 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -215,27 +215,45 @@ PyDoc_STRVAR(_io_FileIO_readinto__doc__, "Same as RawIOBase.readinto()."); #define _IO_FILEIO_READINTO_METHODDEF \ - {"readinto", (PyCFunction)_io_FileIO_readinto, METH_O, _io_FileIO_readinto__doc__}, + {"readinto", _PyCFunction_CAST(_io_FileIO_readinto), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_readinto__doc__}, static PyObject * -_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer); +_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer); static PyObject * -_io_FileIO_readinto(fileio *self, PyObject *arg) +_io_FileIO_readinto(fileio *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 = "readinto", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer buffer = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &buffer, PyBUF_WRITABLE) < 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &buffer, PyBUF_WRITABLE) < 0) { PyErr_Clear(); - _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); goto exit; } if (!PyBuffer_IsContiguous(&buffer, 'C')) { - _PyArg_BadArgument("readinto", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("readinto", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io_FileIO_readinto_impl(self, &buffer); + return_value = _io_FileIO_readinto_impl(self, cls, &buffer); exit: /* Cleanup for buffer */ @@ -278,28 +296,43 @@ PyDoc_STRVAR(_io_FileIO_read__doc__, "Return an empty bytes object at EOF."); #define _IO_FILEIO_READ_METHODDEF \ - {"read", _PyCFunction_CAST(_io_FileIO_read), METH_FASTCALL, _io_FileIO_read__doc__}, + {"read", _PyCFunction_CAST(_io_FileIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_read__doc__}, static PyObject * -_io_FileIO_read_impl(fileio *self, Py_ssize_t size); +_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size); static PyObject * -_io_FileIO_read(fileio *self, PyObject *const *args, Py_ssize_t nargs) +_io_FileIO_read(fileio *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 = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_ssize_t size = -1; - if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { goto exit; } -skip_optional: - return_value = _io_FileIO_read_impl(self, size); +skip_optional_posonly: + return_value = _io_FileIO_read_impl(self, cls, size); exit: return return_value; @@ -316,25 +349,43 @@ PyDoc_STRVAR(_io_FileIO_write__doc__, "returns None if the write would block."); #define _IO_FILEIO_WRITE_METHODDEF \ - {"write", (PyCFunction)_io_FileIO_write, METH_O, _io_FileIO_write__doc__}, + {"write", _PyCFunction_CAST(_io_FileIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_write__doc__}, static PyObject * -_io_FileIO_write_impl(fileio *self, Py_buffer *b); +_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b); static PyObject * -_io_FileIO_write(fileio *self, PyObject *arg) +_io_FileIO_write(fileio *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 = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer b = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&b, 'C')) { - _PyArg_BadArgument("write", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("write", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io_FileIO_write_impl(self, &b); + return_value = _io_FileIO_write_impl(self, cls, &b); exit: /* Cleanup for b */ @@ -422,26 +473,41 @@ PyDoc_STRVAR(_io_FileIO_truncate__doc__, "The current file position is changed to the value of size."); #define _IO_FILEIO_TRUNCATE_METHODDEF \ - {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_FASTCALL, _io_FileIO_truncate__doc__}, + {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_truncate__doc__}, static PyObject * -_io_FileIO_truncate_impl(fileio *self, PyObject *posobj); +_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj); static PyObject * -_io_FileIO_truncate(fileio *self, PyObject *const *args, Py_ssize_t nargs) +_io_FileIO_truncate(fileio *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 = "truncate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyObject *posobj = Py_None; - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } posobj = args[0]; -skip_optional: - return_value = _io_FileIO_truncate_impl(self, posobj); +skip_optional_posonly: + return_value = _io_FileIO_truncate_impl(self, cls, posobj); exit: return return_value; @@ -470,4 +536,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=29ed2ae6c451c139 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bef47b31b644996a input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h index 4c5cd0892c4a..cd3348dc1227 100644 --- a/Modules/_io/clinic/winconsoleio.c.h +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -20,15 +20,19 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__, "close() may be called more than once without error."); #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \ - {"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__}, + {"close", _PyCFunction_CAST(_io__WindowsConsoleIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_close__doc__}, static PyObject * -_io__WindowsConsoleIO_close_impl(winconsoleio *self); +_io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls); static PyObject * -_io__WindowsConsoleIO_close(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +_io__WindowsConsoleIO_close(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__WindowsConsoleIO_close_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } + return _io__WindowsConsoleIO_close_impl(self, cls); } #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ @@ -208,27 +212,46 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_readinto__doc__, "Same as RawIOBase.readinto()."); #define _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF \ - {"readinto", (PyCFunction)_io__WindowsConsoleIO_readinto, METH_O, _io__WindowsConsoleIO_readinto__doc__}, + {"readinto", _PyCFunction_CAST(_io__WindowsConsoleIO_readinto), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_readinto__doc__}, static PyObject * -_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer); +_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *buffer); static PyObject * -_io__WindowsConsoleIO_readinto(winconsoleio *self, PyObject *arg) +_io__WindowsConsoleIO_readinto(winconsoleio *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 = "readinto", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer buffer = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &buffer, PyBUF_WRITABLE) < 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &buffer, PyBUF_WRITABLE) < 0) { PyErr_Clear(); - _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); goto exit; } if (!PyBuffer_IsContiguous(&buffer, 'C')) { - _PyArg_BadArgument("readinto", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("readinto", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io__WindowsConsoleIO_readinto_impl(self, &buffer); + return_value = _io__WindowsConsoleIO_readinto_impl(self, cls, &buffer); exit: /* Cleanup for buffer */ @@ -278,28 +301,44 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_read__doc__, "Return an empty bytes object at EOF."); #define _IO__WINDOWSCONSOLEIO_READ_METHODDEF \ - {"read", _PyCFunction_CAST(_io__WindowsConsoleIO_read), METH_FASTCALL, _io__WindowsConsoleIO_read__doc__}, + {"read", _PyCFunction_CAST(_io__WindowsConsoleIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_read__doc__}, static PyObject * -_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size); +_io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, + Py_ssize_t size); static PyObject * -_io__WindowsConsoleIO_read(winconsoleio *self, PyObject *const *args, Py_ssize_t nargs) +_io__WindowsConsoleIO_read(winconsoleio *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 = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_ssize_t size = -1; - if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { goto exit; } -skip_optional: - return_value = _io__WindowsConsoleIO_read_impl(self, size); +skip_optional_posonly: + return_value = _io__WindowsConsoleIO_read_impl(self, cls, size); exit: return return_value; @@ -319,25 +358,44 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_write__doc__, "The number of bytes actually written is returned."); #define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF \ - {"write", (PyCFunction)_io__WindowsConsoleIO_write, METH_O, _io__WindowsConsoleIO_write__doc__}, + {"write", _PyCFunction_CAST(_io__WindowsConsoleIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_write__doc__}, static PyObject * -_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b); +_io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *b); static PyObject * -_io__WindowsConsoleIO_write(winconsoleio *self, PyObject *arg) +_io__WindowsConsoleIO_write(winconsoleio *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 = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer b = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&b, 'C')) { - _PyArg_BadArgument("write", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("write", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io__WindowsConsoleIO_write_impl(self, &b); + return_value = _io__WindowsConsoleIO_write_impl(self, cls, &b); exit: /* Cleanup for b */ @@ -407,4 +465,4 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ -/*[clinic end generated code: output=163e934aa9b0ef16 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=235393758365c229 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index cc0e7307b9da..473f0a8a6bef 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -549,13 +549,10 @@ err_closed(void) } static PyObject * -err_mode(const char *action) +err_mode(_PyIO_State *state, const char *action) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_Format(state->unsupported_operation, - "File not open for %s", action); - return NULL; + return PyErr_Format(state->unsupported_operation, + "File not open for %s", action); } /*[clinic input] @@ -631,6 +628,7 @@ _io_FileIO_seekable_impl(fileio *self) /*[clinic input] _io.FileIO.readinto + cls: defining_class buffer: Py_buffer(accept={rwbuffer}) / @@ -638,16 +636,18 @@ Same as RawIOBase.readinto(). [clinic start generated code]*/ static PyObject * -_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) -/*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/ +_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer) +/*[clinic end generated code: output=97f0f3d69534db34 input=fd20323e18ce1ec8]*/ { Py_ssize_t n; int err; if (self->fd < 0) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } n = _Py_read(self->fd, buffer->buf, buffer->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ @@ -784,6 +784,7 @@ _io_FileIO_readall_impl(fileio *self) /*[clinic input] _io.FileIO.read + cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -795,8 +796,8 @@ Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * -_io_FileIO_read_impl(fileio *self, Py_ssize_t size) -/*[clinic end generated code: output=42528d39dd0ca641 input=bec9a2c704ddcbc9]*/ +_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) +/*[clinic end generated code: output=bbd749c7c224143e input=f613d2057e4a1918]*/ { char *ptr; Py_ssize_t n; @@ -804,8 +805,10 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size) if (self->fd < 0) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } if (size < 0) return _io_FileIO_readall_impl(self); @@ -843,6 +846,7 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size) /*[clinic input] _io.FileIO.write + cls: defining_class b: Py_buffer / @@ -854,16 +858,18 @@ returns None if the write would block. [clinic start generated code]*/ static PyObject * -_io_FileIO_write_impl(fileio *self, Py_buffer *b) -/*[clinic end generated code: output=b4059db3d363a2f7 input=6e7908b36f0ce74f]*/ +_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b) +/*[clinic end generated code: output=927e25be80f3b77b input=2776314f043088f5]*/ { Py_ssize_t n; int err; if (self->fd < 0) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "writing"); + } n = _Py_write(self->fd, b->buf, b->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ @@ -994,6 +1000,7 @@ _io_FileIO_tell_impl(fileio *self) #ifdef HAVE_FTRUNCATE /*[clinic input] _io.FileIO.truncate + cls: defining_class size as posobj: object = None / @@ -1004,8 +1011,8 @@ The current file position is changed to the value of size. [clinic start generated code]*/ static PyObject * -_io_FileIO_truncate_impl(fileio *self, PyObject *posobj) -/*[clinic end generated code: output=e49ca7a916c176fa input=b0ac133939823875]*/ +_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj) +/*[clinic end generated code: output=d936732a49e8d5a2 input=c367fb45d6bb2c18]*/ { Py_off_t pos; int ret; @@ -1014,8 +1021,10 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) fd = self->fd; if (fd < 0) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "writing"); + } if (posobj == Py_None) { /* Get the current position. */ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 96f5e0c45f51..3cc292cc3510 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -42,11 +42,9 @@ PyDoc_STRVAR(textiobase_doc, ); static PyObject * -_unsupported(const char *message) +_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -64,7 +62,8 @@ static PyObject * _io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls) /*[clinic end generated code: output=50915f40c609eaa4 input=987ca3640d0a3776]*/ { - return _unsupported("detach"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "detach"); } /*[clinic input] @@ -83,7 +82,8 @@ static PyObject * _io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=3adf28998831f461 input=cee1e84664a20de0]*/ { - return _unsupported("read"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "read"); } /*[clinic input] @@ -102,7 +102,8 @@ _io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=3073a948d02319f3 input=58f801259f7ff3ef]*/ { - return _unsupported("readline"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "readline"); } /*[clinic input] @@ -121,7 +122,8 @@ static PyObject * _io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=5d985eb529472bc4 input=21b6961b5cba9496]*/ { - return _unsupported("write"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "write"); } PyDoc_STRVAR(textiobase_encoding_doc, @@ -1381,7 +1383,8 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding, /* Check if something is in the read buffer */ if (self->decoded_chars != NULL) { if (encoding != Py_None || errors != Py_None || newline_obj != NULL) { - _unsupported("It is not possible to set the encoding or newline " + _unsupported(self->state, + "It is not possible to set the encoding or newline " "of stream after the first read"); return NULL; } @@ -1648,8 +1651,9 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) CHECK_ATTACHED(self); CHECK_CLOSED(self); - if (self->encoder == NULL) - return _unsupported("not writable"); + if (self->encoder == NULL) { + return _unsupported(self->state, "not writable"); + } Py_INCREF(text); @@ -1830,7 +1834,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) */ if (self->decoder == NULL) { - _unsupported("not readable"); + _unsupported(self->state, "not readable"); return -1; } @@ -1955,8 +1959,9 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) CHECK_ATTACHED(self); CHECK_CLOSED(self); - if (self->decoder == NULL) - return _unsupported("not readable"); + if (self->decoder == NULL) { + return _unsupported(self->state, "not readable"); + } if (_textiowrapper_writeflush(self) < 0) return NULL; @@ -2487,7 +2492,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) Py_INCREF(cookieObj); if (!self->seekable) { - _unsupported("underlying stream is not seekable"); + _unsupported(self->state, "underlying stream is not seekable"); goto fail; } @@ -2501,7 +2506,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) goto fail; if (cmp == 0) { - _unsupported("can't do nonzero cur-relative seeks"); + _unsupported(self->state, "can't do nonzero cur-relative seeks"); goto fail; } @@ -2521,7 +2526,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) goto fail; if (cmp == 0) { - _unsupported("can't do nonzero end-relative seeks"); + _unsupported(self->state, "can't do nonzero end-relative seeks"); goto fail; } @@ -2684,7 +2689,7 @@ _io_TextIOWrapper_tell_impl(textio *self) CHECK_CLOSED(self); if (!self->seekable) { - _unsupported("underlying stream is not seekable"); + _unsupported(self->state, "underlying stream is not seekable"); goto fail; } if (!self->telling) { diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 58d9f2963aa9..f341cb238ce8 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -180,6 +180,8 @@ internal_close(winconsoleio *self) /*[clinic input] _io._WindowsConsoleIO.close + cls: defining_class + / Close the console object. @@ -188,13 +190,15 @@ close() may be called more than once without error. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_close_impl(winconsoleio *self) -/*[clinic end generated code: output=27ef95b66c29057b input=68c4e5754f8136c2]*/ +_io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls) +/*[clinic end generated code: output=e50c1808c063e1e2 input=161001bd2a649a4b]*/ { PyObject *res; PyObject *exc; int rc; - res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type, + + _PyIO_State *state = get_io_state_by_cls(cls); + res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject*)self); if (!self->closefd) { self->fd = -1; @@ -453,13 +457,10 @@ err_closed(void) } static PyObject * -err_mode(const char *action) +err_mode(_PyIO_State *state, const char *action) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_Format(state->unsupported_operation, - "Console buffer does not support %s", action); - return NULL; + return PyErr_Format(state->unsupported_operation, + "Console buffer does not support %s", action); } /*[clinic input] @@ -636,14 +637,14 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { static Py_ssize_t -readinto(winconsoleio *self, char *buf, Py_ssize_t len) +readinto(_PyIO_State *state, winconsoleio *self, char *buf, Py_ssize_t len) { if (self->fd == -1) { err_closed(); return -1; } if (!self->readable) { - err_mode("reading"); + err_mode(state, "reading"); return -1; } if (len == 0) @@ -733,6 +734,7 @@ readinto(winconsoleio *self, char *buf, Py_ssize_t len) /*[clinic input] _io._WindowsConsoleIO.readinto + cls: defining_class buffer: Py_buffer(accept={rwbuffer}) / @@ -740,10 +742,12 @@ Same as RawIOBase.readinto(). [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer) -/*[clinic end generated code: output=66d1bdfa3f20af39 input=4ed68da48a6baffe]*/ +_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *buffer) +/*[clinic end generated code: output=96717c74f6204b79 input=4b0627c3b1645f78]*/ { - Py_ssize_t len = readinto(self, buffer->buf, buffer->len); + _PyIO_State *state = get_io_state_by_cls(cls); + Py_ssize_t len = readinto(state, self, buffer->buf, buffer->len); if (len < 0) return NULL; @@ -897,6 +901,7 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) /*[clinic input] _io._WindowsConsoleIO.read + cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -908,16 +913,19 @@ Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) -/*[clinic end generated code: output=57df68af9f4b22d0 input=8bc73bc15d0fa072]*/ +_io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, + Py_ssize_t size) +/*[clinic end generated code: output=7e569a586537c0ae input=a14570a5da273365]*/ { PyObject *bytes; Py_ssize_t bytes_size; if (self->fd == -1) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "reading"); + } if (size < 0) return _io__WindowsConsoleIO_readall_impl(self); @@ -930,7 +938,9 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) if (bytes == NULL) return NULL; - bytes_size = readinto(self, PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); + _PyIO_State *state = get_io_state_by_cls(cls); + bytes_size = readinto(state, self, PyBytes_AS_STRING(bytes), + PyBytes_GET_SIZE(bytes)); if (bytes_size < 0) { Py_CLEAR(bytes); return NULL; @@ -948,6 +958,7 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) /*[clinic input] _io._WindowsConsoleIO.write + cls: defining_class b: Py_buffer / @@ -958,8 +969,9 @@ The number of bytes actually written is returned. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b) -/*[clinic end generated code: output=775bdb16fbf9137b input=be35fb624f97c941]*/ +_io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *b) +/*[clinic end generated code: output=e8019f480243cb29 input=10ac37c19339dfbe]*/ { BOOL res = TRUE; wchar_t *wbuf; @@ -968,8 +980,10 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b) if (self->fd == -1) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = get_io_state_by_cls(cls); + return err_mode(state, "writing"); + } handle = _Py_get_osfhandle(self->fd); if (handle == INVALID_HANDLE_VALUE) From webhook-mailer at python.org Thu May 11 06:29:30 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 11 May 2023 10:29:30 -0000 Subject: [Python-checkins] gh-101819: Adapt _io._Buffered* methods to Argument Clinic (#104367) Message-ID: <mailman.307.1683800971.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ed41124bb55cba61739e5180fd12d1285c3baa3d commit: ed41124bb55cba61739e5180fd12d1285c3baa3d branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-11T15:59:23+05:30 summary: gh-101819: Adapt _io._Buffered* methods to Argument Clinic (#104367) files: M Modules/_io/bufferedio.c M Modules/_io/clinic/bufferedio.c.h diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index c7ae60281c2f..00e228bca437 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -419,8 +419,13 @@ buffered_dealloc(buffered *self) Py_DECREF(tp); } +/*[clinic input] +_io._Buffered.__sizeof__ +[clinic start generated code]*/ + static PyObject * -buffered_sizeof(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered___sizeof___impl(buffered *self) +/*[clinic end generated code: output=0231ef7f5053134e input=753c782d808d34df]*/ { size_t res = _PyObject_SIZE(Py_TYPE(self)); if (self->buffer) { @@ -450,8 +455,17 @@ buffered_clear(buffered *self) /* Because this can call arbitrary code, it shouldn't be called when the refcount is 0 (that is, not directly from tp_dealloc unless the refcount has been temporarily re-incremented). */ +/*[clinic input] +_io._Buffered._dealloc_warn + + source: object + / + +[clinic start generated code]*/ + static PyObject * -buffered_dealloc_warn(buffered *self, PyObject *source) +_io__Buffered__dealloc_warn(buffered *self, PyObject *source) +/*[clinic end generated code: output=690dcc3df8967162 input=8f845f2a4786391c]*/ { if (self->ok && self->raw) { PyObject *r; @@ -471,9 +485,13 @@ buffered_dealloc_warn(buffered *self, PyObject *source) */ /* Flush and close */ +/*[clinic input] +_io._Buffered.flush as _io__Buffered_simple_flush +[clinic start generated code]*/ static PyObject * -buffered_simple_flush(buffered *self, PyObject *args) +_io__Buffered_simple_flush_impl(buffered *self) +/*[clinic end generated code: output=29ebb3820db1bdfd input=f33ef045e7250767]*/ { CHECK_INITIALIZED(self) return PyObject_CallMethodNoArgs(self->raw, &_Py_ID(flush)); @@ -500,8 +518,13 @@ buffered_closed_get(buffered *self, void *context) return PyObject_GetAttr(self->raw, &_Py_ID(closed)); } +/*[clinic input] +_io._Buffered.close +[clinic start generated code]*/ + static PyObject * -buffered_close(buffered *self, PyObject *args) +_io__Buffered_close_impl(buffered *self) +/*[clinic end generated code: output=7280b7b42033be0c input=d20b83d1ddd7d805]*/ { PyObject *res = NULL; int r; @@ -520,7 +543,7 @@ buffered_close(buffered *self, PyObject *args) } if (self->finalizing) { - PyObject *r = buffered_dealloc_warn(self, (PyObject *) self); + PyObject *r = _io__Buffered__dealloc_warn(self, (PyObject *) self); if (r) Py_DECREF(r); else @@ -560,10 +583,13 @@ buffered_close(buffered *self, PyObject *args) return res; } -/* detach */ +/*[clinic input] +_io._Buffered.detach +[clinic start generated code]*/ static PyObject * -buffered_detach(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_detach_impl(buffered *self) +/*[clinic end generated code: output=dd0fc057b8b779f7 input=482762a345cc9f44]*/ { PyObject *raw, *res; CHECK_INITIALIZED(self) @@ -580,22 +606,37 @@ buffered_detach(buffered *self, PyObject *Py_UNUSED(ignored)) /* Inquiries */ +/*[clinic input] +_io._Buffered.seekable +[clinic start generated code]*/ + static PyObject * -buffered_seekable(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_seekable_impl(buffered *self) +/*[clinic end generated code: output=90172abb5ceb6e8f input=7d35764f5fb5262b]*/ { CHECK_INITIALIZED(self) return PyObject_CallMethodNoArgs(self->raw, &_Py_ID(seekable)); } +/*[clinic input] +_io._Buffered.readable +[clinic start generated code]*/ + static PyObject * -buffered_readable(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_readable_impl(buffered *self) +/*[clinic end generated code: output=92afa07661ecb698 input=640619addb513b8b]*/ { CHECK_INITIALIZED(self) return PyObject_CallMethodNoArgs(self->raw, &_Py_ID(readable)); } +/*[clinic input] +_io._Buffered.writable +[clinic start generated code]*/ + static PyObject * -buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_writable_impl(buffered *self) +/*[clinic end generated code: output=4e3eee8d6f9d8552 input=b35ea396b2201554]*/ { CHECK_INITIALIZED(self) return PyObject_CallMethodNoArgs(self->raw, &_Py_ID(writable)); @@ -617,15 +658,25 @@ buffered_mode_get(buffered *self, void *context) /* Lower-level APIs */ +/*[clinic input] +_io._Buffered.fileno +[clinic start generated code]*/ + static PyObject * -buffered_fileno(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_fileno_impl(buffered *self) +/*[clinic end generated code: output=b717648d58a95ee3 input=768ea30b3f6314a7]*/ { CHECK_INITIALIZED(self) return PyObject_CallMethodNoArgs(self->raw, &_Py_ID(fileno)); } +/*[clinic input] +_io._Buffered.isatty +[clinic start generated code]*/ + static PyObject * -buffered_isatty(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_isatty_impl(buffered *self) +/*[clinic end generated code: output=c20e55caae67baea input=9ea007b11559bee4]*/ { CHECK_INITIALIZED(self) return PyObject_CallMethodNoArgs(self->raw, &_Py_ID(isatty)); @@ -830,8 +881,13 @@ buffered_flush_and_rewind_unlocked(buffered *self) Py_RETURN_NONE; } +/*[clinic input] +_io._Buffered.flush +[clinic start generated code]*/ + static PyObject * -buffered_flush(buffered *self, PyObject *args) +_io__Buffered_flush_impl(buffered *self) +/*[clinic end generated code: output=da2674ef1ce71f3a input=fda63444697c6bf4]*/ { PyObject *res; @@ -1205,8 +1261,13 @@ _io__Buffered_readline_impl(buffered *self, Py_ssize_t size) } +/*[clinic input] +_io._Buffered.tell +[clinic start generated code]*/ + static PyObject * -buffered_tell(buffered *self, PyObject *Py_UNUSED(ignored)) +_io__Buffered_tell_impl(buffered *self) +/*[clinic end generated code: output=386972ae84716c1e input=ad61e04a6b349573]*/ { Py_off_t pos; @@ -1318,20 +1379,21 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) /*[clinic input] _io._Buffered.truncate + cls: defining_class pos: object = None / [clinic start generated code]*/ static PyObject * -_io__Buffered_truncate_impl(buffered *self, PyObject *pos) -/*[clinic end generated code: output=667ca03c60c270de input=8a1be34d57cca2d3]*/ +_io__Buffered_truncate_impl(buffered *self, PyTypeObject *cls, PyObject *pos) +/*[clinic end generated code: output=fe3882fbffe79f1a input=f5b737d97d76303f]*/ { PyObject *res = NULL; CHECK_INITIALIZED(self) CHECK_CLOSED(self, "truncate of closed file") if (!self->writable) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "truncate"); } if (!ENTER_BUFFERED(self)) @@ -2427,14 +2489,14 @@ PyTypeObject PyBufferedIOBase_Type = { static PyMethodDef bufferedreader_methods[] = { /* BufferedIOMixin methods */ - {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, - {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS}, - {"close", (PyCFunction)buffered_close, METH_NOARGS}, - {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, - {"readable", (PyCFunction)buffered_readable, METH_NOARGS}, - {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, - {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, - {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + _IO__BUFFERED_DETACH_METHODDEF + _IO__BUFFERED_SIMPLE_FLUSH_METHODDEF + _IO__BUFFERED_CLOSE_METHODDEF + _IO__BUFFERED_SEEKABLE_METHODDEF + _IO__BUFFERED_READABLE_METHODDEF + _IO__BUFFERED_FILENO_METHODDEF + _IO__BUFFERED_ISATTY_METHODDEF + _IO__BUFFERED__DEALLOC_WARN_METHODDEF _IO__BUFFERED_READ_METHODDEF _IO__BUFFERED_PEEK_METHODDEF @@ -2443,9 +2505,9 @@ static PyMethodDef bufferedreader_methods[] = { _IO__BUFFERED_READINTO1_METHODDEF _IO__BUFFERED_READLINE_METHODDEF _IO__BUFFERED_SEEK_METHODDEF - {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + _IO__BUFFERED_TELL_METHODDEF _IO__BUFFERED_TRUNCATE_METHODDEF - {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + _IO__BUFFERED___SIZEOF___METHODDEF {NULL, NULL} }; @@ -2489,20 +2551,20 @@ PyType_Spec bufferedreader_spec = { static PyMethodDef bufferedwriter_methods[] = { /* BufferedIOMixin methods */ - {"close", (PyCFunction)buffered_close, METH_NOARGS}, - {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, - {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, - {"writable", (PyCFunction)buffered_writable, METH_NOARGS}, - {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, - {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, - {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + _IO__BUFFERED_CLOSE_METHODDEF + _IO__BUFFERED_DETACH_METHODDEF + _IO__BUFFERED_SEEKABLE_METHODDEF + _IO__BUFFERED_WRITABLE_METHODDEF + _IO__BUFFERED_FILENO_METHODDEF + _IO__BUFFERED_ISATTY_METHODDEF + _IO__BUFFERED__DEALLOC_WARN_METHODDEF _IO_BUFFEREDWRITER_WRITE_METHODDEF _IO__BUFFERED_TRUNCATE_METHODDEF - {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, + _IO__BUFFERED_FLUSH_METHODDEF _IO__BUFFERED_SEEK_METHODDEF - {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, - {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + _IO__BUFFERED_TELL_METHODDEF + _IO__BUFFERED___SIZEOF___METHODDEF {NULL, NULL} }; @@ -2596,19 +2658,19 @@ PyType_Spec bufferedrwpair_spec = { static PyMethodDef bufferedrandom_methods[] = { /* BufferedIOMixin methods */ - {"close", (PyCFunction)buffered_close, METH_NOARGS}, - {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, - {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, - {"readable", (PyCFunction)buffered_readable, METH_NOARGS}, - {"writable", (PyCFunction)buffered_writable, METH_NOARGS}, - {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, - {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, - {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + _IO__BUFFERED_CLOSE_METHODDEF + _IO__BUFFERED_DETACH_METHODDEF + _IO__BUFFERED_SEEKABLE_METHODDEF + _IO__BUFFERED_READABLE_METHODDEF + _IO__BUFFERED_WRITABLE_METHODDEF + _IO__BUFFERED_FILENO_METHODDEF + _IO__BUFFERED_ISATTY_METHODDEF + _IO__BUFFERED__DEALLOC_WARN_METHODDEF - {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, + _IO__BUFFERED_FLUSH_METHODDEF _IO__BUFFERED_SEEK_METHODDEF - {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + _IO__BUFFERED_TELL_METHODDEF _IO__BUFFERED_TRUNCATE_METHODDEF _IO__BUFFERED_READ_METHODDEF _IO__BUFFERED_READ1_METHODDEF @@ -2617,7 +2679,7 @@ static PyMethodDef bufferedrandom_methods[] = { _IO__BUFFERED_READLINE_METHODDEF _IO__BUFFERED_PEEK_METHODDEF _IO_BUFFEREDWRITER_WRITE_METHODDEF - {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + _IO__BUFFERED___SIZEOF___METHODDEF {NULL, NULL} }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index a898b01899ba..e2ac90c54a10 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -266,6 +266,184 @@ _io__BufferedIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *ar return return_value; } +PyDoc_STRVAR(_io__Buffered___sizeof____doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED___SIZEOF___METHODDEF \ + {"__sizeof__", (PyCFunction)_io__Buffered___sizeof__, METH_NOARGS, _io__Buffered___sizeof____doc__}, + +static PyObject * +_io__Buffered___sizeof___impl(buffered *self); + +static PyObject * +_io__Buffered___sizeof__(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered___sizeof___impl(self); +} + +PyDoc_STRVAR(_io__Buffered__dealloc_warn__doc__, +"_dealloc_warn($self, source, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED__DEALLOC_WARN_METHODDEF \ + {"_dealloc_warn", (PyCFunction)_io__Buffered__dealloc_warn, METH_O, _io__Buffered__dealloc_warn__doc__}, + +PyDoc_STRVAR(_io__Buffered_simple_flush__doc__, +"flush($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_SIMPLE_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_io__Buffered_simple_flush, METH_NOARGS, _io__Buffered_simple_flush__doc__}, + +static PyObject * +_io__Buffered_simple_flush_impl(buffered *self); + +static PyObject * +_io__Buffered_simple_flush(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_simple_flush_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_close__doc__, +"close($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io__Buffered_close, METH_NOARGS, _io__Buffered_close__doc__}, + +static PyObject * +_io__Buffered_close_impl(buffered *self); + +static PyObject * +_io__Buffered_close(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_close_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_detach__doc__, +"detach($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_DETACH_METHODDEF \ + {"detach", (PyCFunction)_io__Buffered_detach, METH_NOARGS, _io__Buffered_detach__doc__}, + +static PyObject * +_io__Buffered_detach_impl(buffered *self); + +static PyObject * +_io__Buffered_detach(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_detach_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)_io__Buffered_seekable, METH_NOARGS, _io__Buffered_seekable__doc__}, + +static PyObject * +_io__Buffered_seekable_impl(buffered *self); + +static PyObject * +_io__Buffered_seekable(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_seekable_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io__Buffered_readable, METH_NOARGS, _io__Buffered_readable__doc__}, + +static PyObject * +_io__Buffered_readable_impl(buffered *self); + +static PyObject * +_io__Buffered_readable(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_readable_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io__Buffered_writable, METH_NOARGS, _io__Buffered_writable__doc__}, + +static PyObject * +_io__Buffered_writable_impl(buffered *self); + +static PyObject * +_io__Buffered_writable(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_writable_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_fileno__doc__, +"fileno($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_FILENO_METHODDEF \ + {"fileno", (PyCFunction)_io__Buffered_fileno, METH_NOARGS, _io__Buffered_fileno__doc__}, + +static PyObject * +_io__Buffered_fileno_impl(buffered *self); + +static PyObject * +_io__Buffered_fileno(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_fileno_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io__Buffered_isatty, METH_NOARGS, _io__Buffered_isatty__doc__}, + +static PyObject * +_io__Buffered_isatty_impl(buffered *self); + +static PyObject * +_io__Buffered_isatty(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_isatty_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_flush__doc__, +"flush($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_io__Buffered_flush, METH_NOARGS, _io__Buffered_flush__doc__}, + +static PyObject * +_io__Buffered_flush_impl(buffered *self); + +static PyObject * +_io__Buffered_flush(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_flush_impl(self); +} + PyDoc_STRVAR(_io__Buffered_peek__doc__, "peek($self, size=0, /)\n" "--\n" @@ -490,6 +668,23 @@ _io__Buffered_readline(buffered *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(_io__Buffered_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_TELL_METHODDEF \ + {"tell", (PyCFunction)_io__Buffered_tell, METH_NOARGS, _io__Buffered_tell__doc__}, + +static PyObject * +_io__Buffered_tell_impl(buffered *self); + +static PyObject * +_io__Buffered_tell(buffered *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__Buffered_tell_impl(self); +} + PyDoc_STRVAR(_io__Buffered_seek__doc__, "seek($self, target, whence=0, /)\n" "--\n" @@ -532,26 +727,41 @@ PyDoc_STRVAR(_io__Buffered_truncate__doc__, "\n"); #define _IO__BUFFERED_TRUNCATE_METHODDEF \ - {"truncate", _PyCFunction_CAST(_io__Buffered_truncate), METH_FASTCALL, _io__Buffered_truncate__doc__}, + {"truncate", _PyCFunction_CAST(_io__Buffered_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__Buffered_truncate__doc__}, static PyObject * -_io__Buffered_truncate_impl(buffered *self, PyObject *pos); +_io__Buffered_truncate_impl(buffered *self, PyTypeObject *cls, PyObject *pos); static PyObject * -_io__Buffered_truncate(buffered *self, PyObject *const *args, Py_ssize_t nargs) +_io__Buffered_truncate(buffered *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 = "truncate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyObject *pos = Py_None; - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } pos = args[0]; -skip_optional: - return_value = _io__Buffered_truncate_impl(self, pos); +skip_optional_posonly: + return_value = _io__Buffered_truncate_impl(self, cls, pos); exit: return return_value; @@ -877,4 +1087,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=c4ea041ccc91b5d2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d770e392e8702e12 input=a9049054013a1b77]*/ From webhook-mailer at python.org Thu May 11 06:34:34 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 11 May 2023 10:34:34 -0000 Subject: [Python-checkins] gh-101819: Adapt _io.IOBase.seek and _io.IOBase.truncate to Argument Clinic (#104384) Message-ID: <mailman.308.1683801275.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e629ab6adf19544d5ee3f87bd1a9e9ff90808a08 commit: e629ab6adf19544d5ee3f87bd1a9e9ff90808a08 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-11T10:34:26Z summary: gh-101819: Adapt _io.IOBase.seek and _io.IOBase.truncate to Argument Clinic (#104384) files: M Modules/_io/clinic/iobase.c.h M Modules/_io/iobase.c diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 01c035dad264..727398800bec 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -8,6 +8,59 @@ preserve #endif +PyDoc_STRVAR(_io__IOBase_seek__doc__, +"seek($self, /, *args)\n" +"--\n" +"\n" +"Change the stream position to the given byte offset.\n" +"\n" +"The offset is interpreted relative to the position indicated by whence.\n" +"Values for whence are:\n" +"\n" +"* 0 -- start of stream (the default); offset should be zero or positive\n" +"* 1 -- current stream position; offset may be negative\n" +"* 2 -- end of stream; offset is usually negative\n" +"\n" +"Return the new absolute position."); + +#define _IO__IOBASE_SEEK_METHODDEF \ + {"seek", _PyCFunction_CAST(_io__IOBase_seek), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_seek__doc__}, + +static PyObject * +_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, PyObject *args); + +static PyObject * +_io__IOBase_seek(PyObject *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 = "seek", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__IOBase_seek_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(_io__IOBase_tell__doc__, "tell($self, /)\n" "--\n" @@ -26,6 +79,53 @@ _io__IOBase_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_tell_impl(self); } +PyDoc_STRVAR(_io__IOBase_truncate__doc__, +"truncate($self, /, *args)\n" +"--\n" +"\n" +"Truncate file to size bytes.\n" +"\n" +"File pointer is left unchanged. Size defaults to the current IO position\n" +"as reported by tell(). Return the new size."); + +#define _IO__IOBASE_TRUNCATE_METHODDEF \ + {"truncate", _PyCFunction_CAST(_io__IOBase_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_truncate__doc__}, + +static PyObject * +_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *args); + +static PyObject * +_io__IOBase_truncate(PyObject *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 = "truncate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *__clinic_args = NULL; + + args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + if (!args) { + goto exit; + } + __clinic_args = args[0]; + return_value = _io__IOBase_truncate_impl(self, cls, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + PyDoc_STRVAR(_io__IOBase_flush__doc__, "flush($self, /)\n" "--\n" @@ -316,4 +416,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=b7246a2087eb966b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b6d4845254da1da2 input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index ca13866c33fb..a74e46cc8dc5 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -79,21 +79,27 @@ iobase_unsupported(_PyIO_State *state, const char *message) /* Positioning */ -PyDoc_STRVAR(iobase_seek_doc, - "Change stream position.\n" - "\n" - "Change the stream position to the given byte offset. The offset is\n" - "interpreted relative to the position indicated by whence. Values\n" - "for whence are:\n" - "\n" - "* 0 -- start of stream (the default); offset should be zero or positive\n" - "* 1 -- current stream position; offset may be negative\n" - "* 2 -- end of stream; offset is usually negative\n" - "\n" - "Return the new absolute position."); +/*[clinic input] +_io._IOBase.seek + cls: defining_class + / + *args: object + +Change the stream position to the given byte offset. + +The offset is interpreted relative to the position indicated by whence. +Values for whence are: + +* 0 -- start of stream (the default); offset should be zero or positive +* 1 -- current stream position; offset may be negative +* 2 -- end of stream; offset is usually negative + +Return the new absolute position. +[clinic start generated code]*/ static PyObject * -iobase_seek(PyObject *self, PyObject *args) +_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, PyObject *args) +/*[clinic end generated code: output=1dd694ac9de260fa input=ebb5476eb22fc5d4]*/ { _PyIO_State *state = IO_STATE(); return iobase_unsupported(state, "seek"); @@ -112,14 +118,21 @@ _io__IOBase_tell_impl(PyObject *self) return _PyObject_CallMethod(self, &_Py_ID(seek), "ii", 0, 1); } -PyDoc_STRVAR(iobase_truncate_doc, - "Truncate file to size bytes.\n" - "\n" - "File pointer is left unchanged. Size defaults to the current IO\n" - "position as reported by tell(). Returns the new size."); +/*[clinic input] +_io._IOBase.truncate + cls: defining_class + / + *args: object + +Truncate file to size bytes. + +File pointer is left unchanged. Size defaults to the current IO position +as reported by tell(). Return the new size. +[clinic start generated code]*/ static PyObject * -iobase_truncate(PyObject *self, PyObject *args) +_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *args) +/*[clinic end generated code: output=b7eed4649cbe22c1 input=ad90582a1d8b5cc9]*/ { _PyIO_State *state = IO_STATE(); return iobase_unsupported(state, "truncate"); @@ -809,9 +822,9 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines) #include "clinic/iobase.c.h" static PyMethodDef iobase_methods[] = { - {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc}, + _IO__IOBASE_SEEK_METHODDEF _IO__IOBASE_TELL_METHODDEF - {"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc}, + _IO__IOBASE_TRUNCATE_METHODDEF _IO__IOBASE_FLUSH_METHODDEF _IO__IOBASE_CLOSE_METHODDEF From webhook-mailer at python.org Thu May 11 07:52:14 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 11 May 2023 11:52:14 -0000 Subject: [Python-checkins] gh-87849: fix SEND specialization family definition (GH-104268) Message-ID: <mailman.309.1683805936.13550.python-checkins@python.org> https://github.com/python/cpython/commit/167072938342981b96d06d739cd97185207b64dd commit: 167072938342981b96d06d739cd97185207b64dd branch: main author: Carl Meyer <carl at oddbird.net> committer: markshannon <mark at hotpy.org> date: 2023-05-11T12:52:06+01:00 summary: gh-87849: fix SEND specialization family definition (GH-104268) files: M Python/bytecodes.c M Python/generated_cases.c.h M Python/opcode_metadata.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 82c100444183..1c09dc6be3d6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -813,7 +813,7 @@ dummy_func( PREDICT(LOAD_CONST); } - family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { + family(send, INLINE_CACHE_ENTRIES_SEND) = { SEND, SEND_GEN, }; @@ -866,7 +866,7 @@ dummy_func( Py_DECREF(v); } - inst(SEND_GEN, (unused/1, receiver, v -- receiver)) { + inst(SEND_GEN, (unused/1, receiver, v -- receiver, unused)) { PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 819c857c3c01..a86b895dd43d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1139,6 +1139,7 @@ TARGET(SEND) { PREDICTED(SEND); + static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size"); PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; @@ -1188,7 +1189,7 @@ } } Py_DECREF(v); - #line 1192 "Python/generated_cases.c.h" + #line 1193 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1212,7 +1213,7 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1216 "Python/generated_cases.c.h" + #line 1217 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { @@ -1234,7 +1235,7 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1238 "Python/generated_cases.c.h" + #line 1239 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { @@ -1255,7 +1256,7 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1259 "Python/generated_cases.c.h" + #line 1260 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { @@ -1263,7 +1264,7 @@ #line 924 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1267 "Python/generated_cases.c.h" + #line 1268 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1289,7 +1290,7 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1293 "Python/generated_cases.c.h" + #line 1294 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { @@ -1298,7 +1299,7 @@ #line 949 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1302 "Python/generated_cases.c.h" + #line 1303 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); #line 952 "Python/bytecodes.c" @@ -1308,7 +1309,7 @@ _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1312 "Python/generated_cases.c.h" + #line 1313 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1324,7 +1325,7 @@ assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1328 "Python/generated_cases.c.h" + #line 1329 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); @@ -1335,7 +1336,7 @@ _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1339 "Python/generated_cases.c.h" + #line 1340 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1346,7 +1347,7 @@ PyObject *value; #line 975 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1350 "Python/generated_cases.c.h" + #line 1351 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1376,7 +1377,7 @@ if (true) goto error; } } - #line 1380 "Python/generated_cases.c.h" + #line 1381 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1391,7 +1392,7 @@ if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1395 "Python/generated_cases.c.h" + #line 1396 "Python/generated_cases.c.h" Py_DECREF(v); #line 1010 "Python/bytecodes.c" if (true) goto pop_1_error; @@ -1400,11 +1401,11 @@ err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1404 "Python/generated_cases.c.h" + #line 1405 "Python/generated_cases.c.h" Py_DECREF(v); #line 1017 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1408 "Python/generated_cases.c.h" + #line 1409 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1427,7 +1428,7 @@ name); goto error; } - #line 1431 "Python/generated_cases.c.h" + #line 1432 "Python/generated_cases.c.h" DISPATCH(); } @@ -1448,11 +1449,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1452 "Python/generated_cases.c.h" + #line 1453 "Python/generated_cases.c.h" Py_DECREF(seq); #line 1060 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1456 "Python/generated_cases.c.h" + #line 1457 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1469,7 +1470,7 @@ STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1473 "Python/generated_cases.c.h" + #line 1474 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1488,7 +1489,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1492 "Python/generated_cases.c.h" + #line 1493 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1507,7 +1508,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1511 "Python/generated_cases.c.h" + #line 1512 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1521,11 +1522,11 @@ 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 1525 "Python/generated_cases.c.h" + #line 1526 "Python/generated_cases.c.h" Py_DECREF(seq); #line 1100 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1529 "Python/generated_cases.c.h" + #line 1530 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1552,12 +1553,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1556 "Python/generated_cases.c.h" + #line 1557 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); #line 1127 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1561 "Python/generated_cases.c.h" + #line 1562 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1568,11 +1569,11 @@ #line 1131 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1572 "Python/generated_cases.c.h" + #line 1573 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1134 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1576 "Python/generated_cases.c.h" + #line 1577 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1582,11 +1583,11 @@ #line 1138 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1586 "Python/generated_cases.c.h" + #line 1587 "Python/generated_cases.c.h" Py_DECREF(v); #line 1141 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1590 "Python/generated_cases.c.h" + #line 1591 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1604,7 +1605,7 @@ } goto error; } - #line 1608 "Python/generated_cases.c.h" + #line 1609 "Python/generated_cases.c.h" DISPATCH(); } @@ -1669,7 +1670,7 @@ } } } - #line 1673 "Python/generated_cases.c.h" + #line 1674 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1732,7 +1733,7 @@ } } null = NULL; - #line 1736 "Python/generated_cases.c.h" + #line 1737 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1757,7 +1758,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1761 "Python/generated_cases.c.h" + #line 1762 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1787,7 +1788,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1791 "Python/generated_cases.c.h" + #line 1792 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1801,7 +1802,7 @@ PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1805 "Python/generated_cases.c.h" + #line 1806 "Python/generated_cases.c.h" DISPATCH(); } @@ -1815,7 +1816,7 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1819 "Python/generated_cases.c.h" + #line 1820 "Python/generated_cases.c.h" DISPATCH(); } @@ -1831,7 +1832,7 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1835 "Python/generated_cases.c.h" + #line 1836 "Python/generated_cases.c.h" DISPATCH(); } @@ -1869,7 +1870,7 @@ } Py_INCREF(value); } - #line 1873 "Python/generated_cases.c.h" + #line 1874 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1885,7 +1886,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1889 "Python/generated_cases.c.h" + #line 1890 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1898,7 +1899,7 @@ PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1902 "Python/generated_cases.c.h" + #line 1903 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1915,7 +1916,7 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1919 "Python/generated_cases.c.h" + #line 1920 "Python/generated_cases.c.h" DISPATCH(); } @@ -1924,13 +1925,13 @@ PyObject *str; #line 1404 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1928 "Python/generated_cases.c.h" + #line 1929 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } #line 1406 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1934 "Python/generated_cases.c.h" + #line 1935 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1943,7 +1944,7 @@ #line 1410 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1947 "Python/generated_cases.c.h" + #line 1948 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1956,7 +1957,7 @@ #line 1415 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1960 "Python/generated_cases.c.h" + #line 1961 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1977,13 +1978,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1981 "Python/generated_cases.c.h" + #line 1982 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 1431 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1987 "Python/generated_cases.c.h" + #line 1988 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1994,11 +1995,11 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 1438 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1998 "Python/generated_cases.c.h" + #line 1999 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 1440 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2002 "Python/generated_cases.c.h" + #line 2003 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2021,7 +2022,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2025 "Python/generated_cases.c.h" + #line 2026 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2039,13 +2040,13 @@ if (map == NULL) goto error; - #line 2043 "Python/generated_cases.c.h" + #line 2044 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } #line 1469 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2049 "Python/generated_cases.c.h" + #line 2050 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2093,7 +2094,7 @@ Py_DECREF(ann_dict); } } - #line 2097 "Python/generated_cases.c.h" + #line 2098 "Python/generated_cases.c.h" DISPATCH(); } @@ -2111,14 +2112,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2115 "Python/generated_cases.c.h" + #line 2116 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); #line 1525 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2122 "Python/generated_cases.c.h" + #line 2123 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2134,12 +2135,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2138 "Python/generated_cases.c.h" + #line 2139 "Python/generated_cases.c.h" Py_DECREF(update); #line 1537 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2143 "Python/generated_cases.c.h" + #line 2144 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2152,12 +2153,12 @@ if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2156 "Python/generated_cases.c.h" + #line 2157 "Python/generated_cases.c.h" Py_DECREF(update); #line 1548 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2161 "Python/generated_cases.c.h" + #line 2162 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2173,7 +2174,7 @@ /* 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 2177 "Python/generated_cases.c.h" + #line 2178 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2205,7 +2206,7 @@ // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); - #line 2209 "Python/generated_cases.c.h" + #line 2210 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); @@ -2214,7 +2215,7 @@ res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2218 "Python/generated_cases.c.h" + #line 2219 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2243,7 +2244,7 @@ Py_INCREF(res2); Py_DECREF(global_super); Py_DECREF(class); - #line 2247 "Python/generated_cases.c.h" + #line 2248 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2291,7 +2292,7 @@ NULL | meth | arg1 | ... | argN */ - #line 2295 "Python/generated_cases.c.h" + #line 2296 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1655 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; @@ -2302,12 +2303,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2306 "Python/generated_cases.c.h" + #line 2307 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1664 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2311 "Python/generated_cases.c.h" + #line 2312 "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; } @@ -2334,7 +2335,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2338 "Python/generated_cases.c.h" + #line 2339 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2362,7 +2363,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2366 "Python/generated_cases.c.h" + #line 2367 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2404,7 +2405,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2408 "Python/generated_cases.c.h" + #line 2409 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2429,7 +2430,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2433 "Python/generated_cases.c.h" + #line 2434 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2456,7 +2457,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2460 "Python/generated_cases.c.h" + #line 2461 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2494,7 +2495,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2498 "Python/generated_cases.c.h" + #line 2499 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2528,7 +2529,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2532 "Python/generated_cases.c.h" + #line 2533 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2554,7 +2555,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2558 "Python/generated_cases.c.h" + #line 2559 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2604,7 +2605,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2608 "Python/generated_cases.c.h" + #line 2609 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2625,7 +2626,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2629 "Python/generated_cases.c.h" + #line 2630 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2650,12 +2651,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2654 "Python/generated_cases.c.h" + #line 2655 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 1906 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2659 "Python/generated_cases.c.h" + #line 2660 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2678,7 +2679,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2682 "Python/generated_cases.c.h" + #line 2683 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2705,7 +2706,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2709 "Python/generated_cases.c.h" + #line 2710 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2729,7 +2730,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2733 "Python/generated_cases.c.h" + #line 2734 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2742,12 +2743,12 @@ PyObject *b; #line 1959 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2746 "Python/generated_cases.c.h" + #line 2747 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 1961 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2751 "Python/generated_cases.c.h" + #line 2752 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2759,13 +2760,13 @@ PyObject *b; #line 1965 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2763 "Python/generated_cases.c.h" + #line 2764 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 1967 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2769 "Python/generated_cases.c.h" + #line 2770 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2778,7 +2779,7 @@ PyObject *match; #line 1972 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2782 "Python/generated_cases.c.h" + #line 2783 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 1974 "Python/bytecodes.c" @@ -2789,7 +2790,7 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2793 "Python/generated_cases.c.h" + #line 2794 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 1982 "Python/bytecodes.c" @@ -2801,7 +2802,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2805 "Python/generated_cases.c.h" + #line 2806 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2814,18 +2815,18 @@ #line 1993 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2818 "Python/generated_cases.c.h" + #line 2819 "Python/generated_cases.c.h" Py_DECREF(right); #line 1996 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2825 "Python/generated_cases.c.h" + #line 2826 "Python/generated_cases.c.h" Py_DECREF(right); #line 2001 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2829 "Python/generated_cases.c.h" + #line 2830 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2837,12 +2838,12 @@ #line 2005 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2841 "Python/generated_cases.c.h" + #line 2842 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); #line 2008 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2846 "Python/generated_cases.c.h" + #line 2847 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2855,7 +2856,7 @@ PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2859 "Python/generated_cases.c.h" + #line 2860 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -2864,7 +2865,7 @@ TARGET(JUMP_FORWARD) { #line 2018 "Python/bytecodes.c" JUMPBY(oparg); - #line 2868 "Python/generated_cases.c.h" + #line 2869 "Python/generated_cases.c.h" DISPATCH(); } @@ -2873,7 +2874,7 @@ #line 2022 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2877 "Python/generated_cases.c.h" + #line 2878 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2891,7 +2892,7 @@ } else { int err = PyObject_IsTrue(cond); - #line 2895 "Python/generated_cases.c.h" + #line 2896 "Python/generated_cases.c.h" Py_DECREF(cond); #line 2038 "Python/bytecodes.c" if (err == 0) { @@ -2901,7 +2902,7 @@ if (err < 0) goto pop_1_error; } } - #line 2905 "Python/generated_cases.c.h" + #line 2906 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2918,7 +2919,7 @@ } else { int err = PyObject_IsTrue(cond); - #line 2922 "Python/generated_cases.c.h" + #line 2923 "Python/generated_cases.c.h" Py_DECREF(cond); #line 2058 "Python/bytecodes.c" if (err > 0) { @@ -2928,7 +2929,7 @@ if (err < 0) goto pop_1_error; } } - #line 2932 "Python/generated_cases.c.h" + #line 2933 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2937,7 +2938,7 @@ PyObject *value = stack_pointer[-1]; #line 2068 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2941 "Python/generated_cases.c.h" + #line 2942 "Python/generated_cases.c.h" Py_DECREF(value); #line 2070 "Python/bytecodes.c" JUMPBY(oparg); @@ -2945,7 +2946,7 @@ else { _Py_DECREF_NO_DEALLOC(value); } - #line 2949 "Python/generated_cases.c.h" + #line 2950 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2958,11 +2959,11 @@ JUMPBY(oparg); } else { - #line 2962 "Python/generated_cases.c.h" + #line 2963 "Python/generated_cases.c.h" Py_DECREF(value); #line 2084 "Python/bytecodes.c" } - #line 2966 "Python/generated_cases.c.h" + #line 2967 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2975,7 +2976,7 @@ * (see bpo-30039). */ JUMPBY(-oparg); - #line 2979 "Python/generated_cases.c.h" + #line 2980 "Python/generated_cases.c.h" DISPATCH(); } @@ -2988,7 +2989,7 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2992 "Python/generated_cases.c.h" + #line 2993 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3004,7 +3005,7 @@ // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3008 "Python/generated_cases.c.h" + #line 3009 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); @@ -3016,7 +3017,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3020 "Python/generated_cases.c.h" + #line 3021 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3028,7 +3029,7 @@ #line 2120 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3032 "Python/generated_cases.c.h" + #line 3033 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3041,7 +3042,7 @@ #line 2126 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3045 "Python/generated_cases.c.h" + #line 3046 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3056,7 +3057,7 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3060 "Python/generated_cases.c.h" + #line 3061 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3068,11 +3069,11 @@ #line 2138 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3072 "Python/generated_cases.c.h" + #line 3073 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2141 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3076 "Python/generated_cases.c.h" + #line 3077 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3103,11 +3104,11 @@ if (iter == NULL) { goto error; } - #line 3107 "Python/generated_cases.c.h" + #line 3108 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2168 "Python/bytecodes.c" } - #line 3111 "Python/generated_cases.c.h" + #line 3112 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3149,7 +3150,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3153 "Python/generated_cases.c.h" + #line 3154 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3183,7 +3184,7 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3187 "Python/generated_cases.c.h" + #line 3188 "Python/generated_cases.c.h" DISPATCH(); } @@ -3210,7 +3211,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3214 "Python/generated_cases.c.h" + #line 3215 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3240,7 +3241,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3244 "Python/generated_cases.c.h" + #line 3245 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3268,7 +3269,7 @@ if (next == NULL) { goto error; } - #line 3272 "Python/generated_cases.c.h" + #line 3273 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3292,7 +3293,7 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3296 "Python/generated_cases.c.h" + #line 3297 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { @@ -3322,7 +3323,7 @@ Py_DECREF(enter); goto error; } - #line 3326 "Python/generated_cases.c.h" + #line 3327 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2352 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); @@ -3331,7 +3332,7 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3335 "Python/generated_cases.c.h" + #line 3336 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3369,7 +3370,7 @@ Py_DECREF(enter); goto error; } - #line 3373 "Python/generated_cases.c.h" + #line 3374 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2388 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); @@ -3378,7 +3379,7 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3382 "Python/generated_cases.c.h" + #line 3383 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3411,7 +3412,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3415 "Python/generated_cases.c.h" + #line 3416 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3430,7 +3431,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3434 "Python/generated_cases.c.h" + #line 3435 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3461,7 +3462,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3465 "Python/generated_cases.c.h" + #line 3466 "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; } @@ -3485,7 +3486,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3489 "Python/generated_cases.c.h" + #line 3490 "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; } @@ -3513,7 +3514,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3517 "Python/generated_cases.c.h" + #line 3518 "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; } @@ -3526,7 +3527,7 @@ assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3530 "Python/generated_cases.c.h" + #line 3531 "Python/generated_cases.c.h" DISPATCH(); } @@ -3544,7 +3545,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3548 "Python/generated_cases.c.h" + #line 3549 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3636,7 +3637,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3640 "Python/generated_cases.c.h" + #line 3641 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3658,7 +3659,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3662 "Python/generated_cases.c.h" + #line 3663 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3693,7 +3694,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3697 "Python/generated_cases.c.h" + #line 3698 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3737,7 +3738,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3741 "Python/generated_cases.c.h" + #line 3742 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3755,7 +3756,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3759 "Python/generated_cases.c.h" + #line 3760 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3779,7 +3780,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3783 "Python/generated_cases.c.h" + #line 3784 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3804,7 +3805,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3808 "Python/generated_cases.c.h" + #line 3809 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3840,7 +3841,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3844 "Python/generated_cases.c.h" + #line 3845 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3882,7 +3883,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3886 "Python/generated_cases.c.h" + #line 3887 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3928,7 +3929,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3932 "Python/generated_cases.c.h" + #line 3933 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3974,7 +3975,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3978 "Python/generated_cases.c.h" + #line 3979 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4013,7 +4014,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4017 "Python/generated_cases.c.h" + #line 4018 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4053,7 +4054,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4057 "Python/generated_cases.c.h" + #line 4058 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4083,7 +4084,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4087 "Python/generated_cases.c.h" + #line 4088 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { @@ -4121,7 +4122,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4125 "Python/generated_cases.c.h" + #line 4126 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4163,7 +4164,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4167 "Python/generated_cases.c.h" + #line 4168 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4205,7 +4206,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4209 "Python/generated_cases.c.h" + #line 4210 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4246,7 +4247,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4250 "Python/generated_cases.c.h" + #line 4251 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4258,7 +4259,7 @@ TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { #line 3068 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4262 "Python/generated_cases.c.h" + #line 4263 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4329,14 +4330,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4333 "Python/generated_cases.c.h" + #line 4334 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); #line 3134 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4340 "Python/generated_cases.c.h" + #line 4341 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4380,7 +4381,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4384 "Python/generated_cases.c.h" + #line 4385 "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(); @@ -4408,7 +4409,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4412 "Python/generated_cases.c.h" + #line 4413 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4418,13 +4419,13 @@ PyObject *slice; #line 3198 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4422 "Python/generated_cases.c.h" + #line 4423 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); #line 3200 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4428 "Python/generated_cases.c.h" + #line 4429 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4470,7 +4471,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 4474 "Python/generated_cases.c.h" + #line 4475 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4482,7 +4483,7 @@ #line 3241 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4486 "Python/generated_cases.c.h" + #line 4487 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4509,12 +4510,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4513 "Python/generated_cases.c.h" + #line 4514 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); #line 3261 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4518 "Python/generated_cases.c.h" + #line 4519 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4526,7 +4527,7 @@ PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; #line 3266 "Python/bytecodes.c" assert(oparg >= 2); - #line 4530 "Python/generated_cases.c.h" + #line 4531 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); @@ -4553,7 +4554,7 @@ } opcode = original_opcode; DISPATCH_GOTO(); - #line 4557 "Python/generated_cases.c.h" + #line 4558 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_INSTRUCTION) { @@ -4569,20 +4570,20 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4573 "Python/generated_cases.c.h" + #line 4574 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { #line 3306 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4579 "Python/generated_cases.c.h" + #line 4580 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { #line 3310 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4586 "Python/generated_cases.c.h" + #line 4587 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -4597,7 +4598,7 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4601 "Python/generated_cases.c.h" + #line 4602 "Python/generated_cases.c.h" DISPATCH(); } @@ -4611,7 +4612,7 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4615 "Python/generated_cases.c.h" + #line 4616 "Python/generated_cases.c.h" DISPATCH(); } @@ -4629,7 +4630,7 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4633 "Python/generated_cases.c.h" + #line 4634 "Python/generated_cases.c.h" DISPATCH(); } @@ -4647,7 +4648,7 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4651 "Python/generated_cases.c.h" + #line 4652 "Python/generated_cases.c.h" DISPATCH(); } @@ -4658,19 +4659,19 @@ oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4662 "Python/generated_cases.c.h" + #line 4663 "Python/generated_cases.c.h" } TARGET(CACHE) { #line 3375 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4669 "Python/generated_cases.c.h" + #line 4670 "Python/generated_cases.c.h" } TARGET(RESERVED) { #line 3380 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4676 "Python/generated_cases.c.h" + #line 4677 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index c1a6ed4c18ab..670290e2f3f9 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -512,7 +512,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case SEND: return 2; case SEND_GEN: - return 1; + return 2; case INSTRUMENTED_YIELD_VALUE: return 1; case YIELD_VALUE: From webhook-mailer at python.org Thu May 11 09:01:51 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 11 May 2023 13:01:51 -0000 Subject: [Python-checkins] gh-101819: Fix inverted debug preprocessor check in winconsoleio.c (#104388) Message-ID: <mailman.310.1683810112.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ddc0e70a326180d90a45dfd8abeded9c9f911217 commit: ddc0e70a326180d90a45dfd8abeded9c9f911217 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-11T13:01:05Z summary: gh-101819: Fix inverted debug preprocessor check in winconsoleio.c (#104388) files: M Modules/_io/winconsoleio.c diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index f341cb238ce8..d65e247737a0 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -267,7 +267,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, int fd_is_own = 0; HANDLE handle = NULL; -#ifdef NDEBUG +#ifndef NDEBUG _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); assert(PyObject_TypeCheck(self, state->PyWindowsConsoleIO_Type)); #endif From webhook-mailer at python.org Thu May 11 10:08:29 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 11 May 2023 14:08:29 -0000 Subject: [Python-checkins] gh-87729: improve hit rate of LOAD_SUPER_ATTR specialization (#104270) Message-ID: <mailman.311.1683814109.13550.python-checkins@python.org> https://github.com/python/cpython/commit/77262458fe3fe9f3f0266bbf578675a906b1e353 commit: 77262458fe3fe9f3f0266bbf578675a906b1e353 branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-11T08:08:13-06:00 summary: gh-87729: improve hit rate of LOAD_SUPER_ATTR specialization (#104270) files: M Include/internal/pycore_code.h M Include/internal/pycore_opcode.h M Include/internal/pycore_typeobject.h M Include/opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Objects/typeobject.c M Python/bytecodes.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/opcode_targets.h M Python/specialize.c M Tools/scripts/summarize_stats.py diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index c1f017fdb753..75a23f3f5af5 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -53,9 +53,6 @@ typedef struct { typedef struct { uint16_t counter; - uint16_t class_version[2]; - uint16_t self_type_version[2]; - uint16_t method[4]; } _PySuperAttrCache; #define INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR CACHE_ENTRIES(_PySuperAttrCache) @@ -227,8 +224,8 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range); /* Specialization functions */ -extern void _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *cls, PyObject *self, - _Py_CODEUNIT *instr, PyObject *name, int load_method); +extern void _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *cls, + _Py_CODEUNIT *instr, int load_method); extern void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name); extern void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 52ee70a7bfdc..e823e1bfb5d4 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -42,7 +42,7 @@ const uint8_t _PyOpcode_Caches[256] = { [LOAD_GLOBAL] = 4, [BINARY_OP] = 1, [SEND] = 1, - [LOAD_SUPER_ATTR] = 9, + [LOAD_SUPER_ATTR] = 1, [CALL] = 3, }; @@ -182,6 +182,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL, [LOAD_NAME] = LOAD_NAME, [LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, + [LOAD_SUPER_ATTR_ATTR] = LOAD_SUPER_ATTR, [LOAD_SUPER_ATTR_METHOD] = LOAD_SUPER_ATTR, [MAKE_CELL] = MAKE_CELL, [MAKE_FUNCTION] = MAKE_FUNCTION, @@ -307,29 +308,29 @@ static const char *const _PyOpcode_OpName[267] = { [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", + [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [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", [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -352,9 +353,9 @@ static const char *const _PyOpcode_OpName[267] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -394,22 +395,22 @@ static const char *const _PyOpcode_OpName[267] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", - [168] = "<168>", [169] = "<169>", [170] = "<170>", [CALL] = "CALL", @@ -512,7 +513,6 @@ static const char *const _PyOpcode_OpName[267] = { #endif #define EXTRA_CASES \ - case 168: \ case 169: \ case 170: \ case 175: \ diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index f42f8f62de2c..c7d00002fbc6 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -142,8 +142,6 @@ PyAPI_DATA(PyTypeObject) _PyBufferWrapper_Type; PyObject * _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found); -PyObject * -_PySuper_LookupDescr(PyTypeObject *su_type, PyObject *su_obj, PyObject *name); #ifdef __cplusplus } diff --git a/Include/opcode.h b/Include/opcode.h index f6f4af8c793d..c3b6e5dce49a 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -185,33 +185,34 @@ extern "C" { #define FOR_ITER_TUPLE 63 #define FOR_ITER_RANGE 64 #define FOR_ITER_GEN 65 -#define LOAD_SUPER_ATTR_METHOD 66 -#define LOAD_ATTR_CLASS 67 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 70 -#define LOAD_ATTR_INSTANCE_VALUE 72 -#define LOAD_ATTR_MODULE 73 -#define LOAD_ATTR_PROPERTY 76 -#define LOAD_ATTR_SLOT 77 -#define LOAD_ATTR_WITH_HINT 78 -#define LOAD_ATTR_METHOD_LAZY_DICT 79 -#define LOAD_ATTR_METHOD_NO_DICT 80 -#define LOAD_ATTR_METHOD_WITH_VALUES 81 -#define LOAD_CONST__LOAD_FAST 82 -#define LOAD_FAST__LOAD_CONST 84 -#define LOAD_FAST__LOAD_FAST 86 -#define LOAD_GLOBAL_BUILTIN 87 -#define LOAD_GLOBAL_MODULE 88 -#define STORE_ATTR_INSTANCE_VALUE 111 -#define STORE_ATTR_SLOT 112 -#define STORE_ATTR_WITH_HINT 113 -#define STORE_FAST__LOAD_FAST 153 -#define STORE_FAST__STORE_FAST 154 -#define STORE_SUBSCR_DICT 158 -#define STORE_SUBSCR_LIST_INT 159 -#define UNPACK_SEQUENCE_LIST 160 -#define UNPACK_SEQUENCE_TUPLE 161 -#define UNPACK_SEQUENCE_TWO_TUPLE 166 -#define SEND_GEN 167 +#define LOAD_SUPER_ATTR_ATTR 66 +#define LOAD_SUPER_ATTR_METHOD 67 +#define LOAD_ATTR_CLASS 70 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 72 +#define LOAD_ATTR_INSTANCE_VALUE 73 +#define LOAD_ATTR_MODULE 76 +#define LOAD_ATTR_PROPERTY 77 +#define LOAD_ATTR_SLOT 78 +#define LOAD_ATTR_WITH_HINT 79 +#define LOAD_ATTR_METHOD_LAZY_DICT 80 +#define LOAD_ATTR_METHOD_NO_DICT 81 +#define LOAD_ATTR_METHOD_WITH_VALUES 82 +#define LOAD_CONST__LOAD_FAST 84 +#define LOAD_FAST__LOAD_CONST 86 +#define LOAD_FAST__LOAD_FAST 87 +#define LOAD_GLOBAL_BUILTIN 88 +#define LOAD_GLOBAL_MODULE 111 +#define STORE_ATTR_INSTANCE_VALUE 112 +#define STORE_ATTR_SLOT 113 +#define STORE_ATTR_WITH_HINT 153 +#define STORE_FAST__LOAD_FAST 154 +#define STORE_FAST__STORE_FAST 158 +#define STORE_SUBSCR_DICT 159 +#define STORE_SUBSCR_LIST_INT 160 +#define UNPACK_SEQUENCE_LIST 161 +#define UNPACK_SEQUENCE_TUPLE 166 +#define UNPACK_SEQUENCE_TWO_TUPLE 167 +#define SEND_GEN 168 #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 d4a1593db2c8..3ca5a1aea28a 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -443,6 +443,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12b1 3527 (Add LOAD_SUPER_ATTR) # Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization) # Python 3.12b1 3529 (Inline list/dict/set comprehensions) +# Python 3.12b1 3530 (Shrink the LOAD_SUPER_ATTR caches) # Python 3.13 will start with 3550 @@ -459,7 +460,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 = (3529).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3530).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 d6d478aa1f47..155466b1ab85 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -373,6 +373,7 @@ def pseudo_op(name, op, real_ops): "FOR_ITER_GEN", ], "LOAD_SUPER_ATTR": [ + "LOAD_SUPER_ATTR_ATTR", "LOAD_SUPER_ATTR_METHOD", ], "LOAD_ATTR": [ @@ -450,9 +451,6 @@ def pseudo_op(name, op, real_ops): }, "LOAD_SUPER_ATTR": { "counter": 1, - "class_version": 2, - "self_type_version": 2, - "method": 4, }, "LOAD_ATTR": { "counter": 1, diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 98fac276a873..f1745c919673 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10245,18 +10245,6 @@ _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *me return res; } -PyObject * -_PySuper_LookupDescr(PyTypeObject *su_type, PyObject *su_obj, PyObject *name) -{ - PyTypeObject *su_obj_type = supercheck(su_type, su_obj); - if (su_obj_type == NULL) { - return NULL; - } - PyObject *res = _super_lookup_descr(su_type, su_obj_type, name); - Py_DECREF(su_obj_type); - return res; -} - static PyObject * super_descr_get(PyObject *self, PyObject *obj, PyObject *type) { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1c09dc6be3d6..118a0b5ed439 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1562,17 +1562,18 @@ dummy_func( family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { LOAD_SUPER_ATTR, + LOAD_SUPER_ATTR_ATTR, LOAD_SUPER_ATTR_METHOD, }; - inst(LOAD_SUPER_ATTR, (unused/9, global_super, class, self -- res2 if (oparg & 1), res)) { + inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_LoadSuperAttr(global_super, class, self, next_instr, name, load_method); + _Py_Specialize_LoadSuperAttr(global_super, class, next_instr, load_method); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_SUPER_ATTR, deferred); @@ -1590,17 +1591,38 @@ dummy_func( ERROR_IF(res == NULL, error); } - inst(LOAD_SUPER_ATTR_METHOD, (unused/1, class_version/2, self_type_version/2, method/4, global_super, class, self -- res2, res)) { + inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { + assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); - DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR); - PyTypeObject *self_type = Py_TYPE(self); - DEOPT_IF(self_type->tp_version_tag != self_type_version, LOAD_SUPER_ATTR); - res2 = method; - res = self; // transfer ownership - Py_INCREF(res2); + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + ERROR_IF(res == NULL, error); + DECREF_INPUTS(); + } + + inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- res2, res)) { + assert(oparg & 1); + DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); + DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + int method_found = 0; + res2 = _PySuper_Lookup((PyTypeObject *)class, self, name, &method_found); Py_DECREF(global_super); Py_DECREF(class); + if (res2 == NULL) { + Py_DECREF(self); + ERROR_IF(true, error); + } + if (method_found) { + res = self; // transfer ownership + } else { + Py_DECREF(self); + res = res2; + res2 = NULL; + } } family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a86b895dd43d..373c65e6ce84 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2182,20 +2182,20 @@ TARGET(LOAD_SUPER_ATTR) { PREDICTED(LOAD_SUPER_ATTR); - static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 9, "incorrect cache size"); + static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 1, "incorrect cache size"); PyObject *self = stack_pointer[-1]; PyObject *class = stack_pointer[-2]; PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1569 "Python/bytecodes.c" + #line 1570 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_LoadSuperAttr(global_super, class, self, next_instr, name, load_method); + _Py_Specialize_LoadSuperAttr(global_super, class, next_instr, load_method); DISPATCH_SAME_OPARG(); } STAT_INC(LOAD_SUPER_ATTR, deferred); @@ -2210,7 +2210,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1587 "Python/bytecodes.c" + #line 1588 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); @@ -2220,7 +2220,33 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } - next_instr += 9; + next_instr += 1; + DISPATCH(); + } + + TARGET(LOAD_SUPER_ATTR_ATTR) { + PyObject *self = stack_pointer[-1]; + PyObject *class = stack_pointer[-2]; + PyObject *global_super = stack_pointer[-3]; + PyObject *res2 = NULL; + PyObject *res; + #line 1595 "Python/bytecodes.c" + assert(!(oparg & 1)); + DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); + DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + if (res == NULL) goto pop_3_error; + #line 2242 "Python/generated_cases.c.h" + Py_DECREF(global_super); + Py_DECREF(class); + Py_DECREF(self); + STACK_SHRINK(2); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + next_instr += 1; DISPATCH(); } @@ -2230,25 +2256,32 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - uint32_t class_version = read_u32(&next_instr[1].cache); - uint32_t self_type_version = read_u32(&next_instr[3].cache); - PyObject *method = read_obj(&next_instr[5].cache); - #line 1594 "Python/bytecodes.c" + #line 1606 "Python/bytecodes.c" + assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); - DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR); - PyTypeObject *self_type = Py_TYPE(self); - DEOPT_IF(self_type->tp_version_tag != self_type_version, LOAD_SUPER_ATTR); - res2 = method; - res = self; // transfer ownership - Py_INCREF(res2); + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + int method_found = 0; + res2 = _PySuper_Lookup((PyTypeObject *)class, self, name, &method_found); Py_DECREF(global_super); Py_DECREF(class); - #line 2248 "Python/generated_cases.c.h" + if (res2 == NULL) { + Py_DECREF(self); + if (true) goto pop_3_error; + } + if (method_found) { + res = self; // transfer ownership + } else { + Py_DECREF(self); + res = res2; + res2 = NULL; + } + #line 2281 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; - next_instr += 9; + next_instr += 1; DISPATCH(); } @@ -2258,7 +2291,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1621 "Python/bytecodes.c" + #line 1643 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2292,9 +2325,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2296 "Python/generated_cases.c.h" + #line 2329 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1655 "Python/bytecodes.c" + #line 1677 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2303,12 +2336,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2307 "Python/generated_cases.c.h" + #line 2340 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1664 "Python/bytecodes.c" + #line 1686 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2312 "Python/generated_cases.c.h" + #line 2345 "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; } @@ -2322,7 +2355,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1669 "Python/bytecodes.c" + #line 1691 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2335,7 +2368,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2339 "Python/generated_cases.c.h" + #line 2372 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2350,7 +2383,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1685 "Python/bytecodes.c" + #line 1707 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2363,7 +2396,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2367 "Python/generated_cases.c.h" + #line 2400 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2378,7 +2411,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1701 "Python/bytecodes.c" + #line 1723 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2405,7 +2438,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2409 "Python/generated_cases.c.h" + #line 2442 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2420,7 +2453,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1731 "Python/bytecodes.c" + #line 1753 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2430,7 +2463,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2434 "Python/generated_cases.c.h" + #line 2467 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2445,7 +2478,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1744 "Python/bytecodes.c" + #line 1766 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2457,7 +2490,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2461 "Python/generated_cases.c.h" + #line 2494 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2471,7 +2504,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 1759 "Python/bytecodes.c" + #line 1781 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2495,7 +2528,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2499 "Python/generated_cases.c.h" + #line 2532 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2503,7 +2536,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 1785 "Python/bytecodes.c" + #line 1807 "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); @@ -2529,7 +2562,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2533 "Python/generated_cases.c.h" + #line 2566 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2537,7 +2570,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 1813 "Python/bytecodes.c" + #line 1835 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2555,7 +2588,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2559 "Python/generated_cases.c.h" + #line 2592 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2566,7 +2599,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 1833 "Python/bytecodes.c" + #line 1855 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2605,7 +2638,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2609 "Python/generated_cases.c.h" + #line 2642 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2616,7 +2649,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 1874 "Python/bytecodes.c" + #line 1896 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2626,7 +2659,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2630 "Python/generated_cases.c.h" + #line 2663 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2638,7 +2671,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1893 "Python/bytecodes.c" + #line 1915 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2651,12 +2684,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2655 "Python/generated_cases.c.h" + #line 2688 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1906 "Python/bytecodes.c" + #line 1928 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2660 "Python/generated_cases.c.h" + #line 2693 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2667,7 +2700,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1910 "Python/bytecodes.c" + #line 1932 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2679,7 +2712,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2683 "Python/generated_cases.c.h" + #line 2716 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2690,7 +2723,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1925 "Python/bytecodes.c" + #line 1947 "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); @@ -2706,7 +2739,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2710 "Python/generated_cases.c.h" + #line 2743 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2717,7 +2750,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1944 "Python/bytecodes.c" + #line 1966 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2730,7 +2763,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2734 "Python/generated_cases.c.h" + #line 2767 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2741,14 +2774,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1959 "Python/bytecodes.c" + #line 1981 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2747 "Python/generated_cases.c.h" + #line 2780 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1961 "Python/bytecodes.c" + #line 1983 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2752 "Python/generated_cases.c.h" + #line 2785 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2758,15 +2791,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1965 "Python/bytecodes.c" + #line 1987 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2764 "Python/generated_cases.c.h" + #line 2797 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1967 "Python/bytecodes.c" + #line 1989 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2770 "Python/generated_cases.c.h" + #line 2803 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2777,12 +2810,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1972 "Python/bytecodes.c" + #line 1994 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2783 "Python/generated_cases.c.h" + #line 2816 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1974 "Python/bytecodes.c" + #line 1996 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2790,10 +2823,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2794 "Python/generated_cases.c.h" + #line 2827 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1982 "Python/bytecodes.c" + #line 2004 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2802,7 +2835,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2806 "Python/generated_cases.c.h" + #line 2839 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2812,21 +2845,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1993 "Python/bytecodes.c" + #line 2015 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2819 "Python/generated_cases.c.h" + #line 2852 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1996 "Python/bytecodes.c" + #line 2018 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2826 "Python/generated_cases.c.h" + #line 2859 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2001 "Python/bytecodes.c" + #line 2023 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2830 "Python/generated_cases.c.h" + #line 2863 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2835,15 +2868,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2005 "Python/bytecodes.c" + #line 2027 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2842 "Python/generated_cases.c.h" + #line 2875 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2008 "Python/bytecodes.c" + #line 2030 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2847 "Python/generated_cases.c.h" + #line 2880 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2852,29 +2885,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2012 "Python/bytecodes.c" + #line 2034 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2860 "Python/generated_cases.c.h" + #line 2893 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2018 "Python/bytecodes.c" + #line 2040 "Python/bytecodes.c" JUMPBY(oparg); - #line 2869 "Python/generated_cases.c.h" + #line 2902 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2022 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2878 "Python/generated_cases.c.h" + #line 2911 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2882,7 +2915,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2028 "Python/bytecodes.c" + #line 2050 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2892,9 +2925,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2896 "Python/generated_cases.c.h" + #line 2929 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2038 "Python/bytecodes.c" + #line 2060 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2902,14 +2935,14 @@ if (err < 0) goto pop_1_error; } } - #line 2906 "Python/generated_cases.c.h" + #line 2939 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2048 "Python/bytecodes.c" + #line 2070 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2919,9 +2952,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2923 "Python/generated_cases.c.h" + #line 2956 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2058 "Python/bytecodes.c" + #line 2080 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2929,67 +2962,67 @@ if (err < 0) goto pop_1_error; } } - #line 2933 "Python/generated_cases.c.h" + #line 2966 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2068 "Python/bytecodes.c" + #line 2090 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2942 "Python/generated_cases.c.h" + #line 2975 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2070 "Python/bytecodes.c" + #line 2092 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2950 "Python/generated_cases.c.h" + #line 2983 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2078 "Python/bytecodes.c" + #line 2100 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2963 "Python/generated_cases.c.h" + #line 2996 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2084 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" } - #line 2967 "Python/generated_cases.c.h" + #line 3000 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2088 "Python/bytecodes.c" + #line 2110 "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 2980 "Python/generated_cases.c.h" + #line 3013 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2097 "Python/bytecodes.c" + #line 2119 "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 2993 "Python/generated_cases.c.h" + #line 3026 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3000,16 +3033,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2105 "Python/bytecodes.c" + #line 2127 "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 3009 "Python/generated_cases.c.h" + #line 3042 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2110 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3017,7 +3050,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3021 "Python/generated_cases.c.h" + #line 3054 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3026,10 +3059,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2120 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3033 "Python/generated_cases.c.h" + #line 3066 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3039,10 +3072,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2126 "Python/bytecodes.c" + #line 2148 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3046 "Python/generated_cases.c.h" + #line 3079 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3053,11 +3086,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2132 "Python/bytecodes.c" + #line 2154 "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 3061 "Python/generated_cases.c.h" + #line 3094 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3066,14 +3099,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2138 "Python/bytecodes.c" + #line 2160 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3073 "Python/generated_cases.c.h" + #line 3106 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2141 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3077 "Python/generated_cases.c.h" + #line 3110 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3081,7 +3114,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2145 "Python/bytecodes.c" + #line 2167 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3104,11 +3137,11 @@ if (iter == NULL) { goto error; } - #line 3108 "Python/generated_cases.c.h" + #line 3141 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2168 "Python/bytecodes.c" + #line 2190 "Python/bytecodes.c" } - #line 3112 "Python/generated_cases.c.h" + #line 3145 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3119,7 +3152,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2187 "Python/bytecodes.c" + #line 2209 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3150,7 +3183,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3154 "Python/generated_cases.c.h" + #line 3187 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3158,7 +3191,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2220 "Python/bytecodes.c" + #line 2242 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3184,14 +3217,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3188 "Python/generated_cases.c.h" + #line 3221 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2248 "Python/bytecodes.c" + #line 2270 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3211,7 +3244,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3215 "Python/generated_cases.c.h" + #line 3248 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3221,7 +3254,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2270 "Python/bytecodes.c" + #line 2292 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3241,7 +3274,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3245 "Python/generated_cases.c.h" + #line 3278 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3251,7 +3284,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2292 "Python/bytecodes.c" + #line 2314 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3269,7 +3302,7 @@ if (next == NULL) { goto error; } - #line 3273 "Python/generated_cases.c.h" + #line 3306 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3278,7 +3311,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2312 "Python/bytecodes.c" + #line 2334 "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); @@ -3293,14 +3326,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3297 "Python/generated_cases.c.h" + #line 3330 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2329 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3323,16 +3356,16 @@ Py_DECREF(enter); goto error; } - #line 3327 "Python/generated_cases.c.h" + #line 3360 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2352 "Python/bytecodes.c" + #line 2374 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3336 "Python/generated_cases.c.h" + #line 3369 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3344,7 +3377,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2362 "Python/bytecodes.c" + #line 2384 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3370,16 +3403,16 @@ Py_DECREF(enter); goto error; } - #line 3374 "Python/generated_cases.c.h" + #line 3407 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2388 "Python/bytecodes.c" + #line 2410 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3383 "Python/generated_cases.c.h" + #line 3416 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3391,7 +3424,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2397 "Python/bytecodes.c" + #line 2419 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3412,7 +3445,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3416 "Python/generated_cases.c.h" + #line 3449 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3421,7 +3454,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2420 "Python/bytecodes.c" + #line 2442 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3431,7 +3464,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3435 "Python/generated_cases.c.h" + #line 3468 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3445,7 +3478,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 2432 "Python/bytecodes.c" + #line 2454 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3462,7 +3495,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3466 "Python/generated_cases.c.h" + #line 3499 "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; } @@ -3476,7 +3509,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2451 "Python/bytecodes.c" + #line 2473 "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); @@ -3486,7 +3519,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3490 "Python/generated_cases.c.h" + #line 3523 "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; } @@ -3500,7 +3533,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2463 "Python/bytecodes.c" + #line 2485 "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; @@ -3514,7 +3547,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3518 "Python/generated_cases.c.h" + #line 3551 "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; } @@ -3523,16 +3556,16 @@ } TARGET(KW_NAMES) { - #line 2479 "Python/bytecodes.c" + #line 2501 "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 3531 "Python/generated_cases.c.h" + #line 3564 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2485 "Python/bytecodes.c" + #line 2507 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3545,7 +3578,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3549 "Python/generated_cases.c.h" + #line 3582 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3555,7 +3588,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2530 "Python/bytecodes.c" + #line 2552 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3637,7 +3670,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3641 "Python/generated_cases.c.h" + #line 3674 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3649,7 +3682,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2618 "Python/bytecodes.c" + #line 2640 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3659,7 +3692,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3663 "Python/generated_cases.c.h" + #line 3696 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3668,7 +3701,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2630 "Python/bytecodes.c" + #line 2652 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3694,7 +3727,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3698 "Python/generated_cases.c.h" + #line 3731 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3702,7 +3735,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2658 "Python/bytecodes.c" + #line 2680 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3738,7 +3771,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3742 "Python/generated_cases.c.h" + #line 3775 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3746,7 +3779,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2696 "Python/bytecodes.c" + #line 2718 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3756,7 +3789,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3760 "Python/generated_cases.c.h" + #line 3793 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3769,7 +3802,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2708 "Python/bytecodes.c" + #line 2730 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3780,7 +3813,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3784 "Python/generated_cases.c.h" + #line 3817 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3794,7 +3827,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2722 "Python/bytecodes.c" + #line 2744 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3805,7 +3838,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3809 "Python/generated_cases.c.h" + #line 3842 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3819,7 +3852,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2736 "Python/bytecodes.c" + #line 2758 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3841,7 +3874,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3845 "Python/generated_cases.c.h" + #line 3878 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3855,7 +3888,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2761 "Python/bytecodes.c" + #line 2783 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3883,7 +3916,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3887 "Python/generated_cases.c.h" + #line 3920 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3897,7 +3930,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2792 "Python/bytecodes.c" + #line 2814 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3929,7 +3962,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3933 "Python/generated_cases.c.h" + #line 3966 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3943,7 +3976,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2827 "Python/bytecodes.c" + #line 2849 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -3975,7 +4008,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3979 "Python/generated_cases.c.h" + #line 4012 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3989,7 +4022,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2862 "Python/bytecodes.c" + #line 2884 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4014,7 +4047,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4018 "Python/generated_cases.c.h" + #line 4051 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4027,7 +4060,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2889 "Python/bytecodes.c" + #line 2911 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4054,7 +4087,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4058 "Python/generated_cases.c.h" + #line 4091 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4066,7 +4099,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2919 "Python/bytecodes.c" + #line 2941 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4084,14 +4117,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4088 "Python/generated_cases.c.h" + #line 4121 "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 2939 "Python/bytecodes.c" + #line 2961 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4122,7 +4155,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4126 "Python/generated_cases.c.h" + #line 4159 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4135,7 +4168,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2973 "Python/bytecodes.c" + #line 2995 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4164,7 +4197,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4168 "Python/generated_cases.c.h" + #line 4201 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4177,7 +4210,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3005 "Python/bytecodes.c" + #line 3027 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4206,7 +4239,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4210 "Python/generated_cases.c.h" + #line 4243 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4219,7 +4252,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3037 "Python/bytecodes.c" + #line 3059 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4247,7 +4280,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4251 "Python/generated_cases.c.h" + #line 4284 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4257,9 +4290,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3068 "Python/bytecodes.c" + #line 3090 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4263 "Python/generated_cases.c.h" + #line 4296 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4268,7 +4301,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3072 "Python/bytecodes.c" + #line 3094 "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)); @@ -4330,14 +4363,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4334 "Python/generated_cases.c.h" + #line 4367 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3134 "Python/bytecodes.c" + #line 3156 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4341 "Python/generated_cases.c.h" + #line 4374 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4352,7 +4385,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 3144 "Python/bytecodes.c" + #line 3166 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4381,14 +4414,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4385 "Python/generated_cases.c.h" + #line 4418 "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 3175 "Python/bytecodes.c" + #line 3197 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4409,7 +4442,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4413 "Python/generated_cases.c.h" + #line 4446 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4417,15 +4450,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3198 "Python/bytecodes.c" + #line 3220 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4423 "Python/generated_cases.c.h" + #line 4456 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3200 "Python/bytecodes.c" + #line 3222 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4429 "Python/generated_cases.c.h" + #line 4462 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4436,7 +4469,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 3204 "Python/bytecodes.c" + #line 3226 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4471,7 +4504,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 4475 "Python/generated_cases.c.h" + #line 4508 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4480,10 +4513,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3241 "Python/bytecodes.c" + #line 3263 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4487 "Python/generated_cases.c.h" + #line 4520 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4495,7 +4528,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3246 "Python/bytecodes.c" + #line 3268 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4510,12 +4543,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4514 "Python/generated_cases.c.h" + #line 4547 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3261 "Python/bytecodes.c" + #line 3283 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4519 "Python/generated_cases.c.h" + #line 4552 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4525,16 +4558,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3266 "Python/bytecodes.c" + #line 3288 "Python/bytecodes.c" assert(oparg >= 2); - #line 4531 "Python/generated_cases.c.h" + #line 4564 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_LINE) { - #line 3270 "Python/bytecodes.c" + #line 3292 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _PyFrame_SetStackPointer(frame, stack_pointer); int original_opcode = _Py_call_instrumentation_line( @@ -4554,11 +4587,11 @@ } opcode = original_opcode; DISPATCH_GOTO(); - #line 4558 "Python/generated_cases.c.h" + #line 4591 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3292 "Python/bytecodes.c" + #line 3314 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4570,26 +4603,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4574 "Python/generated_cases.c.h" + #line 4607 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3306 "Python/bytecodes.c" + #line 3328 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4580 "Python/generated_cases.c.h" + #line 4613 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3310 "Python/bytecodes.c" + #line 3332 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4587 "Python/generated_cases.c.h" + #line 4620 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3315 "Python/bytecodes.c" + #line 3337 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4598,12 +4631,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4602 "Python/generated_cases.c.h" + #line 4635 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3326 "Python/bytecodes.c" + #line 3348 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4612,12 +4645,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4616 "Python/generated_cases.c.h" + #line 4649 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3337 "Python/bytecodes.c" + #line 3359 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4630,12 +4663,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4634 "Python/generated_cases.c.h" + #line 4667 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3352 "Python/bytecodes.c" + #line 3374 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4648,30 +4681,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4652 "Python/generated_cases.c.h" + #line 4685 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3367 "Python/bytecodes.c" + #line 3389 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4663 "Python/generated_cases.c.h" + #line 4696 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3375 "Python/bytecodes.c" + #line 3397 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4670 "Python/generated_cases.c.h" + #line 4703 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3380 "Python/bytecodes.c" + #line 3402 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4677 "Python/generated_cases.c.h" + #line 4710 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 670290e2f3f9..daf3a3888f0d 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -209,6 +209,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case LOAD_SUPER_ATTR: return 3; + case LOAD_SUPER_ATTR_ATTR: + return 3; case LOAD_SUPER_ATTR_METHOD: return 3; case LOAD_ATTR: @@ -599,6 +601,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case LOAD_SUPER_ATTR: return ((oparg & 1) ? 1 : 0) + 1; + case LOAD_SUPER_ATTR_ATTR: + return ((oparg & 1) ? 1 : 0) + 1; case LOAD_SUPER_ATTR_METHOD: return 2; case LOAD_ATTR: @@ -783,7 +787,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -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, INSTR_FMT_IXC00000000 }; +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; @@ -892,8 +896,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [DICT_UPDATE] = { true, INSTR_FMT_IB }, [DICT_MERGE] = { true, INSTR_FMT_IB }, [MAP_ADD] = { true, INSTR_FMT_IB }, - [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IXC00000000 }, + [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC }, + [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC }, + [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC }, [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 00f15ff98da4..f2742f4ad1f2 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -65,29 +65,29 @@ static void *opcode_targets[256] = { &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, + &&TARGET_LOAD_SUPER_ATTR_ATTR, &&TARGET_LOAD_SUPER_ATTR_METHOD, - &&TARGET_LOAD_ATTR_CLASS, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, + &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&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_RETURN_VALUE, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_SETUP_ANNOTATIONS, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_GLOBAL_MODULE, &&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_LOAD_GLOBAL_MODULE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -152,24 +152,24 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, - &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, - &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, diff --git a/Python/specialize.c b/Python/specialize.c index 45f1cb412db2..5071d8ef9a49 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -323,11 +323,8 @@ _PyCode_Quicken(PyCodeObject *code) /* Super */ -#define SPEC_FAIL_SUPER_NOT_LOAD_METHOD 9 -#define SPEC_FAIL_SUPER_BAD_CLASS 10 -#define SPEC_FAIL_SUPER_SHADOWED 11 -#define SPEC_FAIL_SUPER_NOT_METHOD 12 -#define SPEC_FAIL_SUPER_ERROR_OR_NOT_FOUND 13 +#define SPEC_FAIL_SUPER_BAD_CLASS 9 +#define SPEC_FAIL_SUPER_SHADOWED 10 /* Attributes */ @@ -516,15 +513,10 @@ specialize_module_load_attr( /* Attribute specialization */ void -_Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *cls, PyObject *self, - _Py_CODEUNIT *instr, PyObject *name, int load_method) { +_Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *cls, _Py_CODEUNIT *instr, int load_method) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_SUPER_ATTR] == INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR); _PySuperAttrCache *cache = (_PySuperAttrCache *)(instr + 1); - if (!load_method) { - SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_NOT_LOAD_METHOD); - goto fail; - } if (global_super != (PyObject *)&PySuper_Type) { SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_SHADOWED); goto fail; @@ -533,23 +525,8 @@ _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *cls, PyObject *se SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_BAD_CLASS); goto fail; } - PyTypeObject *tp = (PyTypeObject *)cls; - PyObject *res = _PySuper_LookupDescr(tp, self, name); - if (res == NULL) { - SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_ERROR_OR_NOT_FOUND); - PyErr_Clear(); - goto fail; - } - if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) { - write_u32(cache->class_version, tp->tp_version_tag); - write_u32(cache->self_type_version, Py_TYPE(self)->tp_version_tag); - write_obj(cache->method, res); // borrowed - instr->op.code = LOAD_SUPER_ATTR_METHOD; - Py_DECREF(res); - goto success; - } - Py_DECREF(res); - SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_NOT_METHOD); + instr->op.code = load_method ? LOAD_SUPER_ATTR_METHOD : LOAD_SUPER_ATTR_ATTR; + goto success; fail: STAT_INC(LOAD_SUPER_ATTR, failure); diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index 4f25ba36d866..9c881897c2de 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -226,11 +226,13 @@ def pretty(defname): def kind_to_text(kind, defines, opname): if kind <= 8: return pretty(defines[kind][0]) - if opname.endswith("ATTR"): + if opname == "LOAD_SUPER_ATTR": + opname = "SUPER" + elif opname.endswith("ATTR"): opname = "ATTR" - if opname in ("FOR_ITER", "SEND"): + elif opname in ("FOR_ITER", "SEND"): opname = "ITER" - if opname.endswith("SUBSCR"): + elif opname.endswith("SUBSCR"): opname = "SUBSCR" for name in defines[kind]: if name.startswith(opname): From webhook-mailer at python.org Thu May 11 10:44:46 2023 From: webhook-mailer at python.org (zware) Date: Thu, 11 May 2023 14:44:46 -0000 Subject: [Python-checkins] gh-104057: Fix direct invocation of test_support (GH-104069) Message-ID: <mailman.312.1683816288.13550.python-checkins@python.org> https://github.com/python/cpython/commit/27419a71b5aa18baf24f4e640c5a6e8df9338928 commit: 27419a71b5aa18baf24f4e640c5a6e8df9338928 branch: main author: Kirill Podoprigora <kirill.bast9 at mail.ru> committer: zware <zachary.ware at gmail.com> date: 2023-05-11T09:44:39-05:00 summary: gh-104057: Fix direct invocation of test_support (GH-104069) files: M Lib/test/test_support.py diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index 7738ca5e9b43..85d692f30974 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -30,7 +30,7 @@ def setUpClass(cls): "test.support.warnings_helper", like=".*used in test_support.*" ) cls._test_support_token = support.ignore_deprecations_from( - "test.test_support", like=".*You should NOT be seeing this.*" + __name__, like=".*You should NOT be seeing this.*" ) assert len(warnings.filters) == orig_filter_len + 2 From webhook-mailer at python.org Thu May 11 13:12:12 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 11 May 2023 17:12:12 -0000 Subject: [Python-checkins] gh-104301: Allow leading whitespace in disambiguated pdb statements (#104342) Message-ID: <mailman.313.1683825133.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0449ffe3a4ddf03367a5ee3d943c89f442b7b407 commit: 0449ffe3a4ddf03367a5ee3d943c89f442b7b407 branch: main author: James Gerity <snoopjedi at gmail.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-11T18:12:02+01:00 summary: gh-104301: Allow leading whitespace in disambiguated pdb statements (#104342) files: A Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst M Doc/library/pdb.rst M Lib/pdb.py M Lib/pydoc_data/topics.py M Lib/test/test_pdb.py diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 74bffef5562a..ef52370bff80 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -602,9 +602,17 @@ can be overridden by the local file. 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 set a global variable, you can prefix the - assignment command with a :keyword:`global` statement on the same line, - e.g.:: + resembles a debugger command, e.g.: + + .. code-block:: none + + (Pdb) ! n=42 + (Pdb) + + To set a global variable, you can prefix the assignment command with a + :keyword:`global` statement on the same line, e.g.: + + .. code-block:: none (Pdb) global list_options; list_options = ['-l'] (Pdb) diff --git a/Lib/pdb.py b/Lib/pdb.py index b3dc5a455e56..6b6feac1ddea 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -440,7 +440,7 @@ def displayhook(self, obj): self.message(repr(obj)) def default(self, line): - if line[:1] == '!': line = line[1:] + if line[:1] == '!': line = line[1:].strip() locals = self.curframe_locals globals = self.curframe.f_globals try: @@ -1642,9 +1642,12 @@ def help_exec(self): 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 - assign to a global variable you must always prefix the command - with a 'global' command, e.g.: + first word of the statement resembles a debugger command, e.g.: + (Pdb) ! n=42 + (Pdb) + + To assign to a global variable you must always prefix the command with + a 'global' command, e.g.: (Pdb) global list_options; list_options = ['-l'] (Pdb) """ diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 1babb5ce9476..3aaaee67fa35 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -5283,11 +5283,14 @@ 'current\n' ' stack frame. The exclamation point can be omitted unless the ' 'first\n' - ' word of the statement resembles a debugger command. To set ' - 'a\n' - ' global variable, you can prefix the assignment command with ' - 'a\n' - ' "global" statement on the same line, e.g.:\n' + ' word of the statement resembles a debugger command, e.g.:' + '\n' + ' (Pdb) ! n=42\n' + ' (Pdb)\n' + '\n' + ' To set a global variable, you can prefix the assignment command ' + ' with \n' + ' a "global" statement on the same line, e.g.:\n' '\n' " (Pdb) global list_options; list_options = ['-l']\n" ' (Pdb)\n' diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 482c92dbf1f6..037673dd0ea8 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1798,6 +1798,29 @@ def test_pdb_issue_gh_101517(): (Pdb) continue """ +def test_pdb_ambiguous_statements(): + """See GH-104301 + + Make sure that ambiguous statements prefixed by '!' are properly disambiguated + + >>> with PdbTestInput([ + ... '! n = 42', # disambiguated statement: reassign the name n + ... 'n', # advance the debugger into the print() + ... 'continue' + ... ]): + ... n = -1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... print(f"The value of n is {n}") + > <doctest test.test_pdb.test_pdb_ambiguous_statements[0]>(8)<module>() + -> print(f"The value of n is {n}") + (Pdb) ! n = 42 + (Pdb) n + The value of n is 42 + > <doctest test.test_pdb.test_pdb_ambiguous_statements[0]>(1)<module>() + -> with PdbTestInput([ + (Pdb) continue + """ + @support.requires_subprocess() class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst b/Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst new file mode 100644 index 000000000000..a44ad765e624 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst @@ -0,0 +1 @@ +Allow leading whitespace in disambiguated statements in :mod:`pdb`. From webhook-mailer at python.org Thu May 11 17:23:59 2023 From: webhook-mailer at python.org (gpshead) Date: Thu, 11 May 2023 21:23:59 -0000 Subject: [Python-checkins] gh-99108: Refresh HACL* from upstream (#104401) Message-ID: <mailman.314.1683840241.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7d7dd4cd70ed997ed7c3cda867c4e7b1ab02b205 commit: 7d7dd4cd70ed997ed7c3cda867c4e7b1ab02b205 branch: main author: Jonathan Protzenko <protz at microsoft.com> committer: gpshead <greg at krypto.org> date: 2023-05-11T21:23:52Z summary: gh-99108: Refresh HACL* from upstream (#104401) Refresh HACL* from upstream and add a SHA3 test hashing over 4GiB of data. files: M Lib/test/test_hashlib.py M Modules/_hacl/Hacl_Hash_SHA3.c M Modules/_hacl/refresh.sh diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 08cb5eb0c2bb..73d758a3631b 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -359,6 +359,15 @@ def test_sha256_update_over_4gb(self): h.update(b"hello world") self.assertEqual(h.hexdigest(), "a5364f7a52ebe2e25f1838a4ca715a893b6fd7a23f2a0d9e9762120da8b1bf53") + @requires_resource('cpu') + def test_sha3_256_update_over_4gb(self): + zero_1mb = b"\0" * 1024 * 1024 + h = hashlib.sha3_256() + for i in range(0, 4096): + h.update(zero_1mb) + h.update(b"hello world") + self.assertEqual(h.hexdigest(), "e2d4535e3b613135c14f2fe4e026d7ad8d569db44901740beffa30d430acb038") + def check(self, name, data, hexdigest, shake=False, **kwargs): length = len(hexdigest)//2 hexdigest = hexdigest.lower() diff --git a/Modules/_hacl/Hacl_Hash_SHA3.c b/Modules/_hacl/Hacl_Hash_SHA3.c index 100afe7c2c6d..58eb436881d4 100644 --- a/Modules/_hacl/Hacl_Hash_SHA3.c +++ b/Modules/_hacl/Hacl_Hash_SHA3.c @@ -244,7 +244,7 @@ Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint Hacl_Streaming_Keccak_hash_buf block_state = s.block_state; uint64_t total_len = s.total_len; Spec_Hash_Definitions_hash_alg i = block_state.fst; - if ((uint64_t)len > (uint64_t)0xffffffffU - total_len) + if ((uint64_t)len > (uint64_t)0xffffffffffffffffU - total_len) { return (uint32_t)1U; } diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh index 220ebbe55613..d2ba05f30d86 100755 --- a/Modules/_hacl/refresh.sh +++ b/Modules/_hacl/refresh.sh @@ -22,7 +22,7 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. -expected_hacl_star_rev=363eae2c2eb60e46f182ddd4bd1cd3f1d00b35c9 +expected_hacl_star_rev=b6903a3e6458000730c3d83174d4b08d6d3e2ece hacl_dir="$(realpath "$1")" cd "$(dirname "$0")" From webhook-mailer at python.org Thu May 11 18:46:02 2023 From: webhook-mailer at python.org (corona10) Date: Thu, 11 May 2023 22:46:02 -0000 Subject: [Python-checkins] gh-104396: uuid.py to skip platform check for emscripten and wasi (gh-104397) Message-ID: <mailman.315.1683845163.13550.python-checkins@python.org> https://github.com/python/cpython/commit/434db68ee31514ddc4aa93f8dfc2eb874d3669c5 commit: 434db68ee31514ddc4aa93f8dfc2eb874d3669c5 branch: main author: Jeong, YunWon <69878+youknowone at users.noreply.github.com> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-12T07:45:55+09:00 summary: gh-104396: uuid.py to skip platform check for emscripten and wasi (gh-104397) files: M Lib/uuid.py diff --git a/Lib/uuid.py b/Lib/uuid.py index 697f3b455970..470bc0d68597 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -53,7 +53,7 @@ __author__ = 'Ka-Ping Yee <ping at zesty.ca>' # The recognized platforms - known behaviors -if sys.platform in ('win32', 'darwin'): +if sys.platform in ('win32', 'darwin', 'emscripten', 'wasi'): _AIX = _LINUX = False else: import platform From webhook-mailer at python.org Thu May 11 19:41:33 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 11 May 2023 23:41:33 -0000 Subject: [Python-checkins] gh-104392: Remove _paramspec_tvars from typing (#104393) Message-ID: <mailman.316.1683848494.13550.python-checkins@python.org> https://github.com/python/cpython/commit/37a5d256b97bc9d2a0ff445997fec851e328ebad commit: 37a5d256b97bc9d2a0ff445997fec851e328ebad branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-11T16:41:26-07:00 summary: gh-104392: Remove _paramspec_tvars from typing (#104393) This does nothing. files: A Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 4f8cba88632d..62c7dd31a629 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -775,8 +775,7 @@ def Concatenate(self, parameters): "ParamSpec variable or ellipsis.") msg = "Concatenate[arg, ...]: each arg must be a type." parameters = (*(_type_check(p, msg) for p in parameters[:-1]), parameters[-1]) - return _ConcatenateGenericAlias(self, parameters, - _paramspec_tvars=True) + return _ConcatenateGenericAlias(self, parameters) @_SpecialForm @@ -1307,8 +1306,7 @@ def __getattr__(self, attr): raise AttributeError(attr) def __setattr__(self, attr, val): - if _is_dunder(attr) or attr in {'_name', '_inst', '_nparams', - '_paramspec_tvars'}: + if _is_dunder(attr) or attr in {'_name', '_inst', '_nparams'}: super().__setattr__(attr, val) else: setattr(self.__origin__, attr, val) @@ -1362,15 +1360,13 @@ class _GenericAlias(_BaseGenericAlias, _root=True): # ClassVar[float] # TypeVar[bool] - def __init__(self, origin, args, *, inst=True, name=None, - _paramspec_tvars=False): + def __init__(self, origin, args, *, inst=True, name=None): super().__init__(origin, inst=inst, name=name) if not isinstance(args, tuple): args = (args,) self.__args__ = tuple(... if a is _TypingEllipsis else a for a in args) self.__parameters__ = _collect_parameters(args) - self._paramspec_tvars = _paramspec_tvars if not name: self.__module__ = origin.__module__ @@ -1513,8 +1509,7 @@ def _make_substitution(self, args, new_arg_by_param): return new_args def copy_with(self, args): - return self.__class__(self.__origin__, args, name=self._name, inst=self._inst, - _paramspec_tvars=self._paramspec_tvars) + return self.__class__(self.__origin__, args, name=self._name, inst=self._inst) def __repr__(self): if self._name: @@ -1624,8 +1619,7 @@ def __reduce__(self): class _CallableType(_SpecialGenericAlias, _root=True): def copy_with(self, params): return _CallableGenericAlias(self.__origin__, params, - name=self._name, inst=self._inst, - _paramspec_tvars=True) + name=self._name, inst=self._inst) def __getitem__(self, params): if not isinstance(params, tuple) or len(params) != 2: @@ -1869,8 +1863,7 @@ def __class_getitem__(cls, params): new_args.append(new_arg) params = tuple(new_args) - return _GenericAlias(cls, params, - _paramspec_tvars=True) + return _GenericAlias(cls, params) def __init_subclass__(cls, *args, **kwargs): super().__init_subclass__(*args, **kwargs) diff --git a/Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst b/Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst new file mode 100644 index 000000000000..b441b2acd19f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst @@ -0,0 +1,2 @@ +Remove undocumented and unused ``_paramspec_tvars`` attribute from some +classes in :mod:`typing`. From webhook-mailer at python.org Thu May 11 19:48:30 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 11 May 2023 23:48:30 -0000 Subject: [Python-checkins] gh-104377: fix cell in comprehension that is free in outer scope (#104394) Message-ID: <mailman.317.1683848910.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ac66cc17f21653b66321b50d0a1f792982fca21f commit: ac66cc17f21653b66321b50d0a1f792982fca21f branch: main author: Carl Meyer <carl at oddbird.net> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-11T16:48:21-07:00 summary: gh-104377: fix cell in comprehension that is free in outer scope (#104394) files: M Lib/test/test_listcomps.py M Python/compile.c diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 1cc202bb599a..b2a3b7ea3e49 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -117,15 +117,15 @@ def get_output(moddict, name): newcode = code def get_output(moddict, name): return moddict[name] - ns = ns or {} + newns = ns.copy() if ns else {} try: - exec(newcode, ns) + exec(newcode, newns) except raises as e: # We care about e.g. NameError vs UnboundLocalError self.assertIs(type(e), raises) else: for k, v in (outputs or {}).items(): - self.assertEqual(get_output(ns, k), v) + self.assertEqual(get_output(newns, k), v) def test_lambdas_with_iteration_var_as_default(self): code = """ @@ -180,6 +180,26 @@ def test_closure_can_jump_over_comp_scope(self): z = [x() for x in items] """ outputs = {"z": [2, 2, 2, 2, 2]} + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + + def test_cell_inner_free_outer(self): + code = """ + def f(): + return [lambda: x for x in (x, [1])[1]] + x = ... + y = [fn() for fn in f()] + """ + outputs = {"y": [1]} + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + + def test_free_inner_cell_outer(self): + code = """ + g = 2 + def f(): + return g + y = [g for x in [1]] + """ + outputs = {"y": [2]} self._check_in_scopes(code, outputs) def test_inner_cell_shadows_outer_redefined(self): @@ -203,6 +223,37 @@ def inner(): outputs = {"x": -1} self._check_in_scopes(code, outputs, ns={"g": -1}) + def test_explicit_global(self): + code = """ + global g + x = g + g = 2 + items = [g for g in [1]] + y = g + """ + outputs = {"x": 1, "y": 2, "items": [1]} + self._check_in_scopes(code, outputs, ns={"g": 1}) + + def test_explicit_global_2(self): + code = """ + global g + x = g + g = 2 + items = [g for x in [1]] + y = g + """ + outputs = {"x": 1, "y": 2, "items": [2]} + self._check_in_scopes(code, outputs, ns={"g": 1}) + + def test_explicit_global_3(self): + code = """ + global g + fns = [lambda: g for g in [2]] + items = [fn() for fn in fns] + """ + outputs = {"items": [2]} + self._check_in_scopes(code, outputs, ns={"g": 1}) + def test_assignment_expression(self): code = """ x = -1 @@ -250,7 +301,7 @@ def g(): g() """ outputs = {"x": 1} - self._check_in_scopes(code, outputs) + self._check_in_scopes(code, outputs, scopes=["module", "function"]) def test_introspecting_frame_locals(self): code = """ diff --git a/Python/compile.c b/Python/compile.c index 941c6e9d4fdb..f8d0197e9f06 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5028,14 +5028,19 @@ push_inlined_comprehension_state(struct compiler *c, location loc, long scope = (symbol >> SCOPE_OFFSET) & SCOPE_MASK; PyObject *outv = PyDict_GetItemWithError(c->u->u_ste->ste_symbols, k); if (outv == NULL) { + assert(PyErr_Occurred()); return ERROR; } assert(PyLong_Check(outv)); long outsc = (PyLong_AS_LONG(outv) >> SCOPE_OFFSET) & SCOPE_MASK; - if (scope != outsc) { + if (scope != outsc && !(scope == CELL && outsc == FREE)) { // If a name has different scope inside than outside the // comprehension, we need to temporarily handle it with the - // right scope while compiling the comprehension. + // right scope while compiling the comprehension. (If it's free + // in outer scope and cell in inner scope, we can't treat it as + // both cell and free in the same function, but treating it as + // free throughout is fine; it's *_DEREF either way.) + if (state->temp_symbols == NULL) { state->temp_symbols = PyDict_New(); if (state->temp_symbols == NULL) { @@ -5071,7 +5076,11 @@ push_inlined_comprehension_state(struct compiler *c, location loc, // comprehension and restore the original one after ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames); if (scope == CELL) { - ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars); + if (outsc == FREE) { + ADDOP_NAME(c, loc, MAKE_CELL, k, freevars); + } else { + ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars); + } } if (PyList_Append(state->pushed_locals, k) < 0) { return ERROR; From webhook-mailer at python.org Fri May 12 01:22:47 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 12 May 2023 05:22:47 -0000 Subject: [Python-checkins] gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378) Message-ID: <mailman.318.1683868968.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a0a98ddb31591357bead4694b21717cb4034924f commit: a0a98ddb31591357bead4694b21717cb4034924f branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-12T05:22:40Z summary: gh-104371: Fix calls to `__release_buffer__` while an exception is active (#104378) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: M Lib/test/test_buffer.py M Objects/typeobject.c diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 2c65ae811481..94fc9d4436b7 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -4749,6 +4749,19 @@ def __buffer__(self, flags): c.clear() self.assertIs(c.buffer, None) + def test_release_buffer_with_exception_set(self): + class A: + def __buffer__(self, flags): + return memoryview(bytes(8)) + def __release_buffer__(self, view): + pass + + b = bytearray(8) + with memoryview(b): + # now b.extend will raise an exception due to exports + with self.assertRaises(BufferError): + b.extend(A()) + if __name__ == "__main__": unittest.main() diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f1745c919673..f40e197f8c23 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9117,6 +9117,12 @@ releasebuffer_maybe_call_super(PyObject *self, Py_buffer *buffer) static void releasebuffer_call_python(PyObject *self, Py_buffer *buffer) { + // bf_releasebuffer may be called while an exception is already active. + // We have no way to report additional errors up the stack, because + // this slot returns void, so we simply stash away the active exception + // and restore it after the call to Python returns. + PyObject *exc = PyErr_GetRaisedException(); + PyObject *mv; bool is_buffer_wrapper = Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type; if (is_buffer_wrapper) { @@ -9124,7 +9130,7 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer) // __release_buffer__() that __buffer__() returned. PyBufferWrapper *bw = (PyBufferWrapper *)buffer->obj; if (bw->mv == NULL) { - return; + goto end; } mv = Py_NewRef(bw->mv); } @@ -9134,7 +9140,7 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer) mv = PyMemoryView_FromBuffer(buffer); if (mv == NULL) { PyErr_WriteUnraisable(self); - return; + goto end; } // Set the memoryview to restricted mode, which forbids // users from saving any reference to the underlying buffer @@ -9155,6 +9161,10 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer) PyObject_CallMethodNoArgs(mv, &_Py_ID(release)); } Py_DECREF(mv); +end: + assert(!PyErr_Occurred()); + + PyErr_SetRaisedException(exc); } /* From webhook-mailer at python.org Fri May 12 02:01:38 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Fri, 12 May 2023 06:01:38 -0000 Subject: [Python-checkins] gh-91896: Improve visibility of `ByteString` deprecation warnings (#104294) Message-ID: <mailman.319.1683871300.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f0f5bb32043e1223d8c413e763cd93061d4f9fac commit: f0f5bb32043e1223d8c413e763cd93061d4f9fac branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-11T23:01:31-07:00 summary: gh-91896: Improve visibility of `ByteString` deprecation warnings (#104294) files: M Lib/collections/abc.py M Lib/test/libregrtest/refleak.py M Lib/test/test_collections.py M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py index 86ca8b8a8414..60b1eb60fa6a 100644 --- a/Lib/collections/abc.py +++ b/Lib/collections/abc.py @@ -1,3 +1,12 @@ from _collections_abc import * from _collections_abc import __all__ from _collections_abc import _CallableGenericAlias + +_deprecated_ByteString = globals().pop("ByteString") + +def __getattr__(attr): + if attr == "ByteString": + import warnings + warnings._deprecated("collections.abc.ByteString", remove=(3, 14)) + return _deprecated_ByteString + raise AttributeError(f"module 'collections.abc' has no attribute {attr!r}") diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 2de8c6cfbc61..776a9e9b587d 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -48,11 +48,13 @@ def dash_R(ns, test_name, test_func): else: zdc = zipimport._zip_directory_cache.copy() abcs = {} - for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: - if not isabstract(abc): - continue - for obj in abc.__subclasses__() + [abc]: - abcs[obj] = _get_dump(obj)[0] + # catch and ignore collections.abc.ByteString deprecation + with warnings.catch_warnings(action='ignore', category=DeprecationWarning): + for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: + if not isabstract(abc): + continue + for obj in abc.__subclasses__() + [abc]: + abcs[obj] = _get_dump(obj)[0] # bpo-31217: Integer pool to get a single integer object for the same # value. The pool is used to prevent false alarm when checking for memory @@ -173,7 +175,9 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): zipimport._zip_directory_cache.update(zdc) # Clear ABC registries, restoring previously saved ABC registries. - abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] + # ignore deprecation warning for collections.abc.ByteString + with warnings.catch_warnings(action='ignore', category=DeprecationWarning): + abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] abs_classes = filter(isabstract, abs_classes) for abc in abs_classes: for obj in abc.__subclasses__() + [abc]: diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index bb8b352518ef..f0736b8081fe 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -11,6 +11,7 @@ import string import sys from test import support +from test.support.import_helper import import_fresh_module import types import unittest @@ -25,7 +26,7 @@ from collections.abc import Set, MutableSet from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView from collections.abc import Sequence, MutableSequence -from collections.abc import ByteString, Buffer +from collections.abc import Buffer class TestUserObjects(unittest.TestCase): @@ -1939,6 +1940,8 @@ def assert_index_same(seq1, seq2, index_args): nativeseq, seqseq, (letter, start, stop)) def test_ByteString(self): + with self.assertWarns(DeprecationWarning): + from collections.abc import ByteString for sample in [bytes, bytearray]: with self.assertWarns(DeprecationWarning): self.assertIsInstance(sample(), ByteString) @@ -1960,6 +1963,11 @@ class X(ByteString): pass # No metaclass conflict class Z(ByteString, Awaitable): pass + def test_ByteString_attribute_access(self): + collections_abc = import_fresh_module("collections.abc") + with self.assertWarns(DeprecationWarning): + collections_abc.ByteString + def test_Buffer(self): for sample in [bytes, bytearray, memoryview]: self.assertIsInstance(sample(b"x"), Buffer) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f162e587810a..3422dc1ed3f5 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -8,6 +8,7 @@ import re import sys import warnings +from test.support.import_helper import import_fresh_module from unittest import TestCase, main, skipUnless, skip from unittest.mock import patch from copy import copy, deepcopy @@ -3908,7 +3909,14 @@ class MyChain(typing.ChainMap[str, T]): ... self.assertEqual(MyChain[int]().__orig_class__, MyChain[int]) def test_all_repr_eq_any(self): - objs = (getattr(typing, el) for el in typing.__all__) + typing = import_fresh_module("typing") + with warnings.catch_warnings(record=True) as wlog: + warnings.filterwarnings('always', '', DeprecationWarning) + objs = [getattr(typing, el) for el in typing.__all__] + self.assertEqual( + [str(w.message) for w in wlog], + ["'typing.ByteString' is deprecated and slated for removal in Python 3.14"] + ) for obj in objs: self.assertNotEqual(repr(obj), '') self.assertEqual(obj, obj) @@ -5996,8 +6004,16 @@ def test_mutablesequence(self): self.assertNotIsInstance((), typing.MutableSequence) def test_bytestring(self): - self.assertIsInstance(b'', typing.ByteString) - self.assertIsInstance(bytearray(b''), typing.ByteString) + with self.assertWarns(DeprecationWarning): + from typing import ByteString + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(b'', ByteString) + with self.assertWarns(DeprecationWarning): + self.assertIsInstance(bytearray(b''), ByteString) + with self.assertWarns(DeprecationWarning): + class Foo(ByteString): ... + with self.assertWarns(DeprecationWarning): + class Bar(ByteString, typing.Awaitable): ... def test_list(self): self.assertIsSubclass(list, typing.List) @@ -8293,6 +8309,10 @@ def test_no_isinstance(self): class SpecialAttrsTests(BaseTestCase): def test_special_attrs(self): + with warnings.catch_warnings( + action='ignore', category=DeprecationWarning + ): + typing_ByteString = typing.ByteString cls_to_check = { # ABC classes typing.AbstractSet: 'AbstractSet', @@ -8301,7 +8321,7 @@ def test_special_attrs(self): typing.AsyncIterable: 'AsyncIterable', typing.AsyncIterator: 'AsyncIterator', typing.Awaitable: 'Awaitable', - typing.ByteString: 'ByteString', + typing_ByteString: 'ByteString', typing.Callable: 'Callable', typing.ChainMap: 'ChainMap', typing.Collection: 'Collection', @@ -8626,6 +8646,8 @@ def test_all_exported_names(self): getattr(v, '__module__', None) == typing.__name__ ) } + # Deprecated; added dynamically via module __getattr__ + computed_all.add("ByteString") self.assertSetEqual(computed_all, actual_all) diff --git a/Lib/typing.py b/Lib/typing.py index 62c7dd31a629..bf7bd241972a 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1599,6 +1599,22 @@ def __or__(self, right): def __ror__(self, left): return Union[left, self] + +class _DeprecatedGenericAlias(_SpecialGenericAlias, _root=True): + def __init__( + self, origin, nparams, *, removal_version, inst=True, name=None + ): + super().__init__(origin, nparams, inst=inst, name=name) + self._removal_version = removal_version + + def __instancecheck__(self, inst): + import warnings + warnings._deprecated( + f"{self.__module__}.{self._name}", remove=self._removal_version + ) + return super().__instancecheck__(inst) + + class _CallableGenericAlias(_NotIterable, _GenericAlias, _root=True): def __repr__(self): assert self._name == 'Callable' @@ -2756,7 +2772,6 @@ class Other(Leaf): # Error reported by type checker MutableMapping = _alias(collections.abc.MutableMapping, 2) Sequence = _alias(collections.abc.Sequence, 1) MutableSequence = _alias(collections.abc.MutableSequence, 1) -ByteString = _alias(collections.abc.ByteString, 0) # Not generic # Tuple accepts variable number of parameters. Tuple = _TupleType(tuple, -1, inst=False, name='Tuple') Tuple.__doc__ = \ @@ -3556,3 +3571,18 @@ def method(self) -> None: # read-only property, TypeError if it's a builtin class. pass return method + + +def __getattr__(attr): + if attr == "ByteString": + import warnings + warnings._deprecated("typing.ByteString", remove=(3, 14)) + with warnings.catch_warnings( + action="ignore", category=DeprecationWarning + ): + # Not generic + ByteString = globals()["ByteString"] = _DeprecatedGenericAlias( + collections.abc.ByteString, 0, removal_version=(3, 14) + ) + return ByteString + raise AttributeError(f"module 'typing' has no attribute {attr!r}") From webhook-mailer at python.org Fri May 12 02:48:49 2023 From: webhook-mailer at python.org (vstinner) Date: Fri, 12 May 2023 06:48:49 -0000 Subject: [Python-checkins] gh-87526: Remove dead initialization from _zoneinfo parse_abbr() (#24700) Message-ID: <mailman.320.1683874130.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3c2992e58b033a6c8adcb52b53c42a96002e7034 commit: 3c2992e58b033a6c8adcb52b53c42a96002e7034 branch: main author: Alex Henrie <alexhenrie24 at gmail.com> committer: vstinner <vstinner at python.org> date: 2023-05-12T08:48:42+02:00 summary: gh-87526: Remove dead initialization from _zoneinfo parse_abbr() (#24700) files: M Modules/_zoneinfo.c diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index 3b2d282d65ca..c8c791b6d7c0 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -1709,11 +1709,11 @@ static Py_ssize_t parse_abbr(const char *const p, PyObject **abbr) { const char *ptr = p; - char buff = *ptr; const char *str_start; const char *str_end; if (*ptr == '<') { + char buff; ptr++; str_start = ptr; while ((buff = *ptr) != '>') { From webhook-mailer at python.org Fri May 12 03:11:35 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 12 May 2023 07:11:35 -0000 Subject: [Python-checkins] Fix refleak in `super_descr_get` (#104408) Message-ID: <mailman.321.1683875496.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a781484c8e9834538e5ee7b9e2e6bec7b679e033 commit: a781484c8e9834538e5ee7b9e2e6bec7b679e033 branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-12T12:41:27+05:30 summary: Fix refleak in `super_descr_get` (#104408) files: M Objects/typeobject.c diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f40e197f8c23..a1ad5021c415 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10277,8 +10277,10 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type) return NULL; newobj = (superobject *)PySuper_Type.tp_new(&PySuper_Type, NULL, NULL); - if (newobj == NULL) + if (newobj == NULL) { + Py_DECREF(obj_type); return NULL; + } newobj->type = (PyTypeObject*)Py_NewRef(su->type); newobj->obj = Py_NewRef(obj); newobj->obj_type = obj_type; From webhook-mailer at python.org Fri May 12 03:30:50 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 12 May 2023 07:30:50 -0000 Subject: [Python-checkins] gh-101819: Prepare _io._IOBase for module state (#104386) Message-ID: <mailman.322.1683876650.13550.python-checkins@python.org> https://github.com/python/cpython/commit/15795b57d92ee6315b5c8263290944b16834b5f2 commit: 15795b57d92ee6315b5c8263290944b16834b5f2 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-12T07:30:26Z summary: gh-101819: Prepare _io._IOBase for module state (#104386) - Add PyIOBase_Type to _io module state - Pass defining class to _io._IOBase.fileno files: M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/clinic/iobase.c.h M Modules/_io/iobase.c diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ee4eca70e2af..2457cb124036 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -582,6 +582,7 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { return 0; Py_VISIT(state->unsupported_operation); + Py_VISIT(state->PyIOBase_Type); Py_VISIT(state->PyIncrementalNewlineDecoder_Type); Py_VISIT(state->PyRawIOBase_Type); Py_VISIT(state->PyBufferedIOBase_Type); @@ -609,6 +610,7 @@ iomodule_clear(PyObject *mod) { return 0; Py_CLEAR(state->unsupported_operation); + Py_CLEAR(state->PyIOBase_Type); Py_CLEAR(state->PyIncrementalNewlineDecoder_Type); Py_CLEAR(state->PyRawIOBase_Type); Py_CLEAR(state->PyBufferedIOBase_Type); @@ -751,6 +753,7 @@ PyInit__io(void) } // Base classes + state->PyIOBase_Type = (PyTypeObject *)Py_NewRef(&PyIOBase_Type); ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 44d651338e69..ae06fecc48b4 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -149,6 +149,7 @@ struct _io_state { PyObject *unsupported_operation; /* Types */ + PyTypeObject *PyIOBase_Type; PyTypeObject *PyIncrementalNewlineDecoder_Type; PyTypeObject *PyRawIOBase_Type; PyTypeObject *PyBufferedIOBase_Type; diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 727398800bec..7e6b3b5b78e8 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -231,20 +231,24 @@ PyDoc_STRVAR(_io__IOBase_fileno__doc__, "fileno($self, /)\n" "--\n" "\n" -"Returns underlying file descriptor if one exists.\n" +"Return underlying file descriptor if one exists.\n" "\n" -"OSError is raised if the IO object does not use a file descriptor."); +"Raise OSError if the IO object does not use a file descriptor."); #define _IO__IOBASE_FILENO_METHODDEF \ - {"fileno", (PyCFunction)_io__IOBase_fileno, METH_NOARGS, _io__IOBase_fileno__doc__}, + {"fileno", _PyCFunction_CAST(_io__IOBase_fileno), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_fileno__doc__}, static PyObject * -_io__IOBase_fileno_impl(PyObject *self); +_io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls); static PyObject * -_io__IOBase_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) +_io__IOBase_fileno(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__IOBase_fileno_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "fileno() takes no arguments"); + return NULL; + } + return _io__IOBase_fileno_impl(self, cls); } PyDoc_STRVAR(_io__IOBase_isatty__doc__, @@ -416,4 +420,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=b6d4845254da1da2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=63bc25a5bfcecaf0 input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index a74e46cc8dc5..26f2a3155bda 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -511,15 +511,17 @@ iobase_exit(PyObject *self, PyObject *args) /*[clinic input] _io._IOBase.fileno + cls: defining_class + / -Returns underlying file descriptor if one exists. +Return underlying file descriptor if one exists. -OSError is raised if the IO object does not use a file descriptor. +Raise OSError if the IO object does not use a file descriptor. [clinic start generated code]*/ static PyObject * -_io__IOBase_fileno_impl(PyObject *self) -/*[clinic end generated code: output=7cc0973f0f5f3b73 input=4e37028947dc1cc8]*/ +_io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls) +/*[clinic end generated code: output=7caaa32a6f4ada3d input=1927c8bea5c85099]*/ { _PyIO_State *state = IO_STATE(); return iobase_unsupported(state, "fileno"); From webhook-mailer at python.org Fri May 12 03:30:50 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 12 May 2023 07:30:50 -0000 Subject: [Python-checkins] gh-104413: Fix refleak when super attribute throws AttributeError (#104414) Message-ID: <mailman.323.1683876651.13550.python-checkins@python.org> https://github.com/python/cpython/commit/718b13277217e90232da5edf7ab3267e59189698 commit: 718b13277217e90232da5edf7ab3267e59189698 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-12T13:00:14+05:30 summary: gh-104413: Fix refleak when super attribute throws AttributeError (#104414) files: M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 118a0b5ed439..eee9147dd866 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1598,8 +1598,8 @@ dummy_func( STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - ERROR_IF(res == NULL, error); DECREF_INPUTS(); + ERROR_IF(res == NULL, error); } inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- res2, res)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 373c65e6ce84..2ea15e98cb02 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2237,11 +2237,13 @@ STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - if (res == NULL) goto pop_3_error; - #line 2242 "Python/generated_cases.c.h" + #line 2241 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); + #line 1602 "Python/bytecodes.c" + if (res == NULL) goto pop_3_error; + #line 2247 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2277,7 +2279,7 @@ res = res2; res2 = NULL; } - #line 2281 "Python/generated_cases.c.h" + #line 2283 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2325,7 +2327,7 @@ NULL | meth | arg1 | ... | argN */ - #line 2329 "Python/generated_cases.c.h" + #line 2331 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1677 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; @@ -2336,12 +2338,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2340 "Python/generated_cases.c.h" + #line 2342 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1686 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2345 "Python/generated_cases.c.h" + #line 2347 "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; } @@ -2368,7 +2370,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2372 "Python/generated_cases.c.h" + #line 2374 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2396,7 +2398,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2400 "Python/generated_cases.c.h" + #line 2402 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2438,7 +2440,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2442 "Python/generated_cases.c.h" + #line 2444 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2463,7 +2465,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2467 "Python/generated_cases.c.h" + #line 2469 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2490,7 +2492,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2494 "Python/generated_cases.c.h" + #line 2496 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2528,7 +2530,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2532 "Python/generated_cases.c.h" + #line 2534 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2562,7 +2564,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2566 "Python/generated_cases.c.h" + #line 2568 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2588,7 +2590,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2592 "Python/generated_cases.c.h" + #line 2594 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2638,7 +2640,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2642 "Python/generated_cases.c.h" + #line 2644 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2659,7 +2661,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2663 "Python/generated_cases.c.h" + #line 2665 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2684,12 +2686,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2688 "Python/generated_cases.c.h" + #line 2690 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 1928 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2693 "Python/generated_cases.c.h" + #line 2695 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2712,7 +2714,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2716 "Python/generated_cases.c.h" + #line 2718 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2739,7 +2741,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2743 "Python/generated_cases.c.h" + #line 2745 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2763,7 +2765,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2767 "Python/generated_cases.c.h" + #line 2769 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2776,12 +2778,12 @@ PyObject *b; #line 1981 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2780 "Python/generated_cases.c.h" + #line 2782 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 1983 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2785 "Python/generated_cases.c.h" + #line 2787 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2793,13 +2795,13 @@ PyObject *b; #line 1987 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2797 "Python/generated_cases.c.h" + #line 2799 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 1989 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2803 "Python/generated_cases.c.h" + #line 2805 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2812,7 +2814,7 @@ PyObject *match; #line 1994 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2816 "Python/generated_cases.c.h" + #line 2818 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 1996 "Python/bytecodes.c" @@ -2823,7 +2825,7 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2827 "Python/generated_cases.c.h" + #line 2829 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2004 "Python/bytecodes.c" @@ -2835,7 +2837,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2839 "Python/generated_cases.c.h" + #line 2841 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2848,18 +2850,18 @@ #line 2015 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2852 "Python/generated_cases.c.h" + #line 2854 "Python/generated_cases.c.h" Py_DECREF(right); #line 2018 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2859 "Python/generated_cases.c.h" + #line 2861 "Python/generated_cases.c.h" Py_DECREF(right); #line 2023 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2863 "Python/generated_cases.c.h" + #line 2865 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2871,12 +2873,12 @@ #line 2027 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2875 "Python/generated_cases.c.h" + #line 2877 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); #line 2030 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2880 "Python/generated_cases.c.h" + #line 2882 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2889,7 +2891,7 @@ PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2893 "Python/generated_cases.c.h" + #line 2895 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -2898,7 +2900,7 @@ TARGET(JUMP_FORWARD) { #line 2040 "Python/bytecodes.c" JUMPBY(oparg); - #line 2902 "Python/generated_cases.c.h" + #line 2904 "Python/generated_cases.c.h" DISPATCH(); } @@ -2907,7 +2909,7 @@ #line 2044 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2911 "Python/generated_cases.c.h" + #line 2913 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2925,7 +2927,7 @@ } else { int err = PyObject_IsTrue(cond); - #line 2929 "Python/generated_cases.c.h" + #line 2931 "Python/generated_cases.c.h" Py_DECREF(cond); #line 2060 "Python/bytecodes.c" if (err == 0) { @@ -2935,7 +2937,7 @@ if (err < 0) goto pop_1_error; } } - #line 2939 "Python/generated_cases.c.h" + #line 2941 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2952,7 +2954,7 @@ } else { int err = PyObject_IsTrue(cond); - #line 2956 "Python/generated_cases.c.h" + #line 2958 "Python/generated_cases.c.h" Py_DECREF(cond); #line 2080 "Python/bytecodes.c" if (err > 0) { @@ -2962,7 +2964,7 @@ if (err < 0) goto pop_1_error; } } - #line 2966 "Python/generated_cases.c.h" + #line 2968 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2971,7 +2973,7 @@ PyObject *value = stack_pointer[-1]; #line 2090 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2975 "Python/generated_cases.c.h" + #line 2977 "Python/generated_cases.c.h" Py_DECREF(value); #line 2092 "Python/bytecodes.c" JUMPBY(oparg); @@ -2979,7 +2981,7 @@ else { _Py_DECREF_NO_DEALLOC(value); } - #line 2983 "Python/generated_cases.c.h" + #line 2985 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2992,11 +2994,11 @@ JUMPBY(oparg); } else { - #line 2996 "Python/generated_cases.c.h" + #line 2998 "Python/generated_cases.c.h" Py_DECREF(value); #line 2106 "Python/bytecodes.c" } - #line 3000 "Python/generated_cases.c.h" + #line 3002 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3009,7 +3011,7 @@ * (see bpo-30039). */ JUMPBY(-oparg); - #line 3013 "Python/generated_cases.c.h" + #line 3015 "Python/generated_cases.c.h" DISPATCH(); } @@ -3022,7 +3024,7 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3026 "Python/generated_cases.c.h" + #line 3028 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3038,7 +3040,7 @@ // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3042 "Python/generated_cases.c.h" + #line 3044 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); @@ -3050,7 +3052,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3054 "Python/generated_cases.c.h" + #line 3056 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3062,7 +3064,7 @@ #line 2142 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3066 "Python/generated_cases.c.h" + #line 3068 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3075,7 +3077,7 @@ #line 2148 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3079 "Python/generated_cases.c.h" + #line 3081 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3090,7 +3092,7 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3094 "Python/generated_cases.c.h" + #line 3096 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3102,11 +3104,11 @@ #line 2160 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3106 "Python/generated_cases.c.h" + #line 3108 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2163 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3110 "Python/generated_cases.c.h" + #line 3112 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3137,11 +3139,11 @@ if (iter == NULL) { goto error; } - #line 3141 "Python/generated_cases.c.h" + #line 3143 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2190 "Python/bytecodes.c" } - #line 3145 "Python/generated_cases.c.h" + #line 3147 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3183,7 +3185,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3187 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3217,7 +3219,7 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3221 "Python/generated_cases.c.h" + #line 3223 "Python/generated_cases.c.h" DISPATCH(); } @@ -3244,7 +3246,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3248 "Python/generated_cases.c.h" + #line 3250 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3274,7 +3276,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3278 "Python/generated_cases.c.h" + #line 3280 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3302,7 +3304,7 @@ if (next == NULL) { goto error; } - #line 3306 "Python/generated_cases.c.h" + #line 3308 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3326,7 +3328,7 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3330 "Python/generated_cases.c.h" + #line 3332 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { @@ -3356,7 +3358,7 @@ Py_DECREF(enter); goto error; } - #line 3360 "Python/generated_cases.c.h" + #line 3362 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2374 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); @@ -3365,7 +3367,7 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3369 "Python/generated_cases.c.h" + #line 3371 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3403,7 +3405,7 @@ Py_DECREF(enter); goto error; } - #line 3407 "Python/generated_cases.c.h" + #line 3409 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2410 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); @@ -3412,7 +3414,7 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3416 "Python/generated_cases.c.h" + #line 3418 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3445,7 +3447,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3449 "Python/generated_cases.c.h" + #line 3451 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3464,7 +3466,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3468 "Python/generated_cases.c.h" + #line 3470 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3495,7 +3497,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3499 "Python/generated_cases.c.h" + #line 3501 "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; } @@ -3519,7 +3521,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3523 "Python/generated_cases.c.h" + #line 3525 "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; } @@ -3547,7 +3549,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3551 "Python/generated_cases.c.h" + #line 3553 "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; } @@ -3560,7 +3562,7 @@ assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3564 "Python/generated_cases.c.h" + #line 3566 "Python/generated_cases.c.h" DISPATCH(); } @@ -3578,7 +3580,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3582 "Python/generated_cases.c.h" + #line 3584 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3670,7 +3672,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3674 "Python/generated_cases.c.h" + #line 3676 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3692,7 +3694,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3696 "Python/generated_cases.c.h" + #line 3698 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3727,7 +3729,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3731 "Python/generated_cases.c.h" + #line 3733 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3771,7 +3773,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3775 "Python/generated_cases.c.h" + #line 3777 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3789,7 +3791,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3793 "Python/generated_cases.c.h" + #line 3795 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3813,7 +3815,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3817 "Python/generated_cases.c.h" + #line 3819 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3838,7 +3840,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3842 "Python/generated_cases.c.h" + #line 3844 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3874,7 +3876,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3878 "Python/generated_cases.c.h" + #line 3880 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3916,7 +3918,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3920 "Python/generated_cases.c.h" + #line 3922 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3962,7 +3964,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3966 "Python/generated_cases.c.h" + #line 3968 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4008,7 +4010,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4012 "Python/generated_cases.c.h" + #line 4014 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4047,7 +4049,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4051 "Python/generated_cases.c.h" + #line 4053 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4087,7 +4089,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4091 "Python/generated_cases.c.h" + #line 4093 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4117,7 +4119,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4121 "Python/generated_cases.c.h" + #line 4123 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { @@ -4155,7 +4157,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4159 "Python/generated_cases.c.h" + #line 4161 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4197,7 +4199,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4201 "Python/generated_cases.c.h" + #line 4203 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4239,7 +4241,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4243 "Python/generated_cases.c.h" + #line 4245 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4280,7 +4282,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4284 "Python/generated_cases.c.h" + #line 4286 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4292,7 +4294,7 @@ TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { #line 3090 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4296 "Python/generated_cases.c.h" + #line 4298 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4363,14 +4365,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4367 "Python/generated_cases.c.h" + #line 4369 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); #line 3156 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4374 "Python/generated_cases.c.h" + #line 4376 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4414,7 +4416,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4418 "Python/generated_cases.c.h" + #line 4420 "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(); @@ -4442,7 +4444,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4446 "Python/generated_cases.c.h" + #line 4448 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4452,13 +4454,13 @@ PyObject *slice; #line 3220 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4456 "Python/generated_cases.c.h" + #line 4458 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); #line 3222 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4462 "Python/generated_cases.c.h" + #line 4464 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4504,7 +4506,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 4508 "Python/generated_cases.c.h" + #line 4510 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4516,7 +4518,7 @@ #line 3263 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4520 "Python/generated_cases.c.h" + #line 4522 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4543,12 +4545,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4547 "Python/generated_cases.c.h" + #line 4549 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); #line 3283 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4552 "Python/generated_cases.c.h" + #line 4554 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4560,7 +4562,7 @@ PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; #line 3288 "Python/bytecodes.c" assert(oparg >= 2); - #line 4564 "Python/generated_cases.c.h" + #line 4566 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); @@ -4587,7 +4589,7 @@ } opcode = original_opcode; DISPATCH_GOTO(); - #line 4591 "Python/generated_cases.c.h" + #line 4593 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_INSTRUCTION) { @@ -4603,20 +4605,20 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4607 "Python/generated_cases.c.h" + #line 4609 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { #line 3328 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4613 "Python/generated_cases.c.h" + #line 4615 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { #line 3332 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4620 "Python/generated_cases.c.h" + #line 4622 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -4631,7 +4633,7 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4635 "Python/generated_cases.c.h" + #line 4637 "Python/generated_cases.c.h" DISPATCH(); } @@ -4645,7 +4647,7 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4649 "Python/generated_cases.c.h" + #line 4651 "Python/generated_cases.c.h" DISPATCH(); } @@ -4663,7 +4665,7 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4667 "Python/generated_cases.c.h" + #line 4669 "Python/generated_cases.c.h" DISPATCH(); } @@ -4681,7 +4683,7 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4685 "Python/generated_cases.c.h" + #line 4687 "Python/generated_cases.c.h" DISPATCH(); } @@ -4692,19 +4694,19 @@ oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4696 "Python/generated_cases.c.h" + #line 4698 "Python/generated_cases.c.h" } TARGET(CACHE) { #line 3397 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4703 "Python/generated_cases.c.h" + #line 4705 "Python/generated_cases.c.h" } TARGET(RESERVED) { #line 3402 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4710 "Python/generated_cases.c.h" + #line 4712 "Python/generated_cases.c.h" } From webhook-mailer at python.org Fri May 12 04:34:13 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 12 May 2023 08:34:13 -0000 Subject: [Python-checkins] gh-104389: Add 'unused' keyword to Argument Clinic C converters (#104390) Message-ID: <mailman.324.1683880454.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b2c1b4da1935639cb89fbbad0ce170a1182537bd commit: b2c1b4da1935639cb89fbbad0ce170a1182537bd branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-12T10:34:00+02:00 summary: gh-104389: Add 'unused' keyword to Argument Clinic C converters (#104390) Use the unused keyword param in the converter to explicitly mark an argument as unused: /*[clinic input] SomeBaseClass.stubmethod flag: bool(unused=True) [clinic start generated code]*/ files: A Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst M Doc/howto/clinic.rst M Lib/test/test_clinic.py M Tools/clinic/clinic.py diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 6ebc2d9b0a71..4620b4617e34 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -775,6 +775,9 @@ All Argument Clinic converters accept the following arguments: because :pep:`8` mandates that the Python library may not use annotations. + ``unused`` + Wrap the argument with :c:macro:`Py_UNUSED` in the impl function signature. + In addition, some converters accept additional arguments. Here is a list of these arguments, along with their meanings: diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 6aaf4d1ed8d5..28d9f6509264 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -774,6 +774,44 @@ def test_legacy_converters(self): module, function = block.signatures self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter) + def test_unused_param(self): + block = self.parse(""" + module foo + foo.func + fn: object + k: float + i: float(unused=True) + / + * + flag: bool(unused=True) = False + """) + sig = block.signatures[1] # Function index == 1 + params = sig.parameters + conv = lambda fn: params[fn].converter + dataset = ( + {"name": "fn", "unused": False}, + {"name": "k", "unused": False}, + {"name": "i", "unused": True}, + {"name": "flag", "unused": True}, + ) + for param in dataset: + name, unused = param.values() + with self.subTest(name=name, unused=unused): + p = conv(name) + # Verify that the unused flag is parsed correctly. + self.assertEqual(unused, p.unused) + + # Now, check that we'll produce correct code. + decl = p.simple_declaration(in_parser=False) + if unused: + self.assertIn("Py_UNUSED", decl) + else: + self.assertNotIn("Py_UNUSED", decl) + + # Make sure the Py_UNUSED macro is not used in the parser body. + parser_decl = p.simple_declaration(in_parser=True) + self.assertNotIn("Py_UNUSED", parser_decl) + def parse(self, text): c = FakeClinic() parser = DSLParser(c) diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst b/Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst new file mode 100644 index 000000000000..854e1cca967c --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst @@ -0,0 +1,2 @@ +Argument Clinic C converters now accept the ``unused`` keyword, for wrapping +a parameter with :c:macro:`Py_UNUSED`. Patch by Erlend E. Aasland. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 2ae8a02aa6d2..19c4cd299f0b 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2599,6 +2599,9 @@ class CConverter(metaclass=CConverterAutoRegister): # Every non-abstract subclass should supply a valid value. c_ignored_default = 'NULL' + # If true, wrap with Py_UNUSED. + unused = False + # The C converter *function* to be used, if any. # (If this is not None, format_unit must be 'O&'.) converter = None @@ -2651,9 +2654,22 @@ class CConverter(metaclass=CConverterAutoRegister): signature_name = None # keep in sync with self_converter.__init__! - def __init__(self, name, py_name, function, default=unspecified, *, c_default=None, py_default=None, annotation=unspecified, **kwargs): + def __init__(self, + # Positional args: + name, + py_name, + function, + default=unspecified, + *, # Keyword only args: + c_default=None, + py_default=None, + annotation=unspecified, + unused=False, + **kwargs + ): self.name = ensure_legal_c_identifier(name) self.py_name = py_name + self.unused = unused if default is not unspecified: if self.default_type and not isinstance(default, (self.default_type, Unknown)): @@ -2800,6 +2816,8 @@ def simple_declaration(self, by_reference=False, *, in_parser=False): name = self.parser_name else: name = self.name + if self.unused: + name = f"Py_UNUSED({name})" prototype.append(name) return "".join(prototype) From webhook-mailer at python.org Fri May 12 05:26:25 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 12 May 2023 09:26:25 -0000 Subject: [Python-checkins] gh-93649: Split gc- and allocation tests from _testcapimodule.c (GH-104403) Message-ID: <mailman.325.1683883585.13550.python-checkins@python.org> https://github.com/python/cpython/commit/19ee53d52e8adf267dfd588c2142967734a3b65a commit: 19ee53d52e8adf267dfd588c2142967734a3b65a branch: main author: Jurica Bradari? <jbradaric at users.noreply.github.com> committer: zooba <steve.dower at microsoft.com> date: 2023-05-12T10:26:07+01:00 summary: gh-93649: Split gc- and allocation tests from _testcapimodule.c (GH-104403) files: A Modules/_testcapi/gc.c M Modules/Setup.stdlib.in M Modules/_testcapi/parts.h M Modules/_testcapimodule.c M PCbuild/_testcapi.vcxproj M PCbuild/_testcapi.vcxproj.filters diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 8e66576b5c5f..95409d48c0da 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE at _xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE at _testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE at _testinternalcapi _testinternalcapi.c - at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c + at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c @MODULE__TESTCLINIC_TRUE at _testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/gc.c b/Modules/_testcapi/gc.c new file mode 100644 index 000000000000..829200ad12cd --- /dev/null +++ b/Modules/_testcapi/gc.c @@ -0,0 +1,344 @@ +#include "parts.h" + +static PyObject* +test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + int orig_enabled = PyGC_IsEnabled(); + const char* msg = "ok"; + int old_state; + + old_state = PyGC_Enable(); + msg = "Enable(1)"; + if (old_state != orig_enabled) { + goto failed; + } + msg = "IsEnabled(1)"; + if (!PyGC_IsEnabled()) { + goto failed; + } + + old_state = PyGC_Disable(); + msg = "disable(2)"; + if (!old_state) { + goto failed; + } + msg = "IsEnabled(2)"; + if (PyGC_IsEnabled()) { + goto failed; + } + + old_state = PyGC_Enable(); + msg = "enable(3)"; + if (old_state) { + goto failed; + } + msg = "IsEnabled(3)"; + if (!PyGC_IsEnabled()) { + goto failed; + } + + if (!orig_enabled) { + old_state = PyGC_Disable(); + msg = "disable(4)"; + if (old_state) { + goto failed; + } + msg = "IsEnabled(4)"; + if (PyGC_IsEnabled()) { + goto failed; + } + } + + Py_RETURN_NONE; + +failed: + /* Try to clean up if we can. */ + if (orig_enabled) { + PyGC_Enable(); + } else { + PyGC_Disable(); + } + PyErr_Format(PyExc_ValueError, "GC control failed in %s", msg); + return NULL; +} + +static PyObject * +without_gc(PyObject *Py_UNUSED(self), PyObject *obj) +{ + PyTypeObject *tp = (PyTypeObject*)obj; + if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { + return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj); + } + if (PyType_IS_GC(tp)) { + // Don't try this at home, kids: + tp->tp_flags -= Py_TPFLAGS_HAVE_GC; + tp->tp_free = PyObject_Del; + tp->tp_traverse = NULL; + tp->tp_clear = NULL; + } + assert(!PyType_IS_GC(tp)); + return Py_NewRef(obj); +} + +static void +slot_tp_del(PyObject *self) +{ + PyObject *del, *res; + + /* Temporarily resurrect the object. */ + assert(Py_REFCNT(self) == 0); + Py_SET_REFCNT(self, 1); + + /* Save the current exception, if any. */ + PyObject *exc = PyErr_GetRaisedException(); + + PyObject *tp_del = PyUnicode_InternFromString("__tp_del__"); + if (tp_del == NULL) { + PyErr_WriteUnraisable(NULL); + PyErr_SetRaisedException(exc); + return; + } + /* Execute __del__ method, if any. */ + del = _PyType_Lookup(Py_TYPE(self), tp_del); + Py_DECREF(tp_del); + if (del != NULL) { + res = PyObject_CallOneArg(del, self); + if (res == NULL) + PyErr_WriteUnraisable(del); + else + Py_DECREF(res); + } + + /* Restore the saved exception. */ + PyErr_SetRaisedException(exc); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(Py_REFCNT(self) > 0); + Py_SET_REFCNT(self, Py_REFCNT(self) - 1); + if (Py_REFCNT(self) == 0) { + /* this is the normal path out */ + return; + } + + /* __del__ resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + { + Py_ssize_t refcnt = Py_REFCNT(self); + _Py_NewReferenceNoTotal(self); + Py_SET_REFCNT(self, refcnt); + } + assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self)); +} + +static PyObject * +with_tp_del(PyObject *self, PyObject *args) +{ + PyObject *obj; + PyTypeObject *tp; + + if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj)) + return NULL; + tp = (PyTypeObject *) obj; + if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "heap type expected, got %R", obj); + return NULL; + } + tp->tp_del = slot_tp_del; + return Py_NewRef(obj); +} + + +struct gc_visit_state_basic { + PyObject *target; + int found; +}; + +static int +gc_visit_callback_basic(PyObject *obj, void *arg) +{ + struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; + if (obj == state->target) { + state->found = 1; + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + PyObject *obj; + struct gc_visit_state_basic state; + + obj = PyList_New(0); + if (obj == NULL) { + return NULL; + } + state.target = obj; + state.found = 0; + + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); + Py_DECREF(obj); + if (!state.found) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_basic: Didn't find live list"); + return NULL; + } + Py_RETURN_NONE; +} + +static int +gc_visit_callback_exit_early(PyObject *obj, void *arg) + { + int *visited_i = (int *)arg; + (*visited_i)++; + if (*visited_i == 2) { + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + int visited_i = 0; + PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); + if (visited_i != 2) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_exit_early: did not exit when expected"); + } + Py_RETURN_NONE; +} + +typedef struct { + PyObject_HEAD +} ObjExtraData; + +static PyObject * +obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + size_t extra_size = sizeof(PyObject *); + PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size); + if (obj == NULL) { + return PyErr_NoMemory(); + } + PyObject_GC_Track(obj); + return obj; +} + +static PyObject ** +obj_extra_data_get_extra_storage(PyObject *self) +{ + return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize); +} + +static PyObject * +obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored)) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + PyObject *value = *extra_storage; + if (!value) { + Py_RETURN_NONE; + } + return Py_NewRef(value); +} + +static int +obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored)) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + Py_CLEAR(*extra_storage); + if (newval) { + *extra_storage = Py_NewRef(newval); + } + return 0; +} + +static PyGetSetDef obj_extra_data_getset[] = { + {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL}, + {NULL} +}; + +static int +obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + PyObject *value = *extra_storage; + Py_VISIT(value); + return 0; +} + +static int +obj_extra_data_clear(PyObject *self) +{ + PyObject **extra_storage = obj_extra_data_get_extra_storage(self); + Py_CLEAR(*extra_storage); + return 0; +} + +static void +obj_extra_data_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + obj_extra_data_clear(self); + tp->tp_free(self); + Py_DECREF(tp); +} + +static PyType_Slot ObjExtraData_Slots[] = { + {Py_tp_getset, obj_extra_data_getset}, + {Py_tp_dealloc, obj_extra_data_dealloc}, + {Py_tp_traverse, obj_extra_data_traverse}, + {Py_tp_clear, obj_extra_data_clear}, + {Py_tp_new, obj_extra_data_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec ObjExtraData_TypeSpec = { + .name = "_testcapi.ObjExtraData", + .basicsize = sizeof(ObjExtraData), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .slots = ObjExtraData_Slots, +}; + +static PyMethodDef test_methods[] = { + {"test_gc_control", test_gc_control, METH_NOARGS}, + {"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}, + {"without_gc", without_gc, METH_O, NULL}, + {"with_tp_del", with_tp_del, METH_VARARGS, NULL}, + {NULL} +}; + +int _PyTestCapi_Init_GC(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec( + mod, &ObjExtraData_TypeSpec, NULL); + if (ObjExtraData_Type == 0) { + return -1; + } + int ret = PyModule_AddType(mod, (PyTypeObject*)ObjExtraData_Type); + Py_DECREF(ObjExtraData_Type); + if (ret < 0) { + return ret; + } + + return 0; +} diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index 663d4f2255de..d1991ac6b464 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -41,6 +41,7 @@ int _PyTestCapi_Init_Code(PyObject *module); int _PyTestCapi_Init_Buffer(PyObject *module); int _PyTestCapi_Init_PyOS(PyObject *module); int _PyTestCapi_Init_Immortal(PyObject *module); +int _PyTestCapi_Init_GC(PyObject *mod); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 79ab7d3f5555..c29d29c47911 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -154,68 +154,6 @@ test_sizeof_c_types(PyObject *self, PyObject *Py_UNUSED(ignored)) #endif } -static PyObject* -test_gc_control(PyObject *self, PyObject *Py_UNUSED(ignored)) -{ - int orig_enabled = PyGC_IsEnabled(); - const char* msg = "ok"; - int old_state; - - old_state = PyGC_Enable(); - msg = "Enable(1)"; - if (old_state != orig_enabled) { - goto failed; - } - msg = "IsEnabled(1)"; - if (!PyGC_IsEnabled()) { - goto failed; - } - - old_state = PyGC_Disable(); - msg = "disable(2)"; - if (!old_state) { - goto failed; - } - msg = "IsEnabled(2)"; - if (PyGC_IsEnabled()) { - goto failed; - } - - old_state = PyGC_Enable(); - msg = "enable(3)"; - if (old_state) { - goto failed; - } - msg = "IsEnabled(3)"; - if (!PyGC_IsEnabled()) { - goto failed; - } - - if (!orig_enabled) { - old_state = PyGC_Disable(); - msg = "disable(4)"; - if (old_state) { - goto failed; - } - msg = "IsEnabled(4)"; - if (PyGC_IsEnabled()) { - goto failed; - } - } - - Py_RETURN_NONE; - -failed: - /* Try to clean up if we can. */ - if (orig_enabled) { - PyGC_Enable(); - } else { - PyGC_Disable(); - } - PyErr_Format(TestError, "GC control failed in %s", msg); - return NULL; -} - static PyObject* test_list_api(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -1627,95 +1565,6 @@ restore_crossinterp_data(PyObject *self, PyObject *args) return _PyCrossInterpreterData_NewObject(data); } -static void -slot_tp_del(PyObject *self) -{ - PyObject *del, *res; - - /* Temporarily resurrect the object. */ - assert(Py_REFCNT(self) == 0); - Py_SET_REFCNT(self, 1); - - /* Save the current exception, if any. */ - PyObject *exc = PyErr_GetRaisedException(); - - PyObject *tp_del = PyUnicode_InternFromString("__tp_del__"); - if (tp_del == NULL) { - PyErr_WriteUnraisable(NULL); - PyErr_SetRaisedException(exc); - return; - } - /* Execute __del__ method, if any. */ - del = _PyType_Lookup(Py_TYPE(self), tp_del); - Py_DECREF(tp_del); - if (del != NULL) { - res = PyObject_CallOneArg(del, self); - if (res == NULL) - PyErr_WriteUnraisable(del); - else - Py_DECREF(res); - } - - /* Restore the saved exception. */ - PyErr_SetRaisedException(exc); - - /* Undo the temporary resurrection; can't use DECREF here, it would - * cause a recursive call. - */ - assert(Py_REFCNT(self) > 0); - Py_SET_REFCNT(self, Py_REFCNT(self) - 1); - if (Py_REFCNT(self) == 0) { - /* this is the normal path out */ - return; - } - - /* __del__ resurrected it! Make it look like the original Py_DECREF - * never happened. - */ - { - Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReferenceNoTotal(self); - Py_SET_REFCNT(self, refcnt); - } - assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self)); -} - -static PyObject * -with_tp_del(PyObject *self, PyObject *args) -{ - PyObject *obj; - PyTypeObject *tp; - - if (!PyArg_ParseTuple(args, "O:with_tp_del", &obj)) - return NULL; - tp = (PyTypeObject *) obj; - if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { - PyErr_Format(PyExc_TypeError, - "heap type expected, got %R", obj); - return NULL; - } - tp->tp_del = slot_tp_del; - return Py_NewRef(obj); -} - -static PyObject * -without_gc(PyObject *Py_UNUSED(self), PyObject *obj) -{ - PyTypeObject *tp = (PyTypeObject*)obj; - if (!PyType_Check(obj) || !PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { - return PyErr_Format(PyExc_TypeError, "heap type expected, got %R", obj); - } - if (PyType_IS_GC(tp)) { - // Don't try this at home, kids: - tp->tp_flags -= Py_TPFLAGS_HAVE_GC; - tp->tp_free = PyObject_Del; - tp->tp_traverse = NULL; - tp->tp_clear = NULL; - } - assert(!PyType_IS_GC(tp)); - return Py_NewRef(obj); -} - static PyMethodDef ml; static PyObject * @@ -3342,165 +3191,6 @@ function_set_kw_defaults(PyObject *self, PyObject *args) Py_RETURN_NONE; } -struct gc_visit_state_basic { - PyObject *target; - int found; -}; - -static int -gc_visit_callback_basic(PyObject *obj, void *arg) -{ - struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; - if (obj == state->target) { - state->found = 1; - return 0; - } - return 1; -} - -static PyObject * -test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), - PyObject *Py_UNUSED(ignored)) -{ - PyObject *obj; - struct gc_visit_state_basic state; - - obj = PyList_New(0); - if (obj == NULL) { - return NULL; - } - state.target = obj; - state.found = 0; - - PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); - Py_DECREF(obj); - if (!state.found) { - PyErr_SetString( - PyExc_AssertionError, - "test_gc_visit_objects_basic: Didn't find live list"); - return NULL; - } - Py_RETURN_NONE; -} - -static int -gc_visit_callback_exit_early(PyObject *obj, void *arg) - { - int *visited_i = (int *)arg; - (*visited_i)++; - if (*visited_i == 2) { - return 0; - } - return 1; -} - -static PyObject * -test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), - PyObject *Py_UNUSED(ignored)) -{ - int visited_i = 0; - PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); - if (visited_i != 2) { - PyErr_SetString( - PyExc_AssertionError, - "test_gc_visit_objects_exit_early: did not exit when expected"); - } - Py_RETURN_NONE; -} - -typedef struct { - PyObject_HEAD -} ObjExtraData; - -static PyObject * -obj_extra_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - size_t extra_size = sizeof(PyObject *); - PyObject *obj = PyUnstable_Object_GC_NewWithExtraData(type, extra_size); - if (obj == NULL) { - return PyErr_NoMemory(); - } - PyObject_GC_Track(obj); - return obj; -} - -static PyObject ** -obj_extra_data_get_extra_storage(PyObject *self) -{ - return (PyObject **)((char *)self + Py_TYPE(self)->tp_basicsize); -} - -static PyObject * -obj_extra_data_get(PyObject *self, void *Py_UNUSED(ignored)) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - PyObject *value = *extra_storage; - if (!value) { - Py_RETURN_NONE; - } - return Py_NewRef(value); -} - -static int -obj_extra_data_set(PyObject *self, PyObject *newval, void *Py_UNUSED(ignored)) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - Py_CLEAR(*extra_storage); - if (newval) { - *extra_storage = Py_NewRef(newval); - } - return 0; -} - -static PyGetSetDef obj_extra_data_getset[] = { - {"extra", (getter)obj_extra_data_get, (setter)obj_extra_data_set, NULL}, - {NULL} -}; - -static int -obj_extra_data_traverse(PyObject *self, visitproc visit, void *arg) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - PyObject *value = *extra_storage; - Py_VISIT(value); - return 0; -} - -static int -obj_extra_data_clear(PyObject *self) -{ - PyObject **extra_storage = obj_extra_data_get_extra_storage(self); - Py_CLEAR(*extra_storage); - return 0; -} - -static void -obj_extra_data_dealloc(PyObject *self) -{ - PyTypeObject *tp = Py_TYPE(self); - PyObject_GC_UnTrack(self); - obj_extra_data_clear(self); - tp->tp_free(self); - Py_DECREF(tp); -} - -static PyType_Slot ObjExtraData_Slots[] = { - {Py_tp_getset, obj_extra_data_getset}, - {Py_tp_dealloc, obj_extra_data_dealloc}, - {Py_tp_traverse, obj_extra_data_traverse}, - {Py_tp_clear, obj_extra_data_clear}, - {Py_tp_new, obj_extra_data_new}, - {Py_tp_free, PyObject_GC_Del}, - {0, NULL}, -}; - -static PyType_Spec ObjExtraData_TypeSpec = { - .name = "_testcapi.ObjExtraData", - .basicsize = sizeof(ObjExtraData), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .slots = ObjExtraData_Slots, -}; - struct atexit_data { int called; }; @@ -3538,7 +3228,6 @@ static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, {"test_sizeof_c_types", test_sizeof_c_types, METH_NOARGS}, - {"test_gc_control", test_gc_control, METH_NOARGS}, {"test_list_api", test_list_api, METH_NOARGS}, {"test_dict_iteration", test_dict_iteration, METH_NOARGS}, {"dict_getitem_knownhash", dict_getitem_knownhash, METH_VARARGS}, @@ -3590,7 +3279,6 @@ static PyMethodDef TestMethods[] = { METH_VARARGS | METH_KEYWORDS}, {"get_crossinterp_data", get_crossinterp_data, METH_VARARGS}, {"restore_crossinterp_data", restore_crossinterp_data, METH_VARARGS}, - {"with_tp_del", with_tp_del, METH_VARARGS}, {"create_cfunction", create_cfunction, METH_NOARGS}, {"call_in_temporary_c_thread", call_in_temporary_c_thread, METH_VARARGS, PyDoc_STR("set_error_class(error_class) -> None")}, @@ -3641,7 +3329,6 @@ static PyMethodDef TestMethods[] = { {"meth_fastcall", _PyCFunction_CAST(meth_fastcall), METH_FASTCALL}, {"meth_fastcall_keywords", _PyCFunction_CAST(meth_fastcall_keywords), METH_FASTCALL|METH_KEYWORDS}, {"pynumber_tobase", pynumber_tobase, METH_VARARGS}, - {"without_gc", without_gc, METH_O}, {"test_set_type_size", test_set_type_size, METH_NOARGS}, {"test_py_clear", test_py_clear, METH_NOARGS}, {"test_py_setref", test_py_setref, METH_NOARGS}, @@ -3675,8 +3362,6 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"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 */ }; @@ -4223,17 +3908,6 @@ PyInit__testcapi(void) Py_INCREF(&MethStatic_Type); PyModule_AddObject(m, "MethStatic", (PyObject *)&MethStatic_Type); - PyObject *ObjExtraData_Type = PyType_FromModuleAndSpec( - m, &ObjExtraData_TypeSpec, NULL); - if (ObjExtraData_Type == 0) { - return NULL; - } - int ret = PyModule_AddType(m, (PyTypeObject*)ObjExtraData_Type); - Py_DECREF(ObjExtraData_Type); - if (ret < 0) { - return NULL; - } - PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX)); PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN)); PyModule_AddObject(m, "UCHAR_MAX", PyLong_FromLong(UCHAR_MAX)); @@ -4327,6 +4001,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Immortal(m) < 0) { return NULL; } + if (_PyTestCapi_Init_GC(m) < 0) { + return NULL; + } #ifndef LIMITED_API_AVAILABLE PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False); diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 350f97f8ff41..3db9426d1a25 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -113,6 +113,7 @@ <ClCompile Include="..\Modules\_testcapi\buffer.c" /> <ClCompile Include="..\Modules\_testcapi\pyos.c" /> <ClCompile Include="..\Modules\_testcapi\immortal.c" /> + <ClCompile Include="..\Modules\_testcapi\gc.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc" /> diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index af80f1eebb3c..8df4874659fa 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -66,6 +66,9 @@ <ClCompile Include="..\Modules\_testcapi\pyos.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Modules\_testcapi\gc.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\PC\python_nt.rc"> From webhook-mailer at python.org Fri May 12 07:21:27 2023 From: webhook-mailer at python.org (markshannon) Date: Fri, 12 May 2023 11:21:27 -0000 Subject: [Python-checkins] GH-103082: Filter LINE events in VM, to simplify tool implementation. (GH-104387) Message-ID: <mailman.326.1683890488.13550.python-checkins@python.org> https://github.com/python/cpython/commit/45f5aa8fc73acf516071d52ef8213532f0381316 commit: 45f5aa8fc73acf516071d52ef8213532f0381316 branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-12T12:21:20+01:00 summary: GH-103082: Filter LINE events in VM, to simplify tool implementation. (GH-104387) When monitoring LINE events, instrument all instructions that can have a predecessor on a different line. Then check that the a new line has been hit in the instrumentation code. This brings the behavior closer to that of 3.11, simplifying implementation and porting of tools. files: A Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst M Include/internal/pycore_frame.h M Include/internal/pycore_instruments.h M Lib/test/test_monitoring.py M Lib/test/test_pdb.py M Lib/test/test_sys.py M Lib/test/test_sys_settrace.py M Objects/frameobject.c M Python/bytecodes.c M Python/ceval.c M Python/ceval_macros.h M Python/generated_cases.c.h M Python/instrumentation.c M Python/legacy_tracing.c M Python/opcode_metadata.h M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 3d3cbbff7aae..a72e03f1438f 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -19,7 +19,6 @@ 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? */ diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index e94d8755546e..9fb3952227af 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -69,13 +69,13 @@ _Py_call_instrumentation(PyThreadState *tstate, int event, extern int _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, - _Py_CODEUNIT *instr); + _Py_CODEUNIT *instr, _Py_CODEUNIT *prev); extern int _Py_call_instrumentation_instruction( PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr); -int +_Py_CODEUNIT * _Py_call_instrumentation_jump( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target); @@ -100,6 +100,7 @@ extern int _Py_Instrumentation_GetLine(PyCodeObject *code, int index); extern PyObject _PyInstrumentation_MISSING; +extern PyObject _PyInstrumentation_DISABLE; #ifdef __cplusplus } diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index a493bb54d70d..06e54fa2965f 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -524,7 +524,7 @@ def test_lines_loop(self): 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]) + self.assertEqual(events, [start+7, 21, 22, 21, 22, 21, start+8]) finally: sys.monitoring.set_events(TEST_TOOL, 0) sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) @@ -1050,6 +1050,8 @@ def func3(): def line_from_offset(code, offset): for start, end, line in code.co_lines(): if start <= offset < end: + if line is None: + return f"[offset={offset}]" return line - code.co_firstlineno return -1 @@ -1072,9 +1074,20 @@ class BranchRecorder(JumpRecorder): event_type = E.BRANCH name = "branch" +class ReturnRecorder: + + event_type = E.PY_RETURN + + def __init__(self, events): + self.events = events + + def __call__(self, code, offset, val): + self.events.append(("return", val)) + JUMP_AND_BRANCH_RECORDERS = JumpRecorder, BranchRecorder JUMP_BRANCH_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder +FLOW_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder, ExceptionRecorder, ReturnRecorder class TestBranchAndJumpEvents(CheckEvents): maxDiff = None @@ -1098,7 +1111,6 @@ def func(): ('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), @@ -1108,15 +1120,62 @@ def func(): ('branch', 'func', 3, 6), ('line', 'func', 6), ('jump', 'func', 6, 2), + ('line', 'func', 2), ('branch', 'func', 2, 2), ('line', 'func', 3), ('branch', 'func', 3, 4), ('line', 'func', 4), ('jump', 'func', 4, 2), + ('line', 'func', 2), ('branch', 'func', 2, 2), + ('line', 'check_events', 11)]) + + def test_except_star(self): + + class Foo: + def meth(self): + pass + + def func(): + try: + try: + raise KeyError + except* Exception as e: + f = Foo(); f.meth() + except KeyError: + pass + + + self.check_events(func, recorders = JUMP_BRANCH_AND_LINE_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('line', 'func', 1), ('line', 'func', 2), + ('line', 'func', 3), + ('line', 'func', 4), + ('branch', 'func', 4, 4), + ('line', 'func', 5), + ('line', 'meth', 1), + ('jump', 'func', 5, 5), + ('jump', 'func', 5, '[offset=114]'), + ('branch', 'func', '[offset=120]', '[offset=122]'), ('line', 'check_events', 11)]) + self.check_events(func, recorders = FLOW_AND_LINE_RECORDERS, expected = [ + ('line', 'check_events', 10), + ('line', 'func', 1), + ('line', 'func', 2), + ('line', 'func', 3), + ('raise', KeyError), + ('line', 'func', 4), + ('branch', 'func', 4, 4), + ('line', 'func', 5), + ('line', 'meth', 1), + ('return', None), + ('jump', 'func', 5, 5), + ('jump', 'func', 5, '[offset=114]'), + ('branch', 'func', '[offset=120]', '[offset=122]'), + ('return', None), + ('line', 'check_events', 11)]) class TestSetGetEvents(MonitoringTestBase, unittest.TestCase): diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 037673dd0ea8..83c7cdff87fd 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1793,8 +1793,9 @@ def test_pdb_issue_gh_101517(): ... 'continue' ... ]): ... test_function() - > <doctest test.test_pdb.test_pdb_issue_gh_101517[0]>(5)test_function() - -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + --Return-- + > <doctest test.test_pdb.test_pdb_issue_gh_101517[0]>(None)test_function()->None + -> Warning: lineno is None (Pdb) continue """ diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 611cd27ecf12..e1db450bf8a2 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1446,7 +1446,7 @@ class C(object): pass def func(): return sys._getframe() x = func() - check(x, size('3Pii3c7P2ic??2P')) + check(x, size('3Pi3c7P2ic??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 980321e169b9..4411603af18c 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -2867,6 +2867,5 @@ def func(arg = 1): sys.settrace(None) - if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst new file mode 100644 index 000000000000..40eee64dfa71 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst @@ -0,0 +1,5 @@ +Change behavior of ``sys.monitoring.events.LINE`` events in +``sys.monitoring``: Line events now occur when a new line is reached +dynamically, instead of using a static approximation, as before. This makes +the behavior very similar to that of "line" events in ``sys.settrace``. This +should ease porting of tools from 3.11 to 3.12. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d9aaea7831a3..2c90a6b71311 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -831,7 +831,6 @@ 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; @@ -854,7 +853,6 @@ frame_settrace(PyFrameObject *f, PyObject* v, void *closure) } if (v != f->f_trace) { Py_XSETREF(f->f_trace, Py_XNewRef(v)); - f->f_last_traced_line = -1; } return 0; } @@ -1056,7 +1054,6 @@ _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/Python/bytecodes.c b/Python/bytecodes.c index eee9147dd866..99935a3d7907 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3288,28 +3288,6 @@ dummy_func( assert(oparg >= 2); } - 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); diff --git a/Python/ceval.c b/Python/ceval.c index 56a3b123f463..e8534ec6598e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -775,6 +775,41 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #include "generated_cases.c.h" + /* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c, + * because it needs to capture frame->prev_instr before it is updated, + * as happens in the standard instruction prologue. + */ +#if USE_COMPUTED_GOTOS + TARGET_INSTRUMENTED_LINE: +#else + case INSTRUMENTED_LINE: +#endif + { + _Py_CODEUNIT *prev = frame->prev_instr; + _Py_CODEUNIT *here = frame->prev_instr = next_instr; + _PyFrame_SetStackPointer(frame, stack_pointer); + int original_opcode = _Py_call_instrumentation_line( + tstate, frame, here, prev); + 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); + /* Prevent the underlying instruction from specializing + * and overwriting the instrumentation. */ + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + } + opcode = original_opcode; + DISPATCH_GOTO(); + } + + #if USE_COMPUTED_GOTOS _unknown_opcode: #else diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 485771ac65a7..f5515d0d32de 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -334,11 +334,10 @@ do { \ #define INSTRUMENTED_JUMP(src, dest, event) \ do { \ _PyFrame_SetStackPointer(frame, stack_pointer); \ - int err = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ + next_instr = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ - if (err) { \ + if (next_instr == NULL) { \ next_instr = (dest)+1; \ goto error; \ } \ - next_instr = frame->prev_instr; \ } while (0); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2ea15e98cb02..0ded2f9dcdc2 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4568,32 +4568,8 @@ DISPATCH(); } - TARGET(INSTRUMENTED_LINE) { - #line 3292 "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 4593 "Python/generated_cases.c.h" - } - TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3314 "Python/bytecodes.c" + #line 3292 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4605,26 +4581,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4609 "Python/generated_cases.c.h" + #line 4585 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3328 "Python/bytecodes.c" + #line 3306 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4615 "Python/generated_cases.c.h" + #line 4591 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3332 "Python/bytecodes.c" + #line 3310 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4622 "Python/generated_cases.c.h" + #line 4598 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3337 "Python/bytecodes.c" + #line 3315 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4633,12 +4609,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4637 "Python/generated_cases.c.h" + #line 4613 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3348 "Python/bytecodes.c" + #line 3326 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4647,12 +4623,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4651 "Python/generated_cases.c.h" + #line 4627 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3359 "Python/bytecodes.c" + #line 3337 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4665,12 +4641,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4669 "Python/generated_cases.c.h" + #line 4645 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3374 "Python/bytecodes.c" + #line 3352 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4683,30 +4659,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4687 "Python/generated_cases.c.h" + #line 4663 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3389 "Python/bytecodes.c" + #line 3367 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4698 "Python/generated_cases.c.h" + #line 4674 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3397 "Python/bytecodes.c" + #line 3375 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4705 "Python/generated_cases.c.h" + #line 4681 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3402 "Python/bytecodes.c" + #line 3380 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4712 "Python/generated_cases.c.h" + #line 4688 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index a14232406096..9152744d7c2c 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -14,7 +14,7 @@ /* Uncomment this to dump debugging output when assertions fail */ // #define INSTRUMENT_DEBUG 1 -static PyObject DISABLE = +PyObject _PyInstrumentation_DISABLE = { .ob_refcnt = _Py_IMMORTAL_REFCNT, .ob_type = &PyBaseObject_Type @@ -859,7 +859,7 @@ call_one_instrument( return -1; } Py_DECREF(res); - return (res == &DISABLE); + return (res == &_PyInstrumentation_DISABLE); } static const int8_t MOST_SIGNIFICANT_BITS[16] = { @@ -1002,7 +1002,7 @@ _Py_call_instrumentation_2args( return call_instrumentation_vector(tstate, event, frame, instr, 4, args); } -int +_Py_CODEUNIT * _Py_call_instrumentation_jump( PyThreadState *tstate, int event, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target) @@ -1010,17 +1010,27 @@ _Py_call_instrumentation_jump( assert(event == PY_MONITORING_EVENT_JUMP || event == PY_MONITORING_EVENT_BRANCH); assert(frame->prev_instr == instr); + /* Event should occur after the jump */ 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; + return NULL; } 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; + if (err) { + return NULL; + } + if (frame->prev_instr != target) { + /* The callback has caused a jump (by setting the line number) */ + return frame->prev_instr; + } + /* Reset prev_instr for INSTRUMENTED_LINE */ + frame->prev_instr = instr; + return target; } static void @@ -1076,13 +1086,14 @@ _Py_Instrumentation_GetLine(PyCodeObject *code, int index) } int -_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) +_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) { 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; @@ -1092,6 +1103,18 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, PyInterpreterState *interp = tstate->interp; int8_t line_delta = line_data->line_delta; int line = compute_line(code, i, line_delta); + assert(line >= 0); + int prev_index = (int)(prev - _PyCode_CODE(code)); + int prev_line = _Py_Instrumentation_GetLine(code, prev_index); + if (prev_line == line) { + int prev_opcode = _PyCode_CODE(code)[prev_index].op.code; + /* RESUME and INSTRUMENTED_RESUME are needed for the operation of + * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. + */ + if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { + goto done; + } + } uint8_t tools = code->_co_monitoring->line_tools != NULL ? code->_co_monitoring->line_tools[i] : (interp->monitors.tools[PY_MONITORING_EVENT_LINE] | @@ -1275,29 +1298,91 @@ initialize_lines(PyCodeObject *code) line_data[i].original_opcode = 0; break; default: + /* Set original_opcode to the opcode iff the instruction + * starts a line, and thus should be instrumented. + * This saves having to perform this check every time the + * we turn instrumentation on or off, and serves as a sanity + * check when debugging. + */ 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; - } + 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; } + i += length; + } + for (int i = code->_co_firsttraceable; i < code_len; ) { + int opcode = _Py_GetBaseOpcode(code, i); + int oparg = 0; + while (opcode == EXTENDED_ARG) { + oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; + i++; + opcode = _Py_GetBaseOpcode(code, i); + } + oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; + i += instruction_length(code, i); + int target = -1; 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; + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + case POP_JUMP_IF_NONE: + case POP_JUMP_IF_NOT_NONE: + case JUMP_FORWARD: + { + target = i + oparg; + break; + } + case FOR_ITER: + case SEND: + { + /* Skip over END_FOR/END_SEND */ + target = i + oparg + 1; + break; + } + case JUMP_BACKWARD: + case JUMP_BACKWARD_NO_INTERRUPT: + { + target = i - oparg; + break; + } + default: + continue; + } + assert(target >= 0); + if (line_data[target].line_delta != NO_LINE) { + line_data[target].original_opcode = _Py_GetBaseOpcode(code, target); + } + } + /* Scan exception table */ + unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code->co_exceptiontable); + unsigned char *end = start + PyBytes_GET_SIZE(code->co_exceptiontable); + unsigned char *scan = start; + while (scan < end) { + int start_offset, size, handler; + scan = parse_varint(scan, &start_offset); + assert(start_offset >= 0 && start_offset < code_len); + scan = parse_varint(scan, &size); + assert(size >= 0 && start_offset+size <= code_len); + scan = parse_varint(scan, &handler); + assert(handler >= 0 && handler < code_len); + int depth_and_lasti; + scan = parse_varint(scan, &depth_and_lasti); + int original_opcode = _Py_GetBaseOpcode(code, handler); + /* Skip if not the start of a line. + * END_ASYNC_FOR is a bit special as it marks the end of + * an `async for` loop, which should not generate its own + * line event. */ + if (line_data[handler].line_delta != NO_LINE && + original_opcode != END_ASYNC_FOR) { + line_data[handler].original_opcode = original_opcode; } - i += length; } } @@ -2010,7 +2095,7 @@ PyObject *_Py_CreateMonitoringObject(void) if (mod == NULL) { return NULL; } - if (PyObject_SetAttrString(mod, "DISABLE", &DISABLE)) { + if (PyObject_SetAttrString(mod, "DISABLE", &_PyInstrumentation_DISABLE)) { goto error; } if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) { diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index e509e63a087a..5143b79b0864 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -4,6 +4,7 @@ #include <stddef.h> #include "Python.h" +#include "opcode.h" #include "pycore_ceval.h" #include "pycore_object.h" #include "pycore_sysmodule.h" @@ -213,7 +214,6 @@ trace_line( 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); @@ -245,14 +245,12 @@ sys_trace_line_func( 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); } - +/* sys.settrace generates line events for all backward + * edges, even if on the same line. + * Handle that case here */ static PyObject * sys_trace_jump_func( _PyLegacyEventHandler *self, PyObject *const *args, @@ -268,61 +266,33 @@ sys_trace_jump_func( 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; + if (to > from) { + /* Forward jump */ + return &_PyInstrumentation_DISABLE; } 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; + int from_line = _Py_Instrumentation_GetLine(code, from); + if (to_line != from_line) { + /* Will be handled by target INSTRUMENTED_LINE */ + return &_PyInstrumentation_DISABLE; } - 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)); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling trace function."); + return NULL; + } 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 */ + if (!frame->f_trace_lines) { Py_RETURN_NONE; } - return trace_line(tstate, self, frame, line); + return trace_line(tstate, self, frame, to_line); } - PyTypeObject _PyLegacyEventHandler_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "sys.legacy_event_handler", @@ -487,7 +457,7 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE, - PY_MONITORING_EVENT_JUMP, PY_MONITORING_EVENT_BRANCH)) { + PY_MONITORING_EVENT_JUMP, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, @@ -495,11 +465,6 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) 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); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index daf3a3888f0d..ae68e045a611 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -367,8 +367,6 @@ _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: @@ -759,8 +757,6 @@ _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: @@ -976,7 +972,6 @@ 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 }, diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 453f63ec3f1c..8afa92ef25d3 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -301,7 +301,7 @@ 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_DISABLE - Python/instrumentation.c - _PyInstrumentation_MISSING - From webhook-mailer at python.org Fri May 12 08:36:00 2023 From: webhook-mailer at python.org (pganssle) Date: Fri, 12 May 2023 12:36:00 -0000 Subject: [Python-checkins] GH-86275: Implementation of hypothesis stubs for property-based tests, with zoneinfo tests (#22863) Message-ID: <mailman.327.1683894962.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d50c37d8adb2d2da9808089d959ca7d6791ac59f commit: d50c37d8adb2d2da9808089d959ca7d6791ac59f branch: main author: Paul Ganssle <1377457+pganssle at users.noreply.github.com> committer: pganssle <1377457+pganssle at users.noreply.github.com> date: 2023-05-12T08:35:53-04:00 summary: GH-86275: Implementation of hypothesis stubs for property-based tests, with zoneinfo tests (#22863) These are stubs to be used for adding hypothesis (https://hypothesis.readthedocs.io/en/latest/) tests to the standard library. When the tests are run in an environment where `hypothesis` and its various dependencies are not installed, the stubs will turn any tests with examples into simple parameterized tests and any tests without examples are skipped. It also adds hypothesis tests for the `zoneinfo` module, and a Github Actions workflow to run the hypothesis tests as a non-required CI job. The full hypothesis interface is not stubbed out ? missing stubs can be added as necessary. Co-authored-by: Zac Hatfield-Dodds <zac.hatfield.dodds at gmail.com> files: A Lib/test/support/_hypothesis_stubs/__init__.py A Lib/test/support/_hypothesis_stubs/_helpers.py A Lib/test/support/_hypothesis_stubs/strategies.py A Lib/test/support/hypothesis_helper.py A Lib/test/test_zoneinfo/test_zoneinfo_property.py A Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst M .github/workflows/build.yml M Lib/test/libregrtest/save_env.py M Lib/test/test_zoneinfo/__init__.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df0f107a5416..f0a2dd5694c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,6 +36,7 @@ jobs: timeout-minutes: 10 outputs: run_tests: ${{ steps.check.outputs.run_tests }} + run_hypothesis: ${{ steps.check.outputs.run_hypothesis }} steps: - uses: actions/checkout at v3 - name: Check for source changes @@ -61,6 +62,17 @@ jobs: git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo "run_tests=true" >> $GITHUB_OUTPUT || true fi + # Check if we should run hypothesis tests + GIT_BRANCH=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}} + echo $GIT_BRANCH + if $(echo "$GIT_BRANCH" | grep -q -w '3\.\(8\|9\|10\|11\)'); then + echo "Branch too old for hypothesis tests" + echo "run_hypothesis=false" >> $GITHUB_OUTPUT + else + echo "Run hypothesis tests" + echo "run_hypothesis=true" >> $GITHUB_OUTPUT + fi + check_generated_files: name: 'Check if generated files are up to date' runs-on: ubuntu-latest @@ -291,6 +303,90 @@ jobs: - name: SSL tests run: ./python Lib/test/ssltests.py + test_hypothesis: + name: "Hypothesis Tests on Ubuntu" + runs-on: ubuntu-20.04 + timeout-minutes: 60 + needs: check_source + if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_hypothesis == 'true' + env: + OPENSSL_VER: 1.1.1t + PYTHONSTRICTEXTENSIONBUILD: 1 + steps: + - uses: actions/checkout at v3 + - name: Register gcc problem matcher + run: echo "::add-matcher::.github/problem-matchers/gcc.json" + - name: Install Dependencies + run: sudo ./.github/workflows/posix-deps-apt.sh + - name: Configure OpenSSL env vars + run: | + echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV + echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV + - name: 'Restore OpenSSL build' + id: cache-openssl + uses: actions/cache at v3 + with: + path: ./multissl/openssl/${{ env.OPENSSL_VER }} + key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }} + - name: Install OpenSSL + if: steps.cache-openssl.outputs.cache-hit != 'true' + run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux + - name: Add ccache to PATH + run: | + echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV + - name: Configure ccache action + uses: hendrikmuhs/ccache-action at v1.2 + - name: Setup directory envs for out-of-tree builds + run: | + echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV + echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV + - name: Create directories for read-only out-of-tree builds + run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR + - name: Bind mount sources read-only + run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR + - name: Configure CPython out-of-tree + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: ../cpython-ro-srcdir/configure --with-pydebug --with-openssl=$OPENSSL_DIR + - name: Build CPython out-of-tree + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: make -j4 + - name: Display build info + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: make pythoninfo + - name: Remount sources writable for tests + # some tests write to srcdir, lack of pyc files slows down testing + run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw + - name: Setup directory envs for out-of-tree builds + run: | + echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV + - name: "Create hypothesis venv" + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: | + VENV_LOC=$(realpath -m .)/hypovenv + VENV_PYTHON=$VENV_LOC/bin/python + echo "HYPOVENV=${VENV_LOC}" >> $GITHUB_ENV + echo "VENV_PYTHON=${VENV_PYTHON}" >> $GITHUB_ENV + ./python -m venv $VENV_LOC && $VENV_PYTHON -m pip install -U hypothesis + - name: "Run tests" + working-directory: ${{ env.CPYTHON_BUILDDIR }} + run: | + # Most of the excluded tests are slow test suites with no property tests + # + # (GH-104097) test_sysconfig is skipped because it has tests that are + # failing when executed from inside a virtual environment. + ${{ env.VENV_PYTHON }} -m test \ + -W \ + -x test_asyncio \ + -x test_multiprocessing_fork \ + -x test_multiprocessing_forkserver \ + -x test_multiprocessing_spawn \ + -x test_concurrent_futures \ + -x test_socket \ + -x test_subprocess \ + -x test_signal \ + -x test_sysconfig + build_asan: name: 'Address sanitizer' diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py index cc5870ab2b83..c7801b767c59 100644 --- a/Lib/test/libregrtest/save_env.py +++ b/Lib/test/libregrtest/save_env.py @@ -257,8 +257,10 @@ def restore_sysconfig__INSTALL_SCHEMES(self, saved): sysconfig._INSTALL_SCHEMES.update(saved[2]) def get_files(self): + # XXX: Maybe add an allow-list here? return sorted(fn + ('/' if os.path.isdir(fn) else '') - for fn in os.listdir()) + for fn in os.listdir() + if not fn.startswith(".hypothesis")) def restore_files(self, saved_value): fn = os_helper.TESTFN if fn not in saved_value and (fn + '/') not in saved_value: diff --git a/Lib/test/support/_hypothesis_stubs/__init__.py b/Lib/test/support/_hypothesis_stubs/__init__.py new file mode 100644 index 000000000000..6ba5bb814b92 --- /dev/null +++ b/Lib/test/support/_hypothesis_stubs/__init__.py @@ -0,0 +1,111 @@ +from enum import Enum +import functools +import unittest + +__all__ = [ + "given", + "example", + "assume", + "reject", + "register_random", + "strategies", + "HealthCheck", + "settings", + "Verbosity", +] + +from . import strategies + + +def given(*_args, **_kwargs): + def decorator(f): + if examples := getattr(f, "_examples", []): + + @functools.wraps(f) + def test_function(self): + for example_args, example_kwargs in examples: + with self.subTest(*example_args, **example_kwargs): + f(self, *example_args, **example_kwargs) + + else: + # If we have found no examples, we must skip the test. If @example + # is applied after @given, it will re-wrap the test to remove the + # skip decorator. + test_function = unittest.skip( + "Hypothesis required for property test with no " + + "specified examples" + )(f) + + test_function._given = True + return test_function + + return decorator + + +def example(*args, **kwargs): + if bool(args) == bool(kwargs): + raise ValueError("Must specify exactly one of *args or **kwargs") + + def decorator(f): + base_func = getattr(f, "__wrapped__", f) + if not hasattr(base_func, "_examples"): + base_func._examples = [] + + base_func._examples.append((args, kwargs)) + + if getattr(f, "_given", False): + # If the given decorator is below all the example decorators, + # it would be erroneously skipped, so we need to re-wrap the new + # base function. + f = given()(base_func) + + return f + + return decorator + + +def assume(condition): + if not condition: + raise unittest.SkipTest("Unsatisfied assumption") + return True + + +def reject(): + assume(False) + + +def register_random(*args, **kwargs): + pass # pragma: no cover + + +def settings(*args, **kwargs): + return lambda f: f # pragma: nocover + + +class HealthCheck(Enum): + data_too_large = 1 + filter_too_much = 2 + too_slow = 3 + return_value = 5 + large_base_example = 7 + not_a_test_method = 8 + + @classmethod + def all(cls): + return list(cls) + + +class Verbosity(Enum): + quiet = 0 + normal = 1 + verbose = 2 + debug = 3 + + +class Phase(Enum): + explicit = 0 + reuse = 1 + generate = 2 + target = 3 + shrink = 4 + explain = 5 diff --git a/Lib/test/support/_hypothesis_stubs/_helpers.py b/Lib/test/support/_hypothesis_stubs/_helpers.py new file mode 100644 index 000000000000..3f6244e4dbc0 --- /dev/null +++ b/Lib/test/support/_hypothesis_stubs/_helpers.py @@ -0,0 +1,43 @@ +# Stub out only the subset of the interface that we actually use in our tests. +class StubClass: + def __init__(self, *args, **kwargs): + self.__stub_args = args + self.__stub_kwargs = kwargs + self.__repr = None + + def _with_repr(self, new_repr): + new_obj = self.__class__(*self.__stub_args, **self.__stub_kwargs) + new_obj.__repr = new_repr + return new_obj + + def __repr__(self): + if self.__repr is not None: + return self.__repr + + argstr = ", ".join(self.__stub_args) + kwargstr = ", ".join(f"{kw}={val}" for kw, val in self.__stub_kwargs.items()) + + in_parens = argstr + if kwargstr: + in_parens += ", " + kwargstr + + return f"{self.__class__.__qualname__}({in_parens})" + + +def stub_factory(klass, name, *, with_repr=None, _seen={}): + if (klass, name) not in _seen: + + class Stub(klass): + def __init__(self, *args, **kwargs): + super().__init__() + self.__stub_args = args + self.__stub_kwargs = kwargs + + Stub.__name__ = name + Stub.__qualname__ = name + if with_repr is not None: + Stub._repr = None + + _seen.setdefault((klass, name, with_repr), Stub) + + return _seen[(klass, name, with_repr)] diff --git a/Lib/test/support/_hypothesis_stubs/strategies.py b/Lib/test/support/_hypothesis_stubs/strategies.py new file mode 100644 index 000000000000..d2b885d41e16 --- /dev/null +++ b/Lib/test/support/_hypothesis_stubs/strategies.py @@ -0,0 +1,91 @@ +import functools + +from ._helpers import StubClass, stub_factory + + +class StubStrategy(StubClass): + def __make_trailing_repr(self, transformation_name, func): + func_name = func.__name__ or repr(func) + return f"{self!r}.{transformation_name}({func_name})" + + def map(self, pack): + return self._with_repr(self.__make_trailing_repr("map", pack)) + + def flatmap(self, expand): + return self._with_repr(self.__make_trailing_repr("flatmap", expand)) + + def filter(self, condition): + return self._with_repr(self.__make_trailing_repr("filter", condition)) + + def __or__(self, other): + new_repr = f"one_of({self!r}, {other!r})" + return self._with_repr(new_repr) + + +_STRATEGIES = { + "binary", + "booleans", + "builds", + "characters", + "complex_numbers", + "composite", + "data", + "dates", + "datetimes", + "decimals", + "deferred", + "dictionaries", + "emails", + "fixed_dictionaries", + "floats", + "fractions", + "from_regex", + "from_type", + "frozensets", + "functions", + "integers", + "iterables", + "just", + "lists", + "none", + "nothing", + "one_of", + "permutations", + "random_module", + "randoms", + "recursive", + "register_type_strategy", + "runner", + "sampled_from", + "sets", + "shared", + "slices", + "timedeltas", + "times", + "text", + "tuples", + "uuids", +} + +__all__ = sorted(_STRATEGIES) + + +def composite(f): + strategy = stub_factory(StubStrategy, f.__name__) + + @functools.wraps(f) + def inner(*args, **kwargs): + return strategy(*args, **kwargs) + + return inner + + +def __getattr__(name): + if name not in _STRATEGIES: + raise AttributeError(f"Unknown attribute {name}") + + return stub_factory(StubStrategy, f"hypothesis.strategies.{name}") + + +def __dir__(): + return __all__ diff --git a/Lib/test/support/hypothesis_helper.py b/Lib/test/support/hypothesis_helper.py new file mode 100644 index 000000000000..76bd2490fe6e --- /dev/null +++ b/Lib/test/support/hypothesis_helper.py @@ -0,0 +1,4 @@ +try: + import hypothesis +except ImportError: + from . import _hypothesis_stubs as hypothesis diff --git a/Lib/test/test_zoneinfo/__init__.py b/Lib/test/test_zoneinfo/__init__.py index 98cc4412ae16..c3ea56710327 100644 --- a/Lib/test/test_zoneinfo/__init__.py +++ b/Lib/test/test_zoneinfo/__init__.py @@ -1 +1,2 @@ from .test_zoneinfo import * +from .test_zoneinfo_property import * diff --git a/Lib/test/test_zoneinfo/test_zoneinfo_property.py b/Lib/test/test_zoneinfo/test_zoneinfo_property.py new file mode 100644 index 000000000000..feaa77f3e7f0 --- /dev/null +++ b/Lib/test/test_zoneinfo/test_zoneinfo_property.py @@ -0,0 +1,368 @@ +import contextlib +import datetime +import os +import pickle +import unittest +import zoneinfo + +from test.support.hypothesis_helper import hypothesis + +import test.test_zoneinfo._support as test_support + +ZoneInfoTestBase = test_support.ZoneInfoTestBase + +py_zoneinfo, c_zoneinfo = test_support.get_modules() + +UTC = datetime.timezone.utc +MIN_UTC = datetime.datetime.min.replace(tzinfo=UTC) +MAX_UTC = datetime.datetime.max.replace(tzinfo=UTC) +ZERO = datetime.timedelta(0) + + +def _valid_keys(): + """Get available time zones, including posix/ and right/ directories.""" + from importlib import resources + + available_zones = sorted(zoneinfo.available_timezones()) + TZPATH = zoneinfo.TZPATH + + def valid_key(key): + for root in TZPATH: + key_file = os.path.join(root, key) + if os.path.exists(key_file): + return True + + components = key.split("/") + package_name = ".".join(["tzdata.zoneinfo"] + components[:-1]) + resource_name = components[-1] + + try: + return resources.files(package_name).joinpath(resource_name).is_file() + except ModuleNotFoundError: + return False + + # This relies on the fact that dictionaries maintain insertion order ? for + # shrinking purposes, it is preferable to start with the standard version, + # then move to the posix/ version, then to the right/ version. + out_zones = {"": available_zones} + for prefix in ["posix", "right"]: + prefix_out = [] + for key in available_zones: + prefix_key = f"{prefix}/{key}" + if valid_key(prefix_key): + prefix_out.append(prefix_key) + + out_zones[prefix] = prefix_out + + output = [] + for keys in out_zones.values(): + output.extend(keys) + + return output + + +VALID_KEYS = _valid_keys() +if not VALID_KEYS: + raise unittest.SkipTest("No time zone data available") + + +def valid_keys(): + return hypothesis.strategies.sampled_from(VALID_KEYS) + + +KEY_EXAMPLES = [ + "Africa/Abidjan", + "Africa/Casablanca", + "America/Los_Angeles", + "America/Santiago", + "Asia/Tokyo", + "Australia/Sydney", + "Europe/Dublin", + "Europe/Lisbon", + "Europe/London", + "Pacific/Kiritimati", + "UTC", +] + + +def add_key_examples(f): + for key in KEY_EXAMPLES: + f = hypothesis.example(key)(f) + return f + + +class ZoneInfoTest(ZoneInfoTestBase): + module = py_zoneinfo + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_str(self, key): + zi = self.klass(key) + self.assertEqual(str(zi), key) + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_key(self, key): + zi = self.klass(key) + + self.assertEqual(zi.key, key) + + @hypothesis.given( + dt=hypothesis.strategies.one_of( + hypothesis.strategies.datetimes(), hypothesis.strategies.times() + ) + ) + @hypothesis.example(dt=datetime.datetime.min) + @hypothesis.example(dt=datetime.datetime.max) + @hypothesis.example(dt=datetime.datetime(1970, 1, 1)) + @hypothesis.example(dt=datetime.datetime(2039, 1, 1)) + @hypothesis.example(dt=datetime.time(0)) + @hypothesis.example(dt=datetime.time(12, 0)) + @hypothesis.example(dt=datetime.time(23, 59, 59, 999999)) + def test_utc(self, dt): + zi = self.klass("UTC") + dt_zi = dt.replace(tzinfo=zi) + + self.assertEqual(dt_zi.utcoffset(), ZERO) + self.assertEqual(dt_zi.dst(), ZERO) + self.assertEqual(dt_zi.tzname(), "UTC") + + +class CZoneInfoTest(ZoneInfoTest): + module = c_zoneinfo + + +class ZoneInfoPickleTest(ZoneInfoTestBase): + module = py_zoneinfo + + def setUp(self): + with contextlib.ExitStack() as stack: + stack.enter_context(test_support.set_zoneinfo_module(self.module)) + self.addCleanup(stack.pop_all().close) + + super().setUp() + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_pickle_unpickle_cache(self, key): + zi = self.klass(key) + pkl_str = pickle.dumps(zi) + zi_rt = pickle.loads(pkl_str) + + self.assertIs(zi, zi_rt) + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_pickle_unpickle_no_cache(self, key): + zi = self.klass.no_cache(key) + pkl_str = pickle.dumps(zi) + zi_rt = pickle.loads(pkl_str) + + self.assertIsNot(zi, zi_rt) + self.assertEqual(str(zi), str(zi_rt)) + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_pickle_unpickle_cache_multiple_rounds(self, key): + """Test that pickle/unpickle is idempotent.""" + zi_0 = self.klass(key) + pkl_str_0 = pickle.dumps(zi_0) + zi_1 = pickle.loads(pkl_str_0) + pkl_str_1 = pickle.dumps(zi_1) + zi_2 = pickle.loads(pkl_str_1) + pkl_str_2 = pickle.dumps(zi_2) + + self.assertEqual(pkl_str_0, pkl_str_1) + self.assertEqual(pkl_str_1, pkl_str_2) + + self.assertIs(zi_0, zi_1) + self.assertIs(zi_0, zi_2) + self.assertIs(zi_1, zi_2) + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_pickle_unpickle_no_cache_multiple_rounds(self, key): + """Test that pickle/unpickle is idempotent.""" + zi_cache = self.klass(key) + + zi_0 = self.klass.no_cache(key) + pkl_str_0 = pickle.dumps(zi_0) + zi_1 = pickle.loads(pkl_str_0) + pkl_str_1 = pickle.dumps(zi_1) + zi_2 = pickle.loads(pkl_str_1) + pkl_str_2 = pickle.dumps(zi_2) + + self.assertEqual(pkl_str_0, pkl_str_1) + self.assertEqual(pkl_str_1, pkl_str_2) + + self.assertIsNot(zi_0, zi_1) + self.assertIsNot(zi_0, zi_2) + self.assertIsNot(zi_1, zi_2) + + self.assertIsNot(zi_0, zi_cache) + self.assertIsNot(zi_1, zi_cache) + self.assertIsNot(zi_2, zi_cache) + + +class CZoneInfoPickleTest(ZoneInfoPickleTest): + module = c_zoneinfo + + +class ZoneInfoCacheTest(ZoneInfoTestBase): + module = py_zoneinfo + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_cache(self, key): + zi_0 = self.klass(key) + zi_1 = self.klass(key) + + self.assertIs(zi_0, zi_1) + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_no_cache(self, key): + zi_0 = self.klass.no_cache(key) + zi_1 = self.klass.no_cache(key) + + self.assertIsNot(zi_0, zi_1) + + +class CZoneInfoCacheTest(ZoneInfoCacheTest): + klass = c_zoneinfo.ZoneInfo + + +class PythonCConsistencyTest(unittest.TestCase): + """Tests that the C and Python versions do the same thing.""" + + def _is_ambiguous(self, dt): + return dt.replace(fold=not dt.fold).utcoffset() == dt.utcoffset() + + @hypothesis.given(dt=hypothesis.strategies.datetimes(), key=valid_keys()) + @hypothesis.example(dt=datetime.datetime.min, key="America/New_York") + @hypothesis.example(dt=datetime.datetime.max, key="America/New_York") + @hypothesis.example(dt=datetime.datetime(1970, 1, 1), key="America/New_York") + @hypothesis.example(dt=datetime.datetime(2020, 1, 1), key="Europe/Paris") + @hypothesis.example(dt=datetime.datetime(2020, 6, 1), key="Europe/Paris") + def test_same_str(self, dt, key): + py_dt = dt.replace(tzinfo=py_zoneinfo.ZoneInfo(key)) + c_dt = dt.replace(tzinfo=c_zoneinfo.ZoneInfo(key)) + + self.assertEqual(str(py_dt), str(c_dt)) + + @hypothesis.given(dt=hypothesis.strategies.datetimes(), key=valid_keys()) + @hypothesis.example(dt=datetime.datetime(1970, 1, 1), key="America/New_York") + @hypothesis.example(dt=datetime.datetime(2020, 2, 5), key="America/New_York") + @hypothesis.example(dt=datetime.datetime(2020, 8, 12), key="America/New_York") + @hypothesis.example(dt=datetime.datetime(2040, 1, 1), key="Africa/Casablanca") + @hypothesis.example(dt=datetime.datetime(1970, 1, 1), key="Europe/Paris") + @hypothesis.example(dt=datetime.datetime(2040, 1, 1), key="Europe/Paris") + @hypothesis.example(dt=datetime.datetime.min, key="Asia/Tokyo") + @hypothesis.example(dt=datetime.datetime.max, key="Asia/Tokyo") + def test_same_offsets_and_names(self, dt, key): + py_dt = dt.replace(tzinfo=py_zoneinfo.ZoneInfo(key)) + c_dt = dt.replace(tzinfo=c_zoneinfo.ZoneInfo(key)) + + self.assertEqual(py_dt.tzname(), c_dt.tzname()) + self.assertEqual(py_dt.utcoffset(), c_dt.utcoffset()) + self.assertEqual(py_dt.dst(), c_dt.dst()) + + @hypothesis.given( + dt=hypothesis.strategies.datetimes(timezones=hypothesis.strategies.just(UTC)), + key=valid_keys(), + ) + @hypothesis.example(dt=MIN_UTC, key="Asia/Tokyo") + @hypothesis.example(dt=MAX_UTC, key="Asia/Tokyo") + @hypothesis.example(dt=MIN_UTC, key="America/New_York") + @hypothesis.example(dt=MAX_UTC, key="America/New_York") + @hypothesis.example( + dt=datetime.datetime(2006, 10, 29, 5, 15, tzinfo=UTC), + key="America/New_York", + ) + def test_same_from_utc(self, dt, key): + py_zi = py_zoneinfo.ZoneInfo(key) + c_zi = c_zoneinfo.ZoneInfo(key) + + # Convert to UTC: This can overflow, but we just care about consistency + py_overflow_exc = None + c_overflow_exc = None + try: + py_dt = dt.astimezone(py_zi) + except OverflowError as e: + py_overflow_exc = e + + try: + c_dt = dt.astimezone(c_zi) + except OverflowError as e: + c_overflow_exc = e + + if (py_overflow_exc is not None) != (c_overflow_exc is not None): + raise py_overflow_exc or c_overflow_exc # pragma: nocover + + if py_overflow_exc is not None: + return # Consistently raises the same exception + + # PEP 495 says that an inter-zone comparison between ambiguous + # datetimes is always False. + if py_dt != c_dt: + self.assertEqual( + self._is_ambiguous(py_dt), + self._is_ambiguous(c_dt), + (py_dt, c_dt), + ) + + self.assertEqual(py_dt.tzname(), c_dt.tzname()) + self.assertEqual(py_dt.utcoffset(), c_dt.utcoffset()) + self.assertEqual(py_dt.dst(), c_dt.dst()) + + @hypothesis.given(dt=hypothesis.strategies.datetimes(), key=valid_keys()) + @hypothesis.example(dt=datetime.datetime.max, key="America/New_York") + @hypothesis.example(dt=datetime.datetime.min, key="America/New_York") + @hypothesis.example(dt=datetime.datetime.min, key="Asia/Tokyo") + @hypothesis.example(dt=datetime.datetime.max, key="Asia/Tokyo") + def test_same_to_utc(self, dt, key): + py_dt = dt.replace(tzinfo=py_zoneinfo.ZoneInfo(key)) + c_dt = dt.replace(tzinfo=c_zoneinfo.ZoneInfo(key)) + + # Convert from UTC: Overflow OK if it happens in both implementations + py_overflow_exc = None + c_overflow_exc = None + try: + py_utc = py_dt.astimezone(UTC) + except OverflowError as e: + py_overflow_exc = e + + try: + c_utc = c_dt.astimezone(UTC) + except OverflowError as e: + c_overflow_exc = e + + if (py_overflow_exc is not None) != (c_overflow_exc is not None): + raise py_overflow_exc or c_overflow_exc # pragma: nocover + + if py_overflow_exc is not None: + return # Consistently raises the same exception + + self.assertEqual(py_utc, c_utc) + + @hypothesis.given(key=valid_keys()) + @add_key_examples + def test_cross_module_pickle(self, key): + py_zi = py_zoneinfo.ZoneInfo(key) + c_zi = c_zoneinfo.ZoneInfo(key) + + with test_support.set_zoneinfo_module(py_zoneinfo): + py_pkl = pickle.dumps(py_zi) + + with test_support.set_zoneinfo_module(c_zoneinfo): + c_pkl = pickle.dumps(c_zi) + + with test_support.set_zoneinfo_module(c_zoneinfo): + # Python ? C + py_to_c_zi = pickle.loads(py_pkl) + self.assertIs(py_to_c_zi, c_zi) + + with test_support.set_zoneinfo_module(py_zoneinfo): + # C ? Python + c_to_py_zi = pickle.loads(c_pkl) + self.assertIs(c_to_py_zi, py_zi) diff --git a/Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst b/Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst new file mode 100644 index 000000000000..37ab74ffc441 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst @@ -0,0 +1,2 @@ +Added property-based tests to the :mod:`zoneinfo` tests, along with stubs +for the ``hypothesis`` interface. (Patch by Paul Ganssle) From webhook-mailer at python.org Fri May 12 08:36:19 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 12 May 2023 12:36:19 -0000 Subject: [Python-checkins] gh-104415: Fix refleak tests for `typing.ByteString` deprecation (#104416) Message-ID: <mailman.328.1683894980.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5b8cd5abe5924646b9ed90e7ba90085b56d5f634 commit: 5b8cd5abe5924646b9ed90e7ba90085b56d5f634 branch: main author: Nikita Sobolev <mail at sobolevn.me> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-12T05:36:12-07:00 summary: gh-104415: Fix refleak tests for `typing.ByteString` deprecation (#104416) files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index bf7bd241972a..513d4d96dd6e 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -3586,3 +3586,12 @@ def __getattr__(attr): ) return ByteString raise AttributeError(f"module 'typing' has no attribute {attr!r}") + + +def _remove_cached_ByteString_from_globals(): + try: + del globals()["ByteString"] + except KeyError: + pass + +_cleanups.append(_remove_cached_ByteString_from_globals) From webhook-mailer at python.org Fri May 12 08:57:16 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 12 May 2023 12:57:16 -0000 Subject: [Python-checkins] GH-104371: check return value of calling `mv.release` (#104417) Message-ID: <mailman.329.1683896237.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a052be4c0d9707ebdb935b8314ed22e8d3d99fc0 commit: a052be4c0d9707ebdb935b8314ed22e8d3d99fc0 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-12T18:27:06+05:30 summary: GH-104371: check return value of calling `mv.release` (#104417) files: M Objects/typeobject.c diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a1ad5021c415..c1525320a7cb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9158,7 +9158,13 @@ releasebuffer_call_python(PyObject *self, Py_buffer *buffer) Py_DECREF(ret); } if (!is_buffer_wrapper) { - PyObject_CallMethodNoArgs(mv, &_Py_ID(release)); + PyObject *res = PyObject_CallMethodNoArgs(mv, &_Py_ID(release)); + if (res == NULL) { + PyErr_WriteUnraisable(self); + } + else { + Py_DECREF(res); + } } Py_DECREF(mv); end: From webhook-mailer at python.org Fri May 12 10:38:51 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 12 May 2023 14:38:51 -0000 Subject: [Python-checkins] gh-91896: Fixup some docs issues following ByteString deprecation (#104422) Message-ID: <mailman.330.1683902331.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ce4eecf989e23fa26c033de78f1ca8b035a979cb commit: ce4eecf989e23fa26c033de78f1ca8b035a979cb branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-12T15:38:35+01:00 summary: gh-91896: Fixup some docs issues following ByteString deprecation (#104422) Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Doc/library/collections.abc.rst M Doc/whatsnew/3.12.rst diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 43a3286ba832..158f48516346 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -14,7 +14,10 @@ .. testsetup:: * - from collections.abc import * + import warnings + # Ignore warning when ByteString is imported + with warnings.catch_warnings(action='ignore', category=DeprecationWarning): + from collections.abc import * import itertools __name__ = '<doctest>' diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index eb13d4bf031c..546c7147bb3b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -831,6 +831,9 @@ Pending Removal in Python 3.14 For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. (Contributed by Shantanu Jain in :gh:`91896`.) +* :class:`typing.ByteString`, deprecated since Python 3.9, now causes an + :exc:`DeprecationWarning` to be emitted when it is used or accessed. + * Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases using the C API. From webhook-mailer at python.org Fri May 12 11:51:53 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 12 May 2023 15:51:53 -0000 Subject: [Python-checkins] gh-86275: Fix install of new _hypothesis_stubs directory (#104425) Message-ID: <mailman.331.1683906715.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b7597dab2c9ef7b825e190c5e4b130203361df24 commit: b7597dab2c9ef7b825e190c5e4b130203361df24 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-12T15:51:46Z summary: gh-86275: Fix install of new _hypothesis_stubs directory (#104425) files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 329466580b9c..52cafabd1ab9 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2060,6 +2060,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/sndhdrdata \ test/subprocessdata \ test/support \ + test/support/_hypothesis_stubs \ test/test_asyncio \ test/test_capi \ test/test_ctypes \ From webhook-mailer at python.org Fri May 12 12:23:15 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 12 May 2023 16:23:15 -0000 Subject: [Python-checkins] GH-86275: Run hypothesis tests in parallel (#104427) Message-ID: <mailman.332.1683908596.13550.python-checkins@python.org> https://github.com/python/cpython/commit/590d7a527d43e4a50fcf74839e516ff7b869434f commit: 590d7a527d43e4a50fcf74839e516ff7b869434f branch: main author: Paul Ganssle <1377457+pganssle at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-12T16:23:08Z summary: GH-86275: Run hypothesis tests in parallel (#104427) Run hypothesis tests in parallel files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f0a2dd5694c0..69b78e5567ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -377,6 +377,8 @@ jobs: # failing when executed from inside a virtual environment. ${{ env.VENV_PYTHON }} -m test \ -W \ + -o \ + -j4 \ -x test_asyncio \ -x test_multiprocessing_fork \ -x test_multiprocessing_forkserver \ From webhook-mailer at python.org Fri May 12 14:25:52 2023 From: webhook-mailer at python.org (abalkin) Date: Fri, 12 May 2023 18:25:52 -0000 Subject: [Python-checkins] gh-103857: Update deprecation stacktrace to point to calling line (#104431) Message-ID: <mailman.333.1683915953.13550.python-checkins@python.org> https://github.com/python/cpython/commit/25db95d224d18fb7b7f53165aeaa87632b0230f2 commit: 25db95d224d18fb7b7f53165aeaa87632b0230f2 branch: main author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: abalkin <abalkin at users.noreply.github.com> date: 2023-05-12T22:25:45+04:00 summary: gh-103857: Update deprecation stacktrace to point to calling line (#104431) files: A Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst M Modules/_datetimemodule.c diff --git a/Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst b/Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst new file mode 100644 index 000000000000..6e8162d9ecc2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst @@ -0,0 +1 @@ +Update datetime deprecations' stracktrace to point to the calling line diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8f86fc919662..8b417bdd0fb5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5147,7 +5147,7 @@ datetime_utcnow(PyObject *cls, PyObject *dummy) if (PyErr_WarnEx(PyExc_DeprecationWarning, "datetime.utcnow() is deprecated and scheduled for removal in a " "future version. Use timezone-aware objects to represent datetimes " - "in UTC: datetime.now(datetime.UTC).", 2)) + "in UTC: datetime.now(datetime.UTC).", 1)) { return NULL; } @@ -5190,7 +5190,7 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) if (PyErr_WarnEx(PyExc_DeprecationWarning, "datetime.utcfromtimestamp() is deprecated and scheduled for removal " "in a future version. Use timezone-aware objects to represent " - "datetimes in UTC: datetime.now(datetime.UTC).", 2)) + "datetimes in UTC: datetime.now(datetime.UTC).", 1)) { return NULL; } From webhook-mailer at python.org Fri May 12 16:26:27 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 12 May 2023 20:26:27 -0000 Subject: [Python-checkins] gh-103204: `http.server` - Enforce that HTTP version numbers must consist only of digits (#103205) Message-ID: <mailman.334.1683923188.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cf720acfcbd8c9c25a706a4b6df136465a803992 commit: cf720acfcbd8c9c25a706a4b6df136465a803992 branch: main author: Ben Kallus <49924171+kenballus at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-12T13:25:58-07:00 summary: gh-103204: `http.server` - Enforce that HTTP version numbers must consist only of digits (#103205) Reject HTTP requests with invalid http/x.y version numbers: x or y being non-digits or too-long. --------- Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index a245ffb30786..ca6240d9a921 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -300,6 +300,10 @@ def parse_request(self): # - Leading zeros MUST be ignored by recipients. if len(version_number) != 2: raise ValueError + if any(not component.isdigit() for component in version_number): + raise ValueError("non digit in http version") + if any(len(component) > 10 for component in version_number): + raise ValueError("unreasonable length http version") version_number = int(version_number[0]), int(version_number[1]) except (ValueError, IndexError): self.send_error( diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 0382b5ec448d..cdd1bea754a0 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -164,6 +164,27 @@ def test_version_digits(self): res = self.con.getresponse() self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + def test_version_signs_and_underscores(self): + self.con._http_vsn_str = 'HTTP/-9_9_9.+9_9_9' + self.con.putrequest('GET', '/') + self.con.endheaders() + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + + def test_major_version_number_too_long(self): + self.con._http_vsn_str = 'HTTP/909876543210.0' + self.con.putrequest('GET', '/') + self.con.endheaders() + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + + def test_minor_version_number_too_long(self): + self.con._http_vsn_str = 'HTTP/1.909876543210' + self.con.putrequest('GET', '/') + self.con.endheaders() + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + def test_version_none_get(self): self.con._http_vsn_str = '' self.con.putrequest('GET', '/') diff --git a/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst b/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst new file mode 100644 index 000000000000..f8b3aa5151b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst @@ -0,0 +1,3 @@ +Fixes :mod:`http.server` accepting HTTP requests with HTTP version numbers +preceded by '+', or '-', or with digit-separating '_' characters. The length +of the version numbers is also constrained. From webhook-mailer at python.org Fri May 12 16:33:31 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 12 May 2023 20:33:31 -0000 Subject: [Python-checkins] gh-103333: Pickle the keyword attributes of AttributeError (#103352) Message-ID: <mailman.335.1683923612.13550.python-checkins@python.org> https://github.com/python/cpython/commit/79b17f2cf0e1a2688bd91df02744f461835c4253 commit: 79b17f2cf0e1a2688bd91df02744f461835c4253 branch: main author: Charles Machalow <csm10495 at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-12T13:33:23-07:00 summary: gh-103333: Pickle the keyword attributes of AttributeError (#103352) * Pickle the `name` and `args` attributes of AttributeError when present. Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst M Lib/test/test_exceptions.py M Objects/exceptions.c diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4ef7decfbc26..f3554f1c4bb3 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -417,45 +417,45 @@ def testAttributes(self): # test that exception attributes are happy exceptionList = [ - (BaseException, (), {'args' : ()}), - (BaseException, (1, ), {'args' : (1,)}), - (BaseException, ('foo',), + (BaseException, (), {}, {'args' : ()}), + (BaseException, (1, ), {}, {'args' : (1,)}), + (BaseException, ('foo',), {}, {'args' : ('foo',)}), - (BaseException, ('foo', 1), + (BaseException, ('foo', 1), {}, {'args' : ('foo', 1)}), - (SystemExit, ('foo',), + (SystemExit, ('foo',), {}, {'args' : ('foo',), 'code' : 'foo'}), - (OSError, ('foo',), + (OSError, ('foo',), {}, {'args' : ('foo',), 'filename' : None, 'filename2' : None, 'errno' : None, 'strerror' : None}), - (OSError, ('foo', 'bar'), + (OSError, ('foo', 'bar'), {}, {'args' : ('foo', 'bar'), 'filename' : None, 'filename2' : None, 'errno' : 'foo', 'strerror' : 'bar'}), - (OSError, ('foo', 'bar', 'baz'), + (OSError, ('foo', 'bar', 'baz'), {}, {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2' : None, 'errno' : 'foo', 'strerror' : 'bar'}), - (OSError, ('foo', 'bar', 'baz', None, 'quux'), + (OSError, ('foo', 'bar', 'baz', None, 'quux'), {}, {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}), - (OSError, ('errnoStr', 'strErrorStr', 'filenameStr'), + (OSError, ('errnoStr', 'strErrorStr', 'filenameStr'), {}, {'args' : ('errnoStr', 'strErrorStr'), 'strerror' : 'strErrorStr', 'errno' : 'errnoStr', 'filename' : 'filenameStr'}), - (OSError, (1, 'strErrorStr', 'filenameStr'), + (OSError, (1, 'strErrorStr', 'filenameStr'), {}, {'args' : (1, 'strErrorStr'), 'errno' : 1, 'strerror' : 'strErrorStr', 'filename' : 'filenameStr', 'filename2' : None}), - (SyntaxError, (), {'msg' : None, 'text' : None, + (SyntaxError, (), {}, {'msg' : None, 'text' : None, 'filename' : None, 'lineno' : None, 'offset' : None, 'end_offset': None, 'print_file_and_line' : None}), - (SyntaxError, ('msgStr',), + (SyntaxError, ('msgStr',), {}, {'args' : ('msgStr',), 'text' : None, 'print_file_and_line' : None, 'msg' : 'msgStr', 'filename' : None, 'lineno' : None, 'offset' : None, 'end_offset': None}), (SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr', - 'textStr', 'endLinenoStr', 'endOffsetStr')), + 'textStr', 'endLinenoStr', 'endOffsetStr')), {}, {'offset' : 'offsetStr', 'text' : 'textStr', 'args' : ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr', 'textStr', @@ -465,7 +465,7 @@ def testAttributes(self): 'end_lineno': 'endLinenoStr', 'end_offset': 'endOffsetStr'}), (SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr', 'textStr', 'endLinenoStr', 'endOffsetStr', - 'print_file_and_lineStr'), + 'print_file_and_lineStr'), {}, {'text' : None, 'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr', 'textStr', 'endLinenoStr', 'endOffsetStr', @@ -473,38 +473,40 @@ def testAttributes(self): 'print_file_and_line' : None, 'msg' : 'msgStr', 'filename' : None, 'lineno' : None, 'offset' : None, 'end_lineno': None, 'end_offset': None}), - (UnicodeError, (), {'args' : (),}), + (UnicodeError, (), {}, {'args' : (),}), (UnicodeEncodeError, ('ascii', 'a', 0, 1, - 'ordinal not in range'), + 'ordinal not in range'), {}, {'args' : ('ascii', 'a', 0, 1, 'ordinal not in range'), 'encoding' : 'ascii', 'object' : 'a', 'start' : 0, 'reason' : 'ordinal not in range'}), (UnicodeDecodeError, ('ascii', bytearray(b'\xff'), 0, 1, - 'ordinal not in range'), + 'ordinal not in range'), {}, {'args' : ('ascii', bytearray(b'\xff'), 0, 1, 'ordinal not in range'), 'encoding' : 'ascii', 'object' : b'\xff', 'start' : 0, 'reason' : 'ordinal not in range'}), (UnicodeDecodeError, ('ascii', b'\xff', 0, 1, - 'ordinal not in range'), + 'ordinal not in range'), {}, {'args' : ('ascii', b'\xff', 0, 1, 'ordinal not in range'), 'encoding' : 'ascii', 'object' : b'\xff', 'start' : 0, 'reason' : 'ordinal not in range'}), - (UnicodeTranslateError, ("\u3042", 0, 1, "ouch"), + (UnicodeTranslateError, ("\u3042", 0, 1, "ouch"), {}, {'args' : ('\u3042', 0, 1, 'ouch'), 'object' : '\u3042', 'reason' : 'ouch', 'start' : 0, 'end' : 1}), - (NaiveException, ('foo',), + (NaiveException, ('foo',), {}, {'args': ('foo',), 'x': 'foo'}), - (SlottedNaiveException, ('foo',), + (SlottedNaiveException, ('foo',), {}, {'args': ('foo',), 'x': 'foo'}), + (AttributeError, ('foo',), dict(name='name', obj='obj'), + dict(args=('foo',), name='name', obj='obj')), ] try: # More tests are in test_WindowsError exceptionList.append( - (WindowsError, (1, 'strErrorStr', 'filenameStr'), + (WindowsError, (1, 'strErrorStr', 'filenameStr'), {}, {'args' : (1, 'strErrorStr'), 'strerror' : 'strErrorStr', 'winerror' : None, 'errno' : 1, @@ -513,11 +515,11 @@ def testAttributes(self): except NameError: pass - for exc, args, expected in exceptionList: + for exc, args, kwargs, expected in exceptionList: try: - e = exc(*args) + e = exc(*args, **kwargs) except: - print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr) + print(f"\nexc={exc!r}, args={args!r}", file=sys.stderr) # raise else: # Verify module name @@ -540,7 +542,12 @@ def testAttributes(self): new = p.loads(s) for checkArgName in expected: got = repr(getattr(new, checkArgName)) - want = repr(expected[checkArgName]) + if exc == AttributeError and checkArgName == 'obj': + # See GH-103352, we're not pickling + # obj at this point. So verify it's None. + want = repr(None) + else: + want = repr(expected[checkArgName]) self.assertEqual(got, want, 'pickled "%r", attribute "%s' % (e, checkArgName)) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst new file mode 100644 index 000000000000..793f02c2afdc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst @@ -0,0 +1 @@ +:exc:`AttributeError` now retains the ``name`` attribute when pickled and unpickled. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index ba5ee291f08b..59c63f4aa449 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2287,6 +2287,46 @@ AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } +/* Pickling support */ +static PyObject * +AttributeError_getstate(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *dict = ((PyAttributeErrorObject *)self)->dict; + if (self->name || self->args) { + dict = dict ? PyDict_Copy(dict) : PyDict_New(); + if (dict == NULL) { + return NULL; + } + if (self->name && PyDict_SetItemString(dict, "name", self->name) < 0) { + Py_DECREF(dict); + return NULL; + } + /* We specifically are not pickling the obj attribute since there are many + cases where it is unlikely to be picklable. See GH-103352. + */ + if (self->args && PyDict_SetItemString(dict, "args", self->args) < 0) { + Py_DECREF(dict); + return NULL; + } + return dict; + } + else if (dict) { + return Py_NewRef(dict); + } + Py_RETURN_NONE; +} + +static PyObject * +AttributeError_reduce(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *state = AttributeError_getstate(self, NULL); + if (state == NULL) { + return NULL; + } + + return PyTuple_Pack(3, Py_TYPE(self), self->args, state); +} + static PyMemberDef AttributeError_members[] = { {"name", T_OBJECT, offsetof(PyAttributeErrorObject, name), 0, PyDoc_STR("attribute name")}, {"obj", T_OBJECT, offsetof(PyAttributeErrorObject, obj), 0, PyDoc_STR("object")}, @@ -2294,7 +2334,9 @@ static PyMemberDef AttributeError_members[] = { }; static PyMethodDef AttributeError_methods[] = { - {NULL} /* Sentinel */ + {"__getstate__", (PyCFunction)AttributeError_getstate, METH_NOARGS}, + {"__reduce__", (PyCFunction)AttributeError_reduce, METH_NOARGS }, + {NULL} }; ComplexExtendsException(PyExc_Exception, AttributeError, From webhook-mailer at python.org Fri May 12 16:54:20 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 12 May 2023 20:54:20 -0000 Subject: [Python-checkins] [3.11] gh-103204: `http.server` - Enforce that HTTP version numbers must consist only of digits (GH-103205) (#104438) Message-ID: <mailman.336.1683924860.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b4c1ca29ccd45c608ff01ce0a4608b1837715573 commit: b4c1ca29ccd45c608ff01ce0a4608b1837715573 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-12T20:54:12Z summary: [3.11] gh-103204: `http.server` - Enforce that HTTP version numbers must consist only of digits (GH-103205) (#104438) gh-103204: `http.server` - Enforce that HTTP version numbers must consist only of digits (GH-103205) Reject HTTP requests with invalid http/x.y version numbers: x or y being non-digits or too-long. --------- (cherry picked from commit cf720acfcbd8c9c25a706a4b6df136465a803992) Co-authored-by: Ben Kallus <49924171+kenballus at users.noreply.github.com> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index 3a6ac977693d..da07f110f177 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -300,6 +300,10 @@ def parse_request(self): # - Leading zeros MUST be ignored by recipients. if len(version_number) != 2: raise ValueError + if any(not component.isdigit() for component in version_number): + raise ValueError("non digit in http version") + if any(len(component) > 10 for component in version_number): + raise ValueError("unreasonable length http version") version_number = int(version_number[0]), int(version_number[1]) except (ValueError, IndexError): self.send_error( diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 0382b5ec448d..cdd1bea754a0 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -164,6 +164,27 @@ def test_version_digits(self): res = self.con.getresponse() self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + def test_version_signs_and_underscores(self): + self.con._http_vsn_str = 'HTTP/-9_9_9.+9_9_9' + self.con.putrequest('GET', '/') + self.con.endheaders() + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + + def test_major_version_number_too_long(self): + self.con._http_vsn_str = 'HTTP/909876543210.0' + self.con.putrequest('GET', '/') + self.con.endheaders() + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + + def test_minor_version_number_too_long(self): + self.con._http_vsn_str = 'HTTP/1.909876543210' + self.con.putrequest('GET', '/') + self.con.endheaders() + res = self.con.getresponse() + self.assertEqual(res.status, HTTPStatus.BAD_REQUEST) + def test_version_none_get(self): self.con._http_vsn_str = '' self.con.putrequest('GET', '/') diff --git a/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst b/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst new file mode 100644 index 000000000000..f8b3aa5151b6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst @@ -0,0 +1,3 @@ +Fixes :mod:`http.server` accepting HTTP requests with HTTP version numbers +preceded by '+', or '-', or with digit-separating '_' characters. The length +of the version numbers is also constrained. From webhook-mailer at python.org Fri May 12 17:27:09 2023 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 12 May 2023 21:27:09 -0000 Subject: [Python-checkins] GH-94841: Fix usage of Py_ALWAYS_INLINE (GH-104409) Message-ID: <mailman.337.1683926830.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a10b026f0fdceac42c4b928917894d77da996555 commit: a10b026f0fdceac42c4b928917894d77da996555 branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-12T14:26:54-07:00 summary: GH-94841: Fix usage of Py_ALWAYS_INLINE (GH-104409) files: M Objects/obmalloc.c diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index de62aeb04461..090129fe8653 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -882,7 +882,7 @@ _Py_GetGlobalAllocatedBlocks(void) /* Return a pointer to a bottom tree node, return NULL if it doesn't exist or * it cannot be created */ -static Py_ALWAYS_INLINE arena_map_bot_t * +static inline Py_ALWAYS_INLINE arena_map_bot_t * arena_map_get(OMState *state, pymem_block *p, int create) { #ifdef USE_INTERIOR_NODES From webhook-mailer at python.org Fri May 12 18:06:39 2023 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 12 May 2023 22:06:39 -0000 Subject: [Python-checkins] [3.11] GH-94841: Fix usage of Py_ALWAYS_INLINE (GH-104439) Message-ID: <mailman.338.1683929200.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b90c922f3f852b51b11de19d73015e3eb64293f4 commit: b90c922f3f852b51b11de19d73015e3eb64293f4 branch: 3.11 author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-12T22:06:29Z summary: [3.11] GH-94841: Fix usage of Py_ALWAYS_INLINE (GH-104439) files: M Objects/obmalloc.c diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index fae9c8110f19..b9529e418d4f 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1445,7 +1445,7 @@ static arena_map_bot_t arena_map_root; /* Return a pointer to a bottom tree node, return NULL if it doesn't exist or * it cannot be created */ -static Py_ALWAYS_INLINE arena_map_bot_t * +static inline Py_ALWAYS_INLINE arena_map_bot_t * arena_map_get(block *p, int create) { #ifdef USE_INTERIOR_NODES From webhook-mailer at python.org Fri May 12 18:23:21 2023 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 12 May 2023 22:23:21 -0000 Subject: [Python-checkins] GH-104405: Add missing PEP 523 checks (GH-104406) Message-ID: <mailman.339.1683930201.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1eb950ca55b3e0b6524b3f03b0b519723916eca2 commit: 1eb950ca55b3e0b6524b3f03b0b519723916eca2 branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-12T22:23:13Z summary: GH-104405: Add missing PEP 523 checks (GH-104406) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst M Lib/test/test_capi/test_misc.py M Python/bytecodes.c M Python/ceval_macros.h M Python/generated_cases.c.h M Python/specialize.c diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 3fc2c07f9330..0ef0b5d8b658 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1748,28 +1748,80 @@ class Subclass(BaseException, self.module.StateAccessType): class Test_Pep523API(unittest.TestCase): - def do_test(self, func): - calls = [] + def do_test(self, func, names): + actual_calls = [] start = SUFFICIENT_TO_DEOPT_AND_SPECIALIZE count = start + SUFFICIENT_TO_DEOPT_AND_SPECIALIZE - for i in range(count): - if i == start: - _testinternalcapi.set_eval_frame_record(calls) - func() - _testinternalcapi.set_eval_frame_default() - self.assertEqual(len(calls), SUFFICIENT_TO_DEOPT_AND_SPECIALIZE) - for name in calls: - self.assertEqual(name, func.__name__) - - def test_pep523_with_specialization_simple(self): - def func1(): - pass - self.do_test(func1) + try: + for i in range(count): + if i == start: + _testinternalcapi.set_eval_frame_record(actual_calls) + func() + finally: + _testinternalcapi.set_eval_frame_default() + expected_calls = names * SUFFICIENT_TO_DEOPT_AND_SPECIALIZE + self.assertEqual(len(expected_calls), len(actual_calls)) + for expected, actual in zip(expected_calls, actual_calls, strict=True): + self.assertEqual(expected, actual) + + def test_inlined_binary_subscr(self): + class C: + def __getitem__(self, other): + return None + def func(): + C()[42] + names = ["func", "__getitem__"] + self.do_test(func, names) - def test_pep523_with_specialization_with_default(self): - def func2(x=None): + def test_inlined_call(self): + def inner(x=42): + pass + def func(): + inner() + inner(42) + names = ["func", "inner", "inner"] + self.do_test(func, names) + + def test_inlined_call_function_ex(self): + def inner(x): pass - self.do_test(func2) + def func(): + inner(*[42]) + names = ["func", "inner"] + self.do_test(func, names) + + def test_inlined_for_iter(self): + def gen(): + yield 42 + def func(): + for _ in gen(): + pass + names = ["func", "gen", "gen", "gen"] + self.do_test(func, names) + + def test_inlined_load_attr(self): + class C: + @property + def a(self): + return 42 + class D: + def __getattribute__(self, name): + return 42 + def func(): + C().a + D().a + names = ["func", "a", "__getattribute__"] + self.do_test(func, names) + + def test_inlined_send(self): + def inner(): + yield 42 + def outer(): + yield from inner() + def func(): + list(outer()) + names = ["func", "outer", "outer", "inner", "inner", "outer", "inner"] + self.do_test(func, names) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst new file mode 100644 index 000000000000..06ec5d7b0f0c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst @@ -0,0 +1,2 @@ +Fix an issue where some :term:`bytecode` instructions could ignore +:pep:`523` when "inlining" calls. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 99935a3d7907..d84a078f1100 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -494,6 +494,7 @@ dummy_func( } inst(BINARY_SUBSCR_GETITEM, (unused/1, container, sub -- unused)) { + DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; @@ -830,8 +831,9 @@ 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) + if ((tstate->interp->eval_frame == NULL) && + (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; @@ -867,6 +869,7 @@ dummy_func( } inst(SEND_GEN, (unused/1, receiver, v -- receiver, unused)) { + DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); @@ -2331,6 +2334,7 @@ dummy_func( } inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { + DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index f5515d0d32de..e92ff0bd6fba 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -105,6 +105,7 @@ #define DISPATCH_INLINED(NEW_FRAME) \ do { \ + assert(tstate->interp->eval_frame == NULL); \ _PyFrame_SetStackPointer(frame, stack_pointer); \ frame->prev_instr = next_instr - 1; \ (NEW_FRAME)->previous = frame; \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0ded2f9dcdc2..014a69ff7e96 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -708,6 +708,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; #line 497 "Python/bytecodes.c" + DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; @@ -729,15 +730,15 @@ JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 733 "Python/generated_cases.c.h" + #line 734 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 521 "Python/bytecodes.c" + #line 522 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 741 "Python/generated_cases.c.h" + #line 742 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -746,13 +747,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 526 "Python/bytecodes.c" + #line 527 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 752 "Python/generated_cases.c.h" + #line 753 "Python/generated_cases.c.h" Py_DECREF(v); - #line 528 "Python/bytecodes.c" + #line 529 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 756 "Python/generated_cases.c.h" + #line 757 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -765,7 +766,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 539 "Python/bytecodes.c" + #line 540 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -780,13 +781,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 784 "Python/generated_cases.c.h" + #line 785 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 554 "Python/bytecodes.c" + #line 555 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 790 "Python/generated_cases.c.h" + #line 791 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -796,7 +797,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 558 "Python/bytecodes.c" + #line 559 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -813,7 +814,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 817 "Python/generated_cases.c.h" + #line 818 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -823,13 +824,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 577 "Python/bytecodes.c" + #line 578 "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 833 "Python/generated_cases.c.h" + #line 834 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -838,15 +839,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 585 "Python/bytecodes.c" + #line 586 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 845 "Python/generated_cases.c.h" + #line 846 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 588 "Python/bytecodes.c" + #line 589 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 850 "Python/generated_cases.c.h" + #line 851 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -854,14 +855,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 592 "Python/bytecodes.c" + #line 593 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 861 "Python/generated_cases.c.h" + #line 862 "Python/generated_cases.c.h" Py_DECREF(value); - #line 595 "Python/bytecodes.c" + #line 596 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 865 "Python/generated_cases.c.h" + #line 866 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -870,15 +871,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 599 "Python/bytecodes.c" + #line 600 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 877 "Python/generated_cases.c.h" + #line 878 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 602 "Python/bytecodes.c" + #line 603 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 882 "Python/generated_cases.c.h" + #line 883 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -886,7 +887,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 606 "Python/bytecodes.c" + #line 607 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -904,12 +905,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 908 "Python/generated_cases.c.h" + #line 909 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 626 "Python/bytecodes.c" + #line 627 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -920,12 +921,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 924 "Python/generated_cases.c.h" + #line 925 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 639 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -938,12 +939,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 942 "Python/generated_cases.c.h" + #line 943 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 654 "Python/bytecodes.c" + #line 655 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -960,11 +961,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 964 "Python/generated_cases.c.h" + #line 965 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 673 "Python/bytecodes.c" + #line 674 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -978,11 +979,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 982 "Python/generated_cases.c.h" + #line 983 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 689 "Python/bytecodes.c" + #line 690 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1000,13 +1001,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1004 "Python/generated_cases.c.h" + #line 1005 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 709 "Python/bytecodes.c" + #line 710 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1019,16 +1020,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1023 "Python/generated_cases.c.h" + #line 1024 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 722 "Python/bytecodes.c" + #line 723 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1030 "Python/generated_cases.c.h" + #line 1031 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 727 "Python/bytecodes.c" + #line 728 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1041,7 +1042,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1045 "Python/generated_cases.c.h" + #line 1046 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1049,7 +1050,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 742 "Python/bytecodes.c" + #line 743 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1093,7 +1094,7 @@ } } - #line 1097 "Python/generated_cases.c.h" + #line 1098 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -1104,16 +1105,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 789 "Python/bytecodes.c" + #line 790 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1115 "Python/generated_cases.c.h" + #line 1116 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 796 "Python/bytecodes.c" + #line 797 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1131,7 +1132,7 @@ if (iter == NULL) goto pop_1_error; - #line 1135 "Python/generated_cases.c.h" + #line 1136 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1143,7 +1144,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 822 "Python/bytecodes.c" + #line 823 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1155,8 +1156,9 @@ 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) + if ((tstate->interp->eval_frame == NULL) && + (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; @@ -1189,7 +1191,7 @@ } } Py_DECREF(v); - #line 1193 "Python/generated_cases.c.h" + #line 1195 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1198,7 +1200,8 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 870 "Python/bytecodes.c" + #line 872 "Python/bytecodes.c" + DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); @@ -1213,12 +1216,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1217 "Python/generated_cases.c.h" + #line 1220 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 887 "Python/bytecodes.c" + #line 890 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1235,12 +1238,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1239 "Python/generated_cases.c.h" + #line 1242 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 906 "Python/bytecodes.c" + #line 909 "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. @@ -1256,15 +1259,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1260 "Python/generated_cases.c.h" + #line 1263 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 924 "Python/bytecodes.c" + #line 927 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1268 "Python/generated_cases.c.h" + #line 1271 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1272,7 +1275,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 929 "Python/bytecodes.c" + #line 932 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1290,26 +1293,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1294 "Python/generated_cases.c.h" + #line 1297 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 949 "Python/bytecodes.c" + #line 952 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1303 "Python/generated_cases.c.h" + #line 1306 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 952 "Python/bytecodes.c" + #line 955 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1313 "Python/generated_cases.c.h" + #line 1316 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1320,23 +1323,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 961 "Python/bytecodes.c" + #line 964 "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 1329 "Python/generated_cases.c.h" + #line 1332 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 966 "Python/bytecodes.c" + #line 969 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1340 "Python/generated_cases.c.h" + #line 1343 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1345,9 +1348,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 975 "Python/bytecodes.c" + #line 978 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1351 "Python/generated_cases.c.h" + #line 1354 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1355,7 +1358,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 979 "Python/bytecodes.c" + #line 982 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1377,7 +1380,7 @@ if (true) goto error; } } - #line 1381 "Python/generated_cases.c.h" + #line 1384 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1385,33 +1388,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1003 "Python/bytecodes.c" + #line 1006 "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 1396 "Python/generated_cases.c.h" + #line 1399 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1010 "Python/bytecodes.c" + #line 1013 "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 1405 "Python/generated_cases.c.h" + #line 1408 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1017 "Python/bytecodes.c" + #line 1020 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1409 "Python/generated_cases.c.h" + #line 1412 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1021 "Python/bytecodes.c" + #line 1024 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1428,7 +1431,7 @@ name); goto error; } - #line 1432 "Python/generated_cases.c.h" + #line 1435 "Python/generated_cases.c.h" DISPATCH(); } @@ -1436,7 +1439,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1047 "Python/bytecodes.c" + #line 1050 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1449,11 +1452,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1453 "Python/generated_cases.c.h" + #line 1456 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1060 "Python/bytecodes.c" + #line 1063 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1457 "Python/generated_cases.c.h" + #line 1460 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1463,14 +1466,14 @@ TARGET(UNPACK_SEQUENCE_TWO_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) != 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 1474 "Python/generated_cases.c.h" + #line 1477 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1481,7 +1484,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1074 "Python/bytecodes.c" + #line 1077 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1489,7 +1492,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1493 "Python/generated_cases.c.h" + #line 1496 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1500,7 +1503,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1085 "Python/bytecodes.c" + #line 1088 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1508,7 +1511,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1512 "Python/generated_cases.c.h" + #line 1515 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1518,15 +1521,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1096 "Python/bytecodes.c" + #line 1099 "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 1526 "Python/generated_cases.c.h" + #line 1529 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1100 "Python/bytecodes.c" + #line 1103 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1530 "Python/generated_cases.c.h" + #line 1533 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1537,7 +1540,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1111 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1553,12 +1556,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1557 "Python/generated_cases.c.h" + #line 1560 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1127 "Python/bytecodes.c" + #line 1130 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1562 "Python/generated_cases.c.h" + #line 1565 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1566,34 +1569,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1131 "Python/bytecodes.c" + #line 1134 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1573 "Python/generated_cases.c.h" + #line 1576 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1134 "Python/bytecodes.c" + #line 1137 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1577 "Python/generated_cases.c.h" + #line 1580 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1138 "Python/bytecodes.c" + #line 1141 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1587 "Python/generated_cases.c.h" + #line 1590 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1141 "Python/bytecodes.c" + #line 1144 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1591 "Python/generated_cases.c.h" + #line 1594 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1145 "Python/bytecodes.c" + #line 1148 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1605,13 +1608,13 @@ } goto error; } - #line 1609 "Python/generated_cases.c.h" + #line 1612 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; - #line 1159 "Python/bytecodes.c" + #line 1162 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1670,7 +1673,7 @@ } } } - #line 1674 "Python/generated_cases.c.h" + #line 1677 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1681,7 +1684,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1226 "Python/bytecodes.c" + #line 1229 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1733,7 +1736,7 @@ } } null = NULL; - #line 1737 "Python/generated_cases.c.h" + #line 1740 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1747,7 +1750,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1280 "Python/bytecodes.c" + #line 1283 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1758,7 +1761,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1762 "Python/generated_cases.c.h" + #line 1765 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1773,7 +1776,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 1293 "Python/bytecodes.c" + #line 1296 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1788,7 +1791,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1792 "Python/generated_cases.c.h" + #line 1795 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1798,16 +1801,16 @@ } TARGET(DELETE_FAST) { - #line 1310 "Python/bytecodes.c" + #line 1313 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1806 "Python/generated_cases.c.h" + #line 1809 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1316 "Python/bytecodes.c" + #line 1319 "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); @@ -1816,12 +1819,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1820 "Python/generated_cases.c.h" + #line 1823 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1327 "Python/bytecodes.c" + #line 1330 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1832,13 +1835,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1836 "Python/generated_cases.c.h" + #line 1839 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1340 "Python/bytecodes.c" + #line 1343 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1870,7 +1873,7 @@ } 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,7 +1881,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1374 "Python/bytecodes.c" + #line 1377 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1886,7 +1889,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1890 "Python/generated_cases.c.h" + #line 1893 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1894,18 +1897,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1384 "Python/bytecodes.c" + #line 1387 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1903 "Python/generated_cases.c.h" + #line 1906 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1391 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1916,22 +1919,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1920 "Python/generated_cases.c.h" + #line 1923 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1404 "Python/bytecodes.c" + #line 1407 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1929 "Python/generated_cases.c.h" + #line 1932 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1406 "Python/bytecodes.c" + #line 1409 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1935 "Python/generated_cases.c.h" + #line 1938 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1941,10 +1944,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1410 "Python/bytecodes.c" + #line 1413 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1948 "Python/generated_cases.c.h" + #line 1951 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1954,10 +1957,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1415 "Python/bytecodes.c" + #line 1418 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1961 "Python/generated_cases.c.h" + #line 1964 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1967,7 +1970,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1420 "Python/bytecodes.c" + #line 1423 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1978,13 +1981,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1982 "Python/generated_cases.c.h" + #line 1985 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1431 "Python/bytecodes.c" + #line 1434 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1988 "Python/generated_cases.c.h" + #line 1991 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1993,13 +1996,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1438 "Python/bytecodes.c" + #line 1441 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1999 "Python/generated_cases.c.h" + #line 2002 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1440 "Python/bytecodes.c" + #line 1443 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2003 "Python/generated_cases.c.h" + #line 2006 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2007,7 +2010,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1444 "Python/bytecodes.c" + #line 1447 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2022,7 +2025,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2026 "Python/generated_cases.c.h" + #line 2029 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2032,7 +2035,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1461 "Python/bytecodes.c" + #line 1464 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2040,13 +2043,13 @@ if (map == NULL) goto error; - #line 2044 "Python/generated_cases.c.h" + #line 2047 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1469 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2050 "Python/generated_cases.c.h" + #line 2053 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2054,7 +2057,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1473 "Python/bytecodes.c" + #line 1476 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2094,7 +2097,7 @@ Py_DECREF(ann_dict); } } - #line 2098 "Python/generated_cases.c.h" + #line 2101 "Python/generated_cases.c.h" DISPATCH(); } @@ -2102,7 +2105,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1515 "Python/bytecodes.c" + #line 1518 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2112,14 +2115,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2116 "Python/generated_cases.c.h" + #line 2119 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1525 "Python/bytecodes.c" + #line 1528 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2123 "Python/generated_cases.c.h" + #line 2126 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2127,7 +2130,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1529 "Python/bytecodes.c" + #line 1532 "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)) { @@ -2135,12 +2138,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2139 "Python/generated_cases.c.h" + #line 2142 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1537 "Python/bytecodes.c" + #line 1540 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2144 "Python/generated_cases.c.h" + #line 2147 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2148,17 +2151,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1543 "Python/bytecodes.c" + #line 1546 "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 2157 "Python/generated_cases.c.h" + #line 2160 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1548 "Python/bytecodes.c" + #line 1551 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2162 "Python/generated_cases.c.h" + #line 2165 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2168,13 +2171,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1555 "Python/bytecodes.c" + #line 1558 "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 2178 "Python/generated_cases.c.h" + #line 2181 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2188,7 +2191,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1570 "Python/bytecodes.c" + #line 1573 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2206,16 +2209,16 @@ // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); - #line 2210 "Python/generated_cases.c.h" + #line 2213 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1588 "Python/bytecodes.c" + #line 1591 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2219 "Python/generated_cases.c.h" + #line 2222 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2230,20 +2233,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1595 "Python/bytecodes.c" + #line 1598 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2241 "Python/generated_cases.c.h" + #line 2244 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1602 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2247 "Python/generated_cases.c.h" + #line 2250 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2258,7 +2261,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1606 "Python/bytecodes.c" + #line 1609 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2279,7 +2282,7 @@ res = res2; res2 = NULL; } - #line 2283 "Python/generated_cases.c.h" + #line 2286 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2293,7 +2296,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1643 "Python/bytecodes.c" + #line 1646 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2327,9 +2330,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2331 "Python/generated_cases.c.h" + #line 2334 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1677 "Python/bytecodes.c" + #line 1680 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2338,12 +2341,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2342 "Python/generated_cases.c.h" + #line 2345 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1686 "Python/bytecodes.c" + #line 1689 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2347 "Python/generated_cases.c.h" + #line 2350 "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; } @@ -2357,7 +2360,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1691 "Python/bytecodes.c" + #line 1694 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2370,7 +2373,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2374 "Python/generated_cases.c.h" + #line 2377 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2385,7 +2388,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1707 "Python/bytecodes.c" + #line 1710 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2398,7 +2401,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2402 "Python/generated_cases.c.h" + #line 2405 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2413,7 +2416,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1723 "Python/bytecodes.c" + #line 1726 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2440,7 +2443,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2444 "Python/generated_cases.c.h" + #line 2447 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2455,7 +2458,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1753 "Python/bytecodes.c" + #line 1756 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2465,7 +2468,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2469 "Python/generated_cases.c.h" + #line 2472 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2480,7 +2483,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1766 "Python/bytecodes.c" + #line 1769 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2492,7 +2495,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2496 "Python/generated_cases.c.h" + #line 2499 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2506,7 +2509,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 1781 "Python/bytecodes.c" + #line 1784 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2530,7 +2533,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2534 "Python/generated_cases.c.h" + #line 2537 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2538,7 +2541,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 1807 "Python/bytecodes.c" + #line 1810 "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); @@ -2564,7 +2567,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2568 "Python/generated_cases.c.h" + #line 2571 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2572,7 +2575,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 1835 "Python/bytecodes.c" + #line 1838 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2590,7 +2593,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2594 "Python/generated_cases.c.h" + #line 2597 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2601,7 +2604,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 1855 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2640,7 +2643,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2644 "Python/generated_cases.c.h" + #line 2647 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2651,7 +2654,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 1896 "Python/bytecodes.c" + #line 1899 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2661,7 +2664,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2665 "Python/generated_cases.c.h" + #line 2668 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2673,7 +2676,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1915 "Python/bytecodes.c" + #line 1918 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2686,12 +2689,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2690 "Python/generated_cases.c.h" + #line 2693 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1928 "Python/bytecodes.c" + #line 1931 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2695 "Python/generated_cases.c.h" + #line 2698 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2702,7 +2705,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1932 "Python/bytecodes.c" + #line 1935 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2714,7 +2717,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2718 "Python/generated_cases.c.h" + #line 2721 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2725,7 +2728,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1947 "Python/bytecodes.c" + #line 1950 "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); @@ -2741,7 +2744,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2745 "Python/generated_cases.c.h" + #line 2748 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2752,7 +2755,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1966 "Python/bytecodes.c" + #line 1969 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2765,7 +2768,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2769 "Python/generated_cases.c.h" + #line 2772 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2776,14 +2779,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1981 "Python/bytecodes.c" + #line 1984 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2782 "Python/generated_cases.c.h" + #line 2785 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1983 "Python/bytecodes.c" + #line 1986 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2787 "Python/generated_cases.c.h" + #line 2790 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2793,15 +2796,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1987 "Python/bytecodes.c" + #line 1990 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2799 "Python/generated_cases.c.h" + #line 2802 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1989 "Python/bytecodes.c" + #line 1992 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2805 "Python/generated_cases.c.h" + #line 2808 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2812,12 +2815,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1994 "Python/bytecodes.c" + #line 1997 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2818 "Python/generated_cases.c.h" + #line 2821 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1996 "Python/bytecodes.c" + #line 1999 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2825,10 +2828,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2829 "Python/generated_cases.c.h" + #line 2832 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2004 "Python/bytecodes.c" + #line 2007 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2837,7 +2840,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2841 "Python/generated_cases.c.h" + #line 2844 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2847,21 +2850,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2015 "Python/bytecodes.c" + #line 2018 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2854 "Python/generated_cases.c.h" + #line 2857 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2018 "Python/bytecodes.c" + #line 2021 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2861 "Python/generated_cases.c.h" + #line 2864 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2023 "Python/bytecodes.c" + #line 2026 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2865 "Python/generated_cases.c.h" + #line 2868 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2870,15 +2873,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2027 "Python/bytecodes.c" + #line 2030 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2877 "Python/generated_cases.c.h" + #line 2880 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2030 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2882 "Python/generated_cases.c.h" + #line 2885 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2887,29 +2890,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2034 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2895 "Python/generated_cases.c.h" + #line 2898 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2040 "Python/bytecodes.c" + #line 2043 "Python/bytecodes.c" JUMPBY(oparg); - #line 2904 "Python/generated_cases.c.h" + #line 2907 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2044 "Python/bytecodes.c" + #line 2047 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2913 "Python/generated_cases.c.h" + #line 2916 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2917,7 +2920,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2050 "Python/bytecodes.c" + #line 2053 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2927,9 +2930,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2931 "Python/generated_cases.c.h" + #line 2934 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2060 "Python/bytecodes.c" + #line 2063 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2937,14 +2940,14 @@ if (err < 0) goto pop_1_error; } } - #line 2941 "Python/generated_cases.c.h" + #line 2944 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2070 "Python/bytecodes.c" + #line 2073 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2954,9 +2957,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2958 "Python/generated_cases.c.h" + #line 2961 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2080 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2964,67 +2967,67 @@ if (err < 0) goto pop_1_error; } } - #line 2968 "Python/generated_cases.c.h" + #line 2971 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2090 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2977 "Python/generated_cases.c.h" + #line 2980 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2092 "Python/bytecodes.c" + #line 2095 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2985 "Python/generated_cases.c.h" + #line 2988 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2100 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2998 "Python/generated_cases.c.h" + #line 3001 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2106 "Python/bytecodes.c" + #line 2109 "Python/bytecodes.c" } - #line 3002 "Python/generated_cases.c.h" + #line 3005 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2110 "Python/bytecodes.c" + #line 2113 "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 3015 "Python/generated_cases.c.h" + #line 3018 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2119 "Python/bytecodes.c" + #line 2122 "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 3028 "Python/generated_cases.c.h" + #line 3031 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3035,16 +3038,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2127 "Python/bytecodes.c" + #line 2130 "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 3044 "Python/generated_cases.c.h" + #line 3047 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2132 "Python/bytecodes.c" + #line 2135 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3052,7 +3055,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3056 "Python/generated_cases.c.h" + #line 3059 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3061,10 +3064,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2142 "Python/bytecodes.c" + #line 2145 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3068 "Python/generated_cases.c.h" + #line 3071 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3074,10 +3077,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2148 "Python/bytecodes.c" + #line 2151 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3081 "Python/generated_cases.c.h" + #line 3084 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3088,11 +3091,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2154 "Python/bytecodes.c" + #line 2157 "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 3096 "Python/generated_cases.c.h" + #line 3099 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3101,14 +3104,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2160 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3108 "Python/generated_cases.c.h" + #line 3111 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2163 "Python/bytecodes.c" + #line 2166 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3112 "Python/generated_cases.c.h" + #line 3115 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3116,7 +3119,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2167 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3139,11 +3142,11 @@ if (iter == NULL) { goto error; } - #line 3143 "Python/generated_cases.c.h" + #line 3146 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2190 "Python/bytecodes.c" + #line 2193 "Python/bytecodes.c" } - #line 3147 "Python/generated_cases.c.h" + #line 3150 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3154,7 +3157,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2209 "Python/bytecodes.c" + #line 2212 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3185,7 +3188,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3189 "Python/generated_cases.c.h" + #line 3192 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3193,7 +3196,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2242 "Python/bytecodes.c" + #line 2245 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3219,14 +3222,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3223 "Python/generated_cases.c.h" + #line 3226 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2270 "Python/bytecodes.c" + #line 2273 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3246,7 +3249,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3250 "Python/generated_cases.c.h" + #line 3253 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3256,7 +3259,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2292 "Python/bytecodes.c" + #line 2295 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3276,7 +3279,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3280 "Python/generated_cases.c.h" + #line 3283 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3286,7 +3289,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2314 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3304,7 +3307,7 @@ if (next == NULL) { goto error; } - #line 3308 "Python/generated_cases.c.h" + #line 3311 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3313,7 +3316,8 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2334 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" + DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); @@ -3328,14 +3332,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3332 "Python/generated_cases.c.h" + #line 3336 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2351 "Python/bytecodes.c" + #line 2355 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3358,16 +3362,16 @@ Py_DECREF(enter); goto error; } - #line 3362 "Python/generated_cases.c.h" + #line 3366 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2374 "Python/bytecodes.c" + #line 2378 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3371 "Python/generated_cases.c.h" + #line 3375 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3379,7 +3383,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2384 "Python/bytecodes.c" + #line 2388 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3405,16 +3409,16 @@ Py_DECREF(enter); goto error; } - #line 3409 "Python/generated_cases.c.h" + #line 3413 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2410 "Python/bytecodes.c" + #line 2414 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3418 "Python/generated_cases.c.h" + #line 3422 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3426,7 +3430,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2419 "Python/bytecodes.c" + #line 2423 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3447,7 +3451,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3451 "Python/generated_cases.c.h" + #line 3455 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3456,7 +3460,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2442 "Python/bytecodes.c" + #line 2446 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3466,7 +3470,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3470 "Python/generated_cases.c.h" + #line 3474 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3480,7 +3484,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 2454 "Python/bytecodes.c" + #line 2458 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3497,7 +3501,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3501 "Python/generated_cases.c.h" + #line 3505 "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; } @@ -3511,7 +3515,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2473 "Python/bytecodes.c" + #line 2477 "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); @@ -3521,7 +3525,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3525 "Python/generated_cases.c.h" + #line 3529 "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; } @@ -3535,7 +3539,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2485 "Python/bytecodes.c" + #line 2489 "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; @@ -3549,7 +3553,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3553 "Python/generated_cases.c.h" + #line 3557 "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; } @@ -3558,16 +3562,16 @@ } TARGET(KW_NAMES) { - #line 2501 "Python/bytecodes.c" + #line 2505 "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 3566 "Python/generated_cases.c.h" + #line 3570 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2507 "Python/bytecodes.c" + #line 2511 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3580,7 +3584,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3584 "Python/generated_cases.c.h" + #line 3588 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3590,7 +3594,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2552 "Python/bytecodes.c" + #line 2556 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3672,7 +3676,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3676 "Python/generated_cases.c.h" + #line 3680 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3684,7 +3688,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2640 "Python/bytecodes.c" + #line 2644 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3694,7 +3698,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3698 "Python/generated_cases.c.h" + #line 3702 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3703,7 +3707,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2652 "Python/bytecodes.c" + #line 2656 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3729,7 +3733,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3733 "Python/generated_cases.c.h" + #line 3737 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3737,7 +3741,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2680 "Python/bytecodes.c" + #line 2684 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3773,7 +3777,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3777 "Python/generated_cases.c.h" + #line 3781 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3781,7 +3785,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2718 "Python/bytecodes.c" + #line 2722 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3791,7 +3795,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3795 "Python/generated_cases.c.h" + #line 3799 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3804,7 +3808,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2730 "Python/bytecodes.c" + #line 2734 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3815,7 +3819,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3819 "Python/generated_cases.c.h" + #line 3823 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3829,7 +3833,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2744 "Python/bytecodes.c" + #line 2748 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3840,7 +3844,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3844 "Python/generated_cases.c.h" + #line 3848 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3854,7 +3858,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2758 "Python/bytecodes.c" + #line 2762 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3876,7 +3880,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3880 "Python/generated_cases.c.h" + #line 3884 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3890,7 +3894,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2783 "Python/bytecodes.c" + #line 2787 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3918,7 +3922,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3922 "Python/generated_cases.c.h" + #line 3926 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3932,7 +3936,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2814 "Python/bytecodes.c" + #line 2818 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3964,7 +3968,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3968 "Python/generated_cases.c.h" + #line 3972 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3978,7 +3982,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2849 "Python/bytecodes.c" + #line 2853 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4010,7 +4014,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4014 "Python/generated_cases.c.h" + #line 4018 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4024,7 +4028,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2884 "Python/bytecodes.c" + #line 2888 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4049,7 +4053,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4053 "Python/generated_cases.c.h" + #line 4057 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4062,7 +4066,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2911 "Python/bytecodes.c" + #line 2915 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4089,7 +4093,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4093 "Python/generated_cases.c.h" + #line 4097 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4101,7 +4105,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2941 "Python/bytecodes.c" + #line 2945 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4119,14 +4123,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4123 "Python/generated_cases.c.h" + #line 4127 "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 2961 "Python/bytecodes.c" + #line 2965 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4157,7 +4161,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4161 "Python/generated_cases.c.h" + #line 4165 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4170,7 +4174,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2995 "Python/bytecodes.c" + #line 2999 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4199,7 +4203,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4203 "Python/generated_cases.c.h" + #line 4207 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4212,7 +4216,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3027 "Python/bytecodes.c" + #line 3031 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4241,7 +4245,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4245 "Python/generated_cases.c.h" + #line 4249 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4254,7 +4258,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3059 "Python/bytecodes.c" + #line 3063 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4282,7 +4286,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4286 "Python/generated_cases.c.h" + #line 4290 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4292,9 +4296,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3090 "Python/bytecodes.c" + #line 3094 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4298 "Python/generated_cases.c.h" + #line 4302 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4303,7 +4307,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3094 "Python/bytecodes.c" + #line 3098 "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)); @@ -4365,14 +4369,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4369 "Python/generated_cases.c.h" + #line 4373 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3156 "Python/bytecodes.c" + #line 3160 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4376 "Python/generated_cases.c.h" + #line 4380 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4387,7 +4391,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 3166 "Python/bytecodes.c" + #line 3170 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4416,14 +4420,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4420 "Python/generated_cases.c.h" + #line 4424 "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 3197 "Python/bytecodes.c" + #line 3201 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4444,7 +4448,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4448 "Python/generated_cases.c.h" + #line 4452 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4452,15 +4456,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3220 "Python/bytecodes.c" + #line 3224 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4458 "Python/generated_cases.c.h" + #line 4462 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3222 "Python/bytecodes.c" + #line 3226 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4464 "Python/generated_cases.c.h" + #line 4468 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4471,7 +4475,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 3226 "Python/bytecodes.c" + #line 3230 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4506,7 +4510,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 4510 "Python/generated_cases.c.h" + #line 4514 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4515,10 +4519,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3263 "Python/bytecodes.c" + #line 3267 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4522 "Python/generated_cases.c.h" + #line 4526 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4530,7 +4534,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3268 "Python/bytecodes.c" + #line 3272 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4545,12 +4549,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4549 "Python/generated_cases.c.h" + #line 4553 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3283 "Python/bytecodes.c" + #line 3287 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4554 "Python/generated_cases.c.h" + #line 4558 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4560,16 +4564,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3288 "Python/bytecodes.c" + #line 3292 "Python/bytecodes.c" assert(oparg >= 2); - #line 4566 "Python/generated_cases.c.h" + #line 4570 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3292 "Python/bytecodes.c" + #line 3296 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4581,26 +4585,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4585 "Python/generated_cases.c.h" + #line 4589 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3306 "Python/bytecodes.c" + #line 3310 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4591 "Python/generated_cases.c.h" + #line 4595 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3310 "Python/bytecodes.c" + #line 3314 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4598 "Python/generated_cases.c.h" + #line 4602 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3315 "Python/bytecodes.c" + #line 3319 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4609,12 +4613,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4613 "Python/generated_cases.c.h" + #line 4617 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3326 "Python/bytecodes.c" + #line 3330 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4623,12 +4627,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4627 "Python/generated_cases.c.h" + #line 4631 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3337 "Python/bytecodes.c" + #line 3341 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4641,12 +4645,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4645 "Python/generated_cases.c.h" + #line 4649 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3352 "Python/bytecodes.c" + #line 3356 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4659,30 +4663,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4663 "Python/generated_cases.c.h" + #line 4667 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3367 "Python/bytecodes.c" + #line 3371 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4674 "Python/generated_cases.c.h" + #line 4678 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3375 "Python/bytecodes.c" + #line 3379 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4681 "Python/generated_cases.c.h" + #line 4685 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3380 "Python/bytecodes.c" + #line 3384 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4688 "Python/generated_cases.c.h" + #line 4692 "Python/generated_cases.c.h" } diff --git a/Python/specialize.c b/Python/specialize.c index 5071d8ef9a49..f1684913b1bc 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -783,6 +783,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) if (version == 0) { goto fail; } + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); + goto fail; + } write_u32(lm_cache->keys_version, version); assert(type->tp_version_tag != 0); write_u32(lm_cache->type_version, type->tp_version_tag); @@ -845,6 +849,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) if (version == 0) { goto fail; } + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); + goto fail; + } write_u32(lm_cache->keys_version, version); /* borrowed */ write_obj(lm_cache->descr, descr); @@ -1371,6 +1379,10 @@ _Py_Specialize_BinarySubscr( SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OTHER); + goto fail; + } PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; // This pointer is invalidated by PyType_Modified (see the comment on // struct _specialization_cache): @@ -2192,11 +2204,16 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) 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 ); + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(FOR_ITER, SPEC_FAIL_OTHER); + goto failure; + } instr->op.code = FOR_ITER_GEN; goto success; } SPECIALIZATION_FAIL(FOR_ITER, _PySpecialization_ClassifyIterator(iter)); +failure: STAT_INC(FOR_ITER, failure); instr->op.code = FOR_ITER; cache->counter = adaptive_counter_backoff(cache->counter); @@ -2214,11 +2231,16 @@ _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr) _PySendCache *cache = (_PySendCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(receiver); if (tp == &PyGen_Type || tp == &PyCoro_Type) { + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(SEND, SPEC_FAIL_OTHER); + goto failure; + } instr->op.code = SEND_GEN; goto success; } SPECIALIZATION_FAIL(SEND, _PySpecialization_ClassifyIterator(receiver)); +failure: STAT_INC(SEND, failure); instr->op.code = SEND; cache->counter = adaptive_counter_backoff(cache->counter); From webhook-mailer at python.org Fri May 12 18:29:08 2023 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 12 May 2023 22:29:08 -0000 Subject: [Python-checkins] [3.11] Fix refleak in super_descr_get (GH-104440) Message-ID: <mailman.340.1683930549.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4ade7c33696b6a2a2e07295366ae0c29c31bb050 commit: 4ade7c33696b6a2a2e07295366ae0c29c31bb050 branch: 3.11 author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-12T22:29:02Z summary: [3.11] Fix refleak in super_descr_get (GH-104440) (cherry picked from commit a781484c8e9834538e5ee7b9e2e6bec7b679e033) files: M Objects/typeobject.c diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 90c6425ffdfe..782a7e972288 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8969,8 +8969,10 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type) return NULL; newobj = (superobject *)PySuper_Type.tp_new(&PySuper_Type, NULL, NULL); - if (newobj == NULL) + if (newobj == NULL) { + Py_DECREF(obj_type); return NULL; + } Py_INCREF(su->type); Py_INCREF(obj); newobj->type = su->type; From webhook-mailer at python.org Fri May 12 19:03:58 2023 From: webhook-mailer at python.org (brandtbucher) Date: Fri, 12 May 2023 23:03:58 -0000 Subject: [Python-checkins] [3.11] GH-104405: Add missing PEP 523 checks (GH-104441) Message-ID: <mailman.341.1683932639.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fbb6def08a7ce7d21653e15ccbc4017b4eb2e795 commit: fbb6def08a7ce7d21653e15ccbc4017b4eb2e795 branch: 3.11 author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-12T23:03:47Z summary: [3.11] GH-104405: Add missing PEP 523 checks (GH-104441) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst M Lib/test/test_capi/test_misc.py M Python/ceval.c M Python/specialize.c diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 67150a8d24cb..3e36fbde8c66 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1378,28 +1378,39 @@ def dummy(): class Test_Pep523API(unittest.TestCase): - def do_test(self, func): - calls = [] + def do_test(self, func, names): + actual_calls = [] start = SUFFICIENT_TO_DEOPT_AND_SPECIALIZE count = start + SUFFICIENT_TO_DEOPT_AND_SPECIALIZE - for i in range(count): - if i == start: - _testinternalcapi.set_eval_frame_record(calls) - func() - _testinternalcapi.set_eval_frame_default() - self.assertEqual(len(calls), SUFFICIENT_TO_DEOPT_AND_SPECIALIZE) - for name in calls: - self.assertEqual(name, func.__name__) - - def test_pep523_with_specialization_simple(self): - def func1(): - pass - self.do_test(func1) + try: + for i in range(count): + if i == start: + _testinternalcapi.set_eval_frame_record(actual_calls) + func() + finally: + _testinternalcapi.set_eval_frame_default() + expected_calls = names * SUFFICIENT_TO_DEOPT_AND_SPECIALIZE + self.assertEqual(len(expected_calls), len(actual_calls)) + for expected, actual in zip(expected_calls, actual_calls, strict=True): + self.assertEqual(expected, actual) + + def test_inlined_binary_subscr(self): + class C: + def __getitem__(self, other): + return None + def func(): + C()[42] + names = ["func", "__getitem__"] + self.do_test(func, names) - def test_pep523_with_specialization_with_default(self): - def func2(x=None): + def test_inlined_call(self): + def inner(x=42): pass - self.do_test(func2) + def func(): + inner() + inner(42) + names = ["func", "inner", "inner"] + self.do_test(func, names) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst new file mode 100644 index 000000000000..06ec5d7b0f0c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst @@ -0,0 +1,2 @@ +Fix an issue where some :term:`bytecode` instructions could ignore +:pep:`523` when "inlining" calls. diff --git a/Python/ceval.c b/Python/ceval.c index 72f9c8375d07..47df35319709 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2233,6 +2233,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(BINARY_SUBSCR_GETITEM) { + DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyObject *sub = TOP(); PyObject *container = SECOND(); _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; diff --git a/Python/specialize.c b/Python/specialize.c index 08ce2f5caa6b..9d182fd31b08 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1238,6 +1238,10 @@ _Py_Specialize_BinarySubscr( SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OTHER); + goto fail; + } cache->func_version = version; ((PyHeapTypeObject *)container_type)->_spec_cache.getitem = descriptor; _Py_SET_OPCODE(*instr, BINARY_SUBSCR_GETITEM); From webhook-mailer at python.org Fri May 12 20:42:25 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 13 May 2023 00:42:25 -0000 Subject: [Python-checkins] gh-104404: fix crasher with nested comprehensions plus lambdas (#104442) Message-ID: <mailman.342.1683938546.13550.python-checkins@python.org> https://github.com/python/cpython/commit/563c7dcba0ea1070698b77129628e9e1c86d34e2 commit: 563c7dcba0ea1070698b77129628e9e1c86d34e2 branch: main author: Carl Meyer <carl at oddbird.net> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-12T17:42:04-07:00 summary: gh-104404: fix crasher with nested comprehensions plus lambdas (#104442) files: M Lib/test/test_listcomps.py M Python/symtable.c diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index b2a3b7ea3e49..23e1b8c1ce31 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -338,6 +338,14 @@ def test_nested_3(self): outputs = {"y": [1, 3, 5]} self._check_in_scopes(code, outputs) + def test_nested_4(self): + code = """ + items = [([lambda: x for x in range(2)], lambda: x) for x in range(3)] + out = [([fn() for fn in fns], fn()) for fns, fn in items] + """ + outputs = {"out": [([1, 1], 2), ([1, 1], 2), ([1, 1], 2)]} + self._check_in_scopes(code, outputs) + def test_nameerror(self): code = """ [x for x in [1]] diff --git a/Python/symtable.c b/Python/symtable.c index 9361674bf165..2c29f6084135 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -575,7 +575,8 @@ is_free_in_any_child(PySTEntryObject *entry, PyObject *key) static int inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, - PyObject *scopes, PyObject *comp_free) + PyObject *scopes, PyObject *comp_free, + PyObject *promote_to_cell) { PyObject *k, *v; Py_ssize_t pos = 0; @@ -611,7 +612,9 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, // cell vars in comprehension that are locals in outer scope // must be promoted to cell so u_cellvars isn't wrong if (scope == CELL && ste->ste_type == FunctionBlock) { - SET_SCOPE(scopes, k, scope); + if (PySet_Add(promote_to_cell, k) < 0) { + return 0; + } } // free vars in comprehension that are locals in outer scope can @@ -638,7 +641,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, */ static int -analyze_cells(PyObject *scopes, PyObject *free) +analyze_cells(PyObject *scopes, PyObject *free, PyObject *promote_to_cell) { PyObject *name, *v, *v_cell; int success = 0; @@ -653,7 +656,7 @@ analyze_cells(PyObject *scopes, PyObject *free) scope = PyLong_AS_LONG(v); if (scope != LOCAL) continue; - if (!PySet_Contains(free, name)) + if (!PySet_Contains(free, name) && !PySet_Contains(promote_to_cell, name)) continue; /* Replace LOCAL with CELL for this name, and remove from free. It is safe to replace the value of name @@ -803,7 +806,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, PyObject *global) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; - PyObject *newglobal = NULL, *newfree = NULL; + PyObject *newglobal = NULL, *newfree = NULL, *promote_to_cell = NULL; PyObject *temp; int success = 0; Py_ssize_t i, pos = 0; @@ -835,6 +838,9 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, newbound = PySet_New(NULL); if (!newbound) goto error; + promote_to_cell = PySet_New(NULL); + if (!promote_to_cell) + goto error; /* Class namespace has no effect on names visible in nested functions, so populate the global and bound @@ -915,7 +921,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, goto error; } if (inline_comp) { - if (!inline_comprehension(ste, entry, scopes, child_free)) { + if (!inline_comprehension(ste, entry, scopes, child_free, promote_to_cell)) { Py_DECREF(child_free); goto error; } @@ -946,7 +952,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, } /* Check if any local variables must be converted to cell variables */ - if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree)) + if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree, promote_to_cell)) goto error; else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree)) goto error; @@ -966,6 +972,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, Py_XDECREF(newbound); Py_XDECREF(newglobal); Py_XDECREF(newfree); + Py_XDECREF(promote_to_cell); if (!success) assert(PyErr_Occurred()); return success; From webhook-mailer at python.org Sat May 13 00:35:52 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 13 May 2023 04:35:52 -0000 Subject: [Python-checkins] gh-99836: IDLE - update news.txt for 3.12 (#104444) Message-ID: <mailman.343.1683952553.13550.python-checkins@python.org> https://github.com/python/cpython/commit/57139a6b5f0cfa04156d5c650026012a7c5a7aad commit: 57139a6b5f0cfa04156d5c650026012a7c5a7aad branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-13T04:35:45Z summary: gh-99836: IDLE - update news.txt for 3.12 (#104444) * gh-99836: IDLE 3.12 news.txt * gh-99836: IDLE - update news.txt for 3.12 files: M Lib/idlelib/NEWS.txt diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index e64e96f75e6c..e97e3ca01ef3 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,9 +1,20 @@ +What's New in IDLE 3.12.0 +(since 3.11.0) +Released on 2023-10-02 +========================= + + +gh-88496 Fix IDLE test hang on macOS. + +gh-103314 Support sys.last_exc after exceptions in Shell. +Patch by Irit Katriel. + + What's New in IDLE 3.11.0 (since 3.10.0) -Released on 2022-10-03 +Released on 2022-10-24 ========================= - gh-97527: Fix a bug in the previous bugfix that caused IDLE to not start when run with 3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed without the Lib/test package. 3.11.0 was never From webhook-mailer at python.org Sat May 13 00:47:29 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 13 May 2023 04:47:29 -0000 Subject: [Python-checkins] [3.11] gh-99836: IDLE - update news.txt for 3.11+ (#104445) Message-ID: <mailman.344.1683953250.13550.python-checkins@python.org> https://github.com/python/cpython/commit/328b5dd8294f29f29c7cd84fbe5496f40ab050d0 commit: 328b5dd8294f29f29c7cd84fbe5496f40ab050d0 branch: 3.11 author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-13T04:47:21Z summary: [3.11] gh-99836: IDLE - update news.txt for 3.11+ (#104445) * gh-99836: IDLE 3.11 News.txt * gh-99836: IDLE - update news.txt for 3.11+ files: M Lib/idlelib/NEWS.txt diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index e64e96f75e6c..987c9924ea92 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -1,9 +1,20 @@ +What's New in IDLE 3.11.z +(since 3.11.0) +Released after 2022-10-24 +========================= + + +gh-88496 Fix IDLE test hang on macOS. + +gh-103314 Support sys.last_exc after exceptions in Shell. +Patch by Irit Katriel. + + What's New in IDLE 3.11.0 (since 3.10.0) -Released on 2022-10-03 +Released on 2022-10-24 ========================= - gh-97527: Fix a bug in the previous bugfix that caused IDLE to not start when run with 3.10.8, 3.12.0a1, and at least Microsoft Python 3.10.2288.0 installed without the Lib/test package. 3.11.0 was never From webhook-mailer at python.org Sat May 13 03:12:21 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 13 May 2023 07:12:21 -0000 Subject: [Python-checkins] Add a mention of PYTHONBREAKPOINT to breakpoint() docs (#104430) Message-ID: <mailman.345.1683961942.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1be80ed107deb15b926f2794b8e6a7a527b8b84c commit: 1be80ed107deb15b926f2794b8e6a7a527b8b84c branch: main author: Ned Batchelder <ned at nedbatchelder.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-13T00:12:03-07:00 summary: Add a mention of PYTHONBREAKPOINT to breakpoint() docs (#104430) files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 48a832db60e9..3d2bb8efc95d 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -168,6 +168,13 @@ are always available. They are listed here in alphabetical order. If :func:`sys.breakpointhook` is not accessible, this function will raise :exc:`RuntimeError`. + By default, the behavior of :func:`breakpoint` can be changed with + the :envvar:`PYTHONBREAKPOINT` environment variable. + See :func:`sys.breakpointhook` for usage details. + + Note that this is not guaranteed if :func:`sys.breakpointhook` + has been replaced. + .. audit-event:: builtins.breakpoint breakpointhook breakpoint .. versionadded:: 3.7 From webhook-mailer at python.org Sat May 13 03:16:35 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 13 May 2023 07:16:35 -0000 Subject: [Python-checkins] [3.11] Add a mention of PYTHONBREAKPOINT to breakpoint() docs (GH-104430) (#104447) Message-ID: <mailman.346.1683962196.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e794d469e3358c10340ff9805f93e9d6c76dc5c1 commit: e794d469e3358c10340ff9805f93e9d6c76dc5c1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-13T07:16:28Z summary: [3.11] Add a mention of PYTHONBREAKPOINT to breakpoint() docs (GH-104430) (#104447) Add a mention of PYTHONBREAKPOINT to breakpoint() docs (GH-104430) (cherry picked from commit 1be80ed107deb15b926f2794b8e6a7a527b8b84c) Co-authored-by: Ned Batchelder <ned at nedbatchelder.com> files: M Doc/library/functions.rst diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index f3dc02f03db0..d1ce1520fdbb 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -168,6 +168,13 @@ are always available. They are listed here in alphabetical order. If :func:`sys.breakpointhook` is not accessible, this function will raise :exc:`RuntimeError`. + By default, the behavior of :func:`breakpoint` can be changed with + the :envvar:`PYTHONBREAKPOINT` environment variable. + See :func:`sys.breakpointhook` for usage details. + + Note that this is not guaranteed if :func:`sys.breakpointhook` + has been replaced. + .. audit-event:: builtins.breakpoint breakpointhook breakpoint .. versionadded:: 3.7 From webhook-mailer at python.org Sat May 13 04:55:46 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 13 May 2023 08:55:46 -0000 Subject: [Python-checkins] gh-91896: Revert some very noisy DeprecationWarnings for `ByteString` (#104424) Message-ID: <mailman.347.1683968146.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c527eb1c2a473df01c19195b378f780e9180fd1c commit: c527eb1c2a473df01c19195b378f780e9180fd1c branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-13T09:55:35+01:00 summary: gh-91896: Revert some very noisy DeprecationWarnings for `ByteString` (#104424) files: M Doc/library/collections.abc.rst M Doc/whatsnew/3.12.rst M Lib/collections/abc.py M Lib/test/libregrtest/refleak.py M Lib/test/test_collections.py M Lib/test/test_typing.py M Lib/typing.py diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst index 158f48516346..43a3286ba832 100644 --- a/Doc/library/collections.abc.rst +++ b/Doc/library/collections.abc.rst @@ -14,10 +14,7 @@ .. testsetup:: * - import warnings - # Ignore warning when ByteString is imported - with warnings.catch_warnings(action='ignore', category=DeprecationWarning): - from collections.abc import * + from collections.abc import * import itertools __name__ = '<doctest>' diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 546c7147bb3b..dc1178811e75 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -831,8 +831,8 @@ Pending Removal in Python 3.14 For use in typing, prefer a union, like ``bytes | bytearray``, or :class:`collections.abc.Buffer`. (Contributed by Shantanu Jain in :gh:`91896`.) -* :class:`typing.ByteString`, deprecated since Python 3.9, now causes an - :exc:`DeprecationWarning` to be emitted when it is used or accessed. +* :class:`typing.ByteString`, deprecated since Python 3.9, now causes a + :exc:`DeprecationWarning` to be emitted when it is used. * Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases using the C API. diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py index 60b1eb60fa6a..86ca8b8a8414 100644 --- a/Lib/collections/abc.py +++ b/Lib/collections/abc.py @@ -1,12 +1,3 @@ from _collections_abc import * from _collections_abc import __all__ from _collections_abc import _CallableGenericAlias - -_deprecated_ByteString = globals().pop("ByteString") - -def __getattr__(attr): - if attr == "ByteString": - import warnings - warnings._deprecated("collections.abc.ByteString", remove=(3, 14)) - return _deprecated_ByteString - raise AttributeError(f"module 'collections.abc' has no attribute {attr!r}") diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py index 776a9e9b587d..cd11d385591f 100644 --- a/Lib/test/libregrtest/refleak.py +++ b/Lib/test/libregrtest/refleak.py @@ -48,13 +48,11 @@ def dash_R(ns, test_name, test_func): else: zdc = zipimport._zip_directory_cache.copy() abcs = {} - # catch and ignore collections.abc.ByteString deprecation - with warnings.catch_warnings(action='ignore', category=DeprecationWarning): - for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: - if not isabstract(abc): - continue - for obj in abc.__subclasses__() + [abc]: - abcs[obj] = _get_dump(obj)[0] + for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]: + if not isabstract(abc): + continue + for obj in abc.__subclasses__() + [abc]: + abcs[obj] = _get_dump(obj)[0] # bpo-31217: Integer pool to get a single integer object for the same # value. The pool is used to prevent false alarm when checking for memory @@ -176,8 +174,7 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs): # Clear ABC registries, restoring previously saved ABC registries. # ignore deprecation warning for collections.abc.ByteString - with warnings.catch_warnings(action='ignore', category=DeprecationWarning): - abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] + abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__] abs_classes = filter(isabstract, abs_classes) for abc in abs_classes: for obj in abc.__subclasses__() + [abc]: diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index f0736b8081fe..bb8b352518ef 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -11,7 +11,6 @@ import string import sys from test import support -from test.support.import_helper import import_fresh_module import types import unittest @@ -26,7 +25,7 @@ from collections.abc import Set, MutableSet from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView from collections.abc import Sequence, MutableSequence -from collections.abc import Buffer +from collections.abc import ByteString, Buffer class TestUserObjects(unittest.TestCase): @@ -1940,8 +1939,6 @@ def assert_index_same(seq1, seq2, index_args): nativeseq, seqseq, (letter, start, stop)) def test_ByteString(self): - with self.assertWarns(DeprecationWarning): - from collections.abc import ByteString for sample in [bytes, bytearray]: with self.assertWarns(DeprecationWarning): self.assertIsInstance(sample(), ByteString) @@ -1963,11 +1960,6 @@ class X(ByteString): pass # No metaclass conflict class Z(ByteString, Awaitable): pass - def test_ByteString_attribute_access(self): - collections_abc = import_fresh_module("collections.abc") - with self.assertWarns(DeprecationWarning): - collections_abc.ByteString - def test_Buffer(self): for sample in [bytes, bytearray, memoryview]: self.assertIsInstance(sample(b"x"), Buffer) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3422dc1ed3f5..e1c6a8a7f376 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -8,7 +8,6 @@ import re import sys import warnings -from test.support.import_helper import import_fresh_module from unittest import TestCase, main, skipUnless, skip from unittest.mock import patch from copy import copy, deepcopy @@ -3909,14 +3908,7 @@ class MyChain(typing.ChainMap[str, T]): ... self.assertEqual(MyChain[int]().__orig_class__, MyChain[int]) def test_all_repr_eq_any(self): - typing = import_fresh_module("typing") - with warnings.catch_warnings(record=True) as wlog: - warnings.filterwarnings('always', '', DeprecationWarning) - objs = [getattr(typing, el) for el in typing.__all__] - self.assertEqual( - [str(w.message) for w in wlog], - ["'typing.ByteString' is deprecated and slated for removal in Python 3.14"] - ) + objs = (getattr(typing, el) for el in typing.__all__) for obj in objs: self.assertNotEqual(repr(obj), '') self.assertEqual(obj, obj) @@ -6005,15 +5997,13 @@ def test_mutablesequence(self): def test_bytestring(self): with self.assertWarns(DeprecationWarning): - from typing import ByteString + self.assertIsInstance(b'', typing.ByteString) with self.assertWarns(DeprecationWarning): - self.assertIsInstance(b'', ByteString) + self.assertIsInstance(bytearray(b''), typing.ByteString) with self.assertWarns(DeprecationWarning): - self.assertIsInstance(bytearray(b''), ByteString) + class Foo(typing.ByteString): ... with self.assertWarns(DeprecationWarning): - class Foo(ByteString): ... - with self.assertWarns(DeprecationWarning): - class Bar(ByteString, typing.Awaitable): ... + class Bar(typing.ByteString, typing.Awaitable): ... def test_list(self): self.assertIsSubclass(list, typing.List) @@ -8309,10 +8299,6 @@ def test_no_isinstance(self): class SpecialAttrsTests(BaseTestCase): def test_special_attrs(self): - with warnings.catch_warnings( - action='ignore', category=DeprecationWarning - ): - typing_ByteString = typing.ByteString cls_to_check = { # ABC classes typing.AbstractSet: 'AbstractSet', @@ -8321,7 +8307,7 @@ def test_special_attrs(self): typing.AsyncIterable: 'AsyncIterable', typing.AsyncIterator: 'AsyncIterator', typing.Awaitable: 'Awaitable', - typing_ByteString: 'ByteString', + typing.ByteString: 'ByteString', typing.Callable: 'Callable', typing.ChainMap: 'ChainMap', typing.Collection: 'Collection', @@ -8646,8 +8632,6 @@ def test_all_exported_names(self): getattr(v, '__module__', None) == typing.__name__ ) } - # Deprecated; added dynamically via module __getattr__ - computed_all.add("ByteString") self.assertSetEqual(computed_all, actual_all) diff --git a/Lib/typing.py b/Lib/typing.py index 513d4d96dd6e..61aed0980ac2 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2772,6 +2772,9 @@ class Other(Leaf): # Error reported by type checker MutableMapping = _alias(collections.abc.MutableMapping, 2) Sequence = _alias(collections.abc.Sequence, 1) MutableSequence = _alias(collections.abc.MutableSequence, 1) +ByteString = _DeprecatedGenericAlias( + collections.abc.ByteString, 0, removal_version=(3, 14) # Not generic. +) # Tuple accepts variable number of parameters. Tuple = _TupleType(tuple, -1, inst=False, name='Tuple') Tuple.__doc__ = \ @@ -3571,27 +3574,3 @@ def method(self) -> None: # read-only property, TypeError if it's a builtin class. pass return method - - -def __getattr__(attr): - if attr == "ByteString": - import warnings - warnings._deprecated("typing.ByteString", remove=(3, 14)) - with warnings.catch_warnings( - action="ignore", category=DeprecationWarning - ): - # Not generic - ByteString = globals()["ByteString"] = _DeprecatedGenericAlias( - collections.abc.ByteString, 0, removal_version=(3, 14) - ) - return ByteString - raise AttributeError(f"module 'typing' has no attribute {attr!r}") - - -def _remove_cached_ByteString_from_globals(): - try: - del globals()["ByteString"] - except KeyError: - pass - -_cleanups.append(_remove_cached_ByteString_from_globals) From webhook-mailer at python.org Sat May 13 11:41:46 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 13 May 2023 15:41:46 -0000 Subject: [Python-checkins] gh-75710: IDLE - add docstrings and comments to editor module (#104446) Message-ID: <mailman.348.1683992507.13550.python-checkins@python.org> https://github.com/python/cpython/commit/46f1c78eebe08e96ed29d364b1804dd37364831d commit: 46f1c78eebe08e96ed29d364b1804dd37364831d branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-13T11:41:39-04:00 summary: gh-75710: IDLE - add docstrings and comments to editor module (#104446) Commit extracted from PR #3669. Will edit more later. Co-authored-by: Cheryl Sabella <cheryl.sabella at gmail.com> files: M Lib/idlelib/editor.py diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 505815502600..21402ad71391 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -446,6 +446,26 @@ def set_line_and_column(self, event=None): self.status_bar.set_label('column', 'Col: %s' % column) self.status_bar.set_label('line', 'Ln: %s' % line) + + """ Menu definitions and functions. + * self.menubar - the always visible horizontal menu bar. + * mainmenu.menudefs - a list of tuples, one for each menubar item. + Each tuple pairs a lower-case name and list of dropdown items. + Each item is a name, virtual event pair or None for separator. + * mainmenu.default_keydefs - maps events to keys. + * text.keydefs - same. + * cls.menu_specs - menubar name, titlecase display form pairs + with Alt-hotkey indicator. A subset of menudefs items. + * self.menudict - map menu name to dropdown menu. + * self.recent_files_menu - 2nd level cascade in the file cascade. + * self.wmenu_end - set in __init__ (purpose unclear). + + createmenubar, postwindowsmenu, update_menu_label, update_menu_state, + ApplyKeybings (2nd part), reset_help_menu_entries, + _extra_help_callback, update_recent_files_list, + apply_bindings, fill_menus, (other functions?) + """ + menu_specs = [ ("file", "_File"), ("edit", "_Edit"), @@ -456,8 +476,22 @@ def set_line_and_column(self, event=None): ("help", "_Help"), ] - def createmenubar(self): + """Populate the menu bar widget for the editor window. + + Each option on the menubar is itself a cascade-type Menu widget + with the menubar as the parent. The names, labels, and menu + shortcuts for the menubar items are stored in menu_specs. Each + submenu is subsequently populated in fill_menus(), except for + 'Recent Files' which is added to the File menu here. + + Instance variables: + menubar: Menu widget containing first level menu items. + menudict: Dictionary of {menuname: Menu instance} items. The keys + represent the valid menu items for this window and may be a + subset of all the menudefs available. + recent_files_menu: Menu widget contained within the 'file' menudict. + """ mbar = self.menubar self.menudict = menudict = {} for name, label in self.menu_specs: @@ -480,7 +514,10 @@ def createmenubar(self): self.reset_help_menu_entries() def postwindowsmenu(self): - # Only called when Window menu exists + """Callback to register window. + + Only called when Window menu exists. + """ menu = self.menudict['window'] end = menu.index("end") if end is None: @@ -859,8 +896,11 @@ def ResetFont(self): self.set_width() def RemoveKeybindings(self): - "Remove the keybindings before they are changed." - # Called from configdialog.py + """Remove the virtual, configurable keybindings. + + Leaves the default Tk Text keybindings. + """ + # Called from configdialog.deactivate_current_config. self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() for event, keylist in keydefs.items(): self.text.event_delete(event, *keylist) @@ -871,15 +911,19 @@ def RemoveKeybindings(self): self.text.event_delete(event, *keylist) def ApplyKeybindings(self): - "Update the keybindings after they are changed" - # Called from configdialog.py + """Apply the virtual, configurable keybindings. + + Alse update hotkeys to current keyset. + """ + # Called from configdialog.activate_config_changes. self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() self.apply_bindings() for extensionName in self.get_standard_extension_names(): xkeydefs = idleConf.GetExtensionBindings(extensionName) if xkeydefs: self.apply_bindings(xkeydefs) - #update menu accelerators + + # Update menu accelerators. menuEventDict = {} for menu in self.mainmenu.menudefs: menuEventDict[menu[0]] = {} @@ -914,25 +958,25 @@ def set_notabs_indentwidth(self): type='int') def reset_help_menu_entries(self): - "Update the additional help entries on the Help menu" + """Update the additional help entries on the Help menu.""" help_list = idleConf.GetAllExtraHelpSourcesList() helpmenu = self.menudict['help'] - # first delete the extra help entries, if any + # First delete the extra help entries, if any. helpmenu_length = helpmenu.index(END) if helpmenu_length > self.base_helpmenu_length: helpmenu.delete((self.base_helpmenu_length + 1), helpmenu_length) - # then rebuild them + # Then rebuild them. if help_list: helpmenu.add_separator() for entry in help_list: - cmd = self.__extra_help_callback(entry[1]) + cmd = self._extra_help_callback(entry[1]) helpmenu.add_command(label=entry[0], command=cmd) - # and update the menu dictionary + # And update the menu dictionary. self.menudict['help'] = helpmenu - def __extra_help_callback(self, helpfile): - "Create a callback with the helpfile value frozen at definition time" - def display_extra_help(helpfile=helpfile): + def _extra_help_callback(self, resource): + """Return a callback that loads resource (file or web page).""" + def display_extra_help(helpfile=resource): if not helpfile.startswith(('www', 'http')): helpfile = os.path.normpath(helpfile) if sys.platform[:3] == 'win': @@ -1158,6 +1202,7 @@ def load_extension(self, name): self.text.bind(vevent, getattr(ins, methodname)) def apply_bindings(self, keydefs=None): + """Add events with keys to self.text.""" if keydefs is None: keydefs = self.mainmenu.default_keydefs text = self.text @@ -1167,9 +1212,10 @@ def apply_bindings(self, keydefs=None): text.event_add(event, *keylist) def fill_menus(self, menudefs=None, keydefs=None): - """Add appropriate entries to the menus and submenus + """Fill in dropdown menus used by this window. - Menus that are absent or None in self.menudict are ignored. + Items whose name begins with '!' become checkbuttons. + Other names indicate commands. None becomes a separator. """ if menudefs is None: menudefs = self.mainmenu.menudefs @@ -1182,7 +1228,7 @@ def fill_menus(self, menudefs=None, keydefs=None): if not menu: continue for entry in entrylist: - if not entry: + if entry is None: menu.add_separator() else: label, eventname = entry @@ -1218,11 +1264,13 @@ def setvar(self, name, value, vartype=None): else: raise NameError(name) - def get_var_obj(self, name, vartype=None): - var = self.tkinter_vars.get(name) + def get_var_obj(self, eventname, vartype=None): + """Return a tkinter variable instance for the event. + """ + var = self.tkinter_vars.get(eventname) if not var and vartype: - # create a Tkinter variable object with self.text as master: - self.tkinter_vars[name] = var = vartype(self.text) + # Create a Tkinter variable object. + self.tkinter_vars[eventname] = var = vartype(self.text) return var # Tk implementations of "virtual text methods" -- each platform @@ -1613,8 +1661,16 @@ def run(self): ### end autoindent code ### def prepstr(s): - # Helper to extract the underscore from a string, e.g. - # prepstr("Co_py") returns (2, "Copy"). + """Extract the underscore from a string. + + For example, prepstr("Co_py") returns (2, "Copy"). + + Args: + s: String with underscore. + + Returns: + Tuple of (position of underscore, string without underscore). + """ i = s.find('_') if i >= 0: s = s[:i] + s[i+1:] @@ -1628,6 +1684,18 @@ def prepstr(s): } def get_accelerator(keydefs, eventname): + """Return a formatted string for the keybinding of an event. + + Convert the first keybinding for a given event to a form that + can be displayed as an accelerator on the menu. + + Args: + keydefs: Dictionary of valid events to keybindings. + eventname: Event to retrieve keybinding for. + + Returns: + Formatted string of the keybinding. + """ keylist = keydefs.get(eventname) # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5 # if not keylist: @@ -1637,14 +1705,23 @@ def get_accelerator(keydefs, eventname): "<<change-indentwidth>>"}): return "" s = keylist[0] + # Convert strings of the form -singlelowercase to -singleuppercase. s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s) + # Convert certain keynames to their symbol. s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) + # Remove Key- from string. s = re.sub("Key-", "", s) - s = re.sub("Cancel","Ctrl-Break",s) # dscherer at cmu.edu + # Convert Cancel to Ctrl-Break. + s = re.sub("Cancel", "Ctrl-Break", s) # dscherer at cmu.edu + # Convert Control to Ctrl-. s = re.sub("Control-", "Ctrl-", s) + # Change - to +. s = re.sub("-", "+", s) + # Change >< to space. s = re.sub("><", " ", s) + # Remove <. s = re.sub("<", "", s) + # Remove >. s = re.sub(">", "", s) return s From webhook-mailer at python.org Sat May 13 12:04:44 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 13 May 2023 16:04:44 -0000 Subject: [Python-checkins] [3.11] gh-75710: IDLE - add docstrings and comments to editor module (GH-104446) (#104450) Message-ID: <mailman.349.1683993886.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b87ccc38fe3ab4eca6e026b76f868db4d53c963f commit: b87ccc38fe3ab4eca6e026b76f868db4d53c963f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-13T16:04:37Z summary: [3.11] gh-75710: IDLE - add docstrings and comments to editor module (GH-104446) (#104450) gh-75710: IDLE - add docstrings and comments to editor module (GH-104446) Commit extracted from PR GH-3669. Will edit more later. (cherry picked from commit 46f1c78eebe08e96ed29d364b1804dd37364831d) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> Co-authored-by: Cheryl Sabella <cheryl.sabella at gmail.com> files: M Lib/idlelib/editor.py diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 505815502600..21402ad71391 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -446,6 +446,26 @@ def set_line_and_column(self, event=None): self.status_bar.set_label('column', 'Col: %s' % column) self.status_bar.set_label('line', 'Ln: %s' % line) + + """ Menu definitions and functions. + * self.menubar - the always visible horizontal menu bar. + * mainmenu.menudefs - a list of tuples, one for each menubar item. + Each tuple pairs a lower-case name and list of dropdown items. + Each item is a name, virtual event pair or None for separator. + * mainmenu.default_keydefs - maps events to keys. + * text.keydefs - same. + * cls.menu_specs - menubar name, titlecase display form pairs + with Alt-hotkey indicator. A subset of menudefs items. + * self.menudict - map menu name to dropdown menu. + * self.recent_files_menu - 2nd level cascade in the file cascade. + * self.wmenu_end - set in __init__ (purpose unclear). + + createmenubar, postwindowsmenu, update_menu_label, update_menu_state, + ApplyKeybings (2nd part), reset_help_menu_entries, + _extra_help_callback, update_recent_files_list, + apply_bindings, fill_menus, (other functions?) + """ + menu_specs = [ ("file", "_File"), ("edit", "_Edit"), @@ -456,8 +476,22 @@ def set_line_and_column(self, event=None): ("help", "_Help"), ] - def createmenubar(self): + """Populate the menu bar widget for the editor window. + + Each option on the menubar is itself a cascade-type Menu widget + with the menubar as the parent. The names, labels, and menu + shortcuts for the menubar items are stored in menu_specs. Each + submenu is subsequently populated in fill_menus(), except for + 'Recent Files' which is added to the File menu here. + + Instance variables: + menubar: Menu widget containing first level menu items. + menudict: Dictionary of {menuname: Menu instance} items. The keys + represent the valid menu items for this window and may be a + subset of all the menudefs available. + recent_files_menu: Menu widget contained within the 'file' menudict. + """ mbar = self.menubar self.menudict = menudict = {} for name, label in self.menu_specs: @@ -480,7 +514,10 @@ def createmenubar(self): self.reset_help_menu_entries() def postwindowsmenu(self): - # Only called when Window menu exists + """Callback to register window. + + Only called when Window menu exists. + """ menu = self.menudict['window'] end = menu.index("end") if end is None: @@ -859,8 +896,11 @@ def ResetFont(self): self.set_width() def RemoveKeybindings(self): - "Remove the keybindings before they are changed." - # Called from configdialog.py + """Remove the virtual, configurable keybindings. + + Leaves the default Tk Text keybindings. + """ + # Called from configdialog.deactivate_current_config. self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() for event, keylist in keydefs.items(): self.text.event_delete(event, *keylist) @@ -871,15 +911,19 @@ def RemoveKeybindings(self): self.text.event_delete(event, *keylist) def ApplyKeybindings(self): - "Update the keybindings after they are changed" - # Called from configdialog.py + """Apply the virtual, configurable keybindings. + + Alse update hotkeys to current keyset. + """ + # Called from configdialog.activate_config_changes. self.mainmenu.default_keydefs = keydefs = idleConf.GetCurrentKeySet() self.apply_bindings() for extensionName in self.get_standard_extension_names(): xkeydefs = idleConf.GetExtensionBindings(extensionName) if xkeydefs: self.apply_bindings(xkeydefs) - #update menu accelerators + + # Update menu accelerators. menuEventDict = {} for menu in self.mainmenu.menudefs: menuEventDict[menu[0]] = {} @@ -914,25 +958,25 @@ def set_notabs_indentwidth(self): type='int') def reset_help_menu_entries(self): - "Update the additional help entries on the Help menu" + """Update the additional help entries on the Help menu.""" help_list = idleConf.GetAllExtraHelpSourcesList() helpmenu = self.menudict['help'] - # first delete the extra help entries, if any + # First delete the extra help entries, if any. helpmenu_length = helpmenu.index(END) if helpmenu_length > self.base_helpmenu_length: helpmenu.delete((self.base_helpmenu_length + 1), helpmenu_length) - # then rebuild them + # Then rebuild them. if help_list: helpmenu.add_separator() for entry in help_list: - cmd = self.__extra_help_callback(entry[1]) + cmd = self._extra_help_callback(entry[1]) helpmenu.add_command(label=entry[0], command=cmd) - # and update the menu dictionary + # And update the menu dictionary. self.menudict['help'] = helpmenu - def __extra_help_callback(self, helpfile): - "Create a callback with the helpfile value frozen at definition time" - def display_extra_help(helpfile=helpfile): + def _extra_help_callback(self, resource): + """Return a callback that loads resource (file or web page).""" + def display_extra_help(helpfile=resource): if not helpfile.startswith(('www', 'http')): helpfile = os.path.normpath(helpfile) if sys.platform[:3] == 'win': @@ -1158,6 +1202,7 @@ def load_extension(self, name): self.text.bind(vevent, getattr(ins, methodname)) def apply_bindings(self, keydefs=None): + """Add events with keys to self.text.""" if keydefs is None: keydefs = self.mainmenu.default_keydefs text = self.text @@ -1167,9 +1212,10 @@ def apply_bindings(self, keydefs=None): text.event_add(event, *keylist) def fill_menus(self, menudefs=None, keydefs=None): - """Add appropriate entries to the menus and submenus + """Fill in dropdown menus used by this window. - Menus that are absent or None in self.menudict are ignored. + Items whose name begins with '!' become checkbuttons. + Other names indicate commands. None becomes a separator. """ if menudefs is None: menudefs = self.mainmenu.menudefs @@ -1182,7 +1228,7 @@ def fill_menus(self, menudefs=None, keydefs=None): if not menu: continue for entry in entrylist: - if not entry: + if entry is None: menu.add_separator() else: label, eventname = entry @@ -1218,11 +1264,13 @@ def setvar(self, name, value, vartype=None): else: raise NameError(name) - def get_var_obj(self, name, vartype=None): - var = self.tkinter_vars.get(name) + def get_var_obj(self, eventname, vartype=None): + """Return a tkinter variable instance for the event. + """ + var = self.tkinter_vars.get(eventname) if not var and vartype: - # create a Tkinter variable object with self.text as master: - self.tkinter_vars[name] = var = vartype(self.text) + # Create a Tkinter variable object. + self.tkinter_vars[eventname] = var = vartype(self.text) return var # Tk implementations of "virtual text methods" -- each platform @@ -1613,8 +1661,16 @@ def run(self): ### end autoindent code ### def prepstr(s): - # Helper to extract the underscore from a string, e.g. - # prepstr("Co_py") returns (2, "Copy"). + """Extract the underscore from a string. + + For example, prepstr("Co_py") returns (2, "Copy"). + + Args: + s: String with underscore. + + Returns: + Tuple of (position of underscore, string without underscore). + """ i = s.find('_') if i >= 0: s = s[:i] + s[i+1:] @@ -1628,6 +1684,18 @@ def prepstr(s): } def get_accelerator(keydefs, eventname): + """Return a formatted string for the keybinding of an event. + + Convert the first keybinding for a given event to a form that + can be displayed as an accelerator on the menu. + + Args: + keydefs: Dictionary of valid events to keybindings. + eventname: Event to retrieve keybinding for. + + Returns: + Formatted string of the keybinding. + """ keylist = keydefs.get(eventname) # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5 # if not keylist: @@ -1637,14 +1705,23 @@ def get_accelerator(keydefs, eventname): "<<change-indentwidth>>"}): return "" s = keylist[0] + # Convert strings of the form -singlelowercase to -singleuppercase. s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s) + # Convert certain keynames to their symbol. s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) + # Remove Key- from string. s = re.sub("Key-", "", s) - s = re.sub("Cancel","Ctrl-Break",s) # dscherer at cmu.edu + # Convert Cancel to Ctrl-Break. + s = re.sub("Cancel", "Ctrl-Break", s) # dscherer at cmu.edu + # Convert Control to Ctrl-. s = re.sub("Control-", "Ctrl-", s) + # Change - to +. s = re.sub("-", "+", s) + # Change >< to space. s = re.sub("><", " ", s) + # Remove <. s = re.sub("<", "", s) + # Remove >. s = re.sub(">", "", s) return s From webhook-mailer at python.org Sat May 13 16:45:45 2023 From: webhook-mailer at python.org (gpshead) Date: Sat, 13 May 2023 20:45:45 -0000 Subject: [Python-checkins] gh-104454: Fix refleak in AttributeError_reduce (#104455) Message-ID: <mailman.350.1684010746.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7d2deafb73237a2175971a26cfb544974661de4b commit: 7d2deafb73237a2175971a26cfb544974661de4b branch: main author: Charles Machalow <csm10495 at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-13T13:45:36-07:00 summary: gh-104454: Fix refleak in AttributeError_reduce (#104455) * Fix the reference leak introduced by https://github.com/python/cpython/issues/103333 Co-authored-by: Kirill Podoprigora <kirill.bast9 at mail.ru> files: M Objects/exceptions.c diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 59c63f4aa449..a8d4e3a696ce 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2324,7 +2324,9 @@ AttributeError_reduce(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored) return NULL; } - return PyTuple_Pack(3, Py_TYPE(self), self->args, state); + PyObject *return_value = PyTuple_Pack(3, Py_TYPE(self), self->args, state); + Py_DECREF(state); + return return_value; } static PyMemberDef AttributeError_members[] = { From webhook-mailer at python.org Sat May 13 23:55:31 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 14 May 2023 03:55:31 -0000 Subject: [Python-checkins] GH-71383: IDLE - Document testing subsets of modules (#104463) Message-ID: <mailman.351.1684036532.13550.python-checkins@python.org> https://github.com/python/cpython/commit/080a5961527473af182b025bb29e0c52d43fd49e commit: 080a5961527473af182b025bb29e0c52d43fd49e branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-13T23:55:20-04:00 summary: GH-71383: IDLE - Document testing subsets of modules (#104463) files: M Lib/idlelib/idle_test/README.txt M Lib/idlelib/idle_test/__init__.py M Lib/test/test_idle.py diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt index 566bfd179fdf..cacd06db873d 100644 --- a/Lib/idlelib/idle_test/README.txt +++ b/Lib/idlelib/idle_test/README.txt @@ -146,14 +146,17 @@ python -m unittest -v idlelib.idle_test python -m test -v -ugui test_idle python -m test.test_idle -The idle tests are 'discovered' by -idlelib.idle_test.__init__.load_tests, which is also imported into -test.test_idle. Normally, neither file should be changed when working on -individual test modules. The third command runs unittest indirectly -through regrtest. The same happens when the entire test suite is run -with 'python -m test'. So that command must work for buildbots to stay -green. Idle tests must not disturb the environment in a way that makes -other tests fail (issue 18081). +IDLE tests are 'discovered' by idlelib.idle_test.__init__.load_tests +when this is imported into test.test_idle. Normally, neither file +should be changed when working on individual test modules. The third +command runs unittest indirectly through regrtest. The same happens when +the entire test suite is run with 'python -m test'. So that command must +work for buildbots to stay green. IDLE tests must not disturb the +environment in a way that makes other tests fail (GH-62281). + +To test subsets of modules, see idlelib.idle_test.__init__. This +can be used to find refleaks or possible sources of "Theme changed" +tcl messages (GH-71383). To run an individual Testcase or test method, extend the dotted name given to unittest on the command line or use the test -m option. The diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py index ad067b405cab..79b5d102dd7d 100644 --- a/Lib/idlelib/idle_test/__init__.py +++ b/Lib/idlelib/idle_test/__init__.py @@ -1,17 +1,27 @@ -'''idlelib.idle_test is a private implementation of test.test_idle, -which tests the IDLE application as part of the stdlib test suite. -Run IDLE tests alone with "python -m test.test_idle". -Starting with Python 3.6, IDLE requires tcl/tk 8.5 or later. +"""idlelib.idle_test implements test.test_idle, which tests the IDLE +application as part of the stdlib test suite. +Run IDLE tests alone with "python -m test.test_idle (-v)". This package and its contained modules are subject to change and any direct use is at your own risk. -''' +""" from os.path import dirname +# test_idle imports load_tests for test discovery (default all). +# To run subsets of idlelib module tests, insert '[<chars>]' after '_'. +# Example: insert '[ac]' for modules beginning with 'a' or 'c'. +# Additional .discover/.addTest pairs with separate inserts work. +# Example: pairs with 'c' and 'g' test c* files and grep. + def load_tests(loader, standard_tests, pattern): this_dir = dirname(__file__) top_dir = dirname(dirname(this_dir)) - package_tests = loader.discover(start_dir=this_dir, pattern='test*.py', + module_tests = loader.discover(start_dir=this_dir, + pattern='test_*.py', # Insert here. top_level_dir=top_dir) - standard_tests.addTests(package_tests) + standard_tests.addTests(module_tests) +## module_tests = loader.discover(start_dir=this_dir, +## pattern='test_*.py', # Insert here. +## top_level_dir=top_dir) +## standard_tests.addTests(module_tests) return standard_tests diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py index 90cff9002b75..ebb1e8eb823b 100644 --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -5,12 +5,8 @@ if check_sanitizer(address=True, memory=True): raise unittest.SkipTest("Tests involving libX11 can SEGFAULT on ASAN/MSAN builds") -# Skip test_idle if _tkinter wasn't built, if tkinter is missing, -# if tcl/tk is not the 8.5+ needed for ttk widgets, -# or if idlelib is missing (not installed). +# Skip test_idle if _tkinter, tkinter, or idlelib are missing. tk = import_module('tkinter') # Also imports _tkinter. -if tk.TkVersion < 8.5: - raise unittest.SkipTest("IDLE requires tk 8.5 or later.") idlelib = import_module('idlelib') # Before importing and executing more of idlelib, From webhook-mailer at python.org Sun May 14 00:18:55 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 14 May 2023 04:18:55 -0000 Subject: [Python-checkins] [3.11] GH-71383: IDLE - Document testing subsets of modules (GH-104463) (#104464) Message-ID: <mailman.352.1684037936.13550.python-checkins@python.org> https://github.com/python/cpython/commit/03f0d75f1de21288c0c9c9c35219657c48856062 commit: 03f0d75f1de21288c0c9c9c35219657c48856062 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-14T04:18:30Z summary: [3.11] GH-71383: IDLE - Document testing subsets of modules (GH-104463) (#104464) GH-71383: IDLE - Document testing subsets of modules (GH-104463) (cherry picked from commit 080a5961527473af182b025bb29e0c52d43fd49e) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: M Lib/idlelib/idle_test/README.txt M Lib/idlelib/idle_test/__init__.py M Lib/test/test_idle.py diff --git a/Lib/idlelib/idle_test/README.txt b/Lib/idlelib/idle_test/README.txt index 566bfd179fdf..cacd06db873d 100644 --- a/Lib/idlelib/idle_test/README.txt +++ b/Lib/idlelib/idle_test/README.txt @@ -146,14 +146,17 @@ python -m unittest -v idlelib.idle_test python -m test -v -ugui test_idle python -m test.test_idle -The idle tests are 'discovered' by -idlelib.idle_test.__init__.load_tests, which is also imported into -test.test_idle. Normally, neither file should be changed when working on -individual test modules. The third command runs unittest indirectly -through regrtest. The same happens when the entire test suite is run -with 'python -m test'. So that command must work for buildbots to stay -green. Idle tests must not disturb the environment in a way that makes -other tests fail (issue 18081). +IDLE tests are 'discovered' by idlelib.idle_test.__init__.load_tests +when this is imported into test.test_idle. Normally, neither file +should be changed when working on individual test modules. The third +command runs unittest indirectly through regrtest. The same happens when +the entire test suite is run with 'python -m test'. So that command must +work for buildbots to stay green. IDLE tests must not disturb the +environment in a way that makes other tests fail (GH-62281). + +To test subsets of modules, see idlelib.idle_test.__init__. This +can be used to find refleaks or possible sources of "Theme changed" +tcl messages (GH-71383). To run an individual Testcase or test method, extend the dotted name given to unittest on the command line or use the test -m option. The diff --git a/Lib/idlelib/idle_test/__init__.py b/Lib/idlelib/idle_test/__init__.py index ad067b405cab..79b5d102dd7d 100644 --- a/Lib/idlelib/idle_test/__init__.py +++ b/Lib/idlelib/idle_test/__init__.py @@ -1,17 +1,27 @@ -'''idlelib.idle_test is a private implementation of test.test_idle, -which tests the IDLE application as part of the stdlib test suite. -Run IDLE tests alone with "python -m test.test_idle". -Starting with Python 3.6, IDLE requires tcl/tk 8.5 or later. +"""idlelib.idle_test implements test.test_idle, which tests the IDLE +application as part of the stdlib test suite. +Run IDLE tests alone with "python -m test.test_idle (-v)". This package and its contained modules are subject to change and any direct use is at your own risk. -''' +""" from os.path import dirname +# test_idle imports load_tests for test discovery (default all). +# To run subsets of idlelib module tests, insert '[<chars>]' after '_'. +# Example: insert '[ac]' for modules beginning with 'a' or 'c'. +# Additional .discover/.addTest pairs with separate inserts work. +# Example: pairs with 'c' and 'g' test c* files and grep. + def load_tests(loader, standard_tests, pattern): this_dir = dirname(__file__) top_dir = dirname(dirname(this_dir)) - package_tests = loader.discover(start_dir=this_dir, pattern='test*.py', + module_tests = loader.discover(start_dir=this_dir, + pattern='test_*.py', # Insert here. top_level_dir=top_dir) - standard_tests.addTests(package_tests) + standard_tests.addTests(module_tests) +## module_tests = loader.discover(start_dir=this_dir, +## pattern='test_*.py', # Insert here. +## top_level_dir=top_dir) +## standard_tests.addTests(module_tests) return standard_tests diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py index b94b18a541a7..7cf3a93dd5b1 100644 --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -5,12 +5,8 @@ if check_sanitizer(address=True, memory=True): raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") -# Skip test_idle if _tkinter wasn't built, if tkinter is missing, -# if tcl/tk is not the 8.5+ needed for ttk widgets, -# or if idlelib is missing (not installed). +# Skip test_idle if _tkinter, tkinter, or idlelib are missing. tk = import_module('tkinter') # Also imports _tkinter. -if tk.TkVersion < 8.5: - raise unittest.SkipTest("IDLE requires tk 8.5 or later.") idlelib = import_module('idlelib') # Before importing and executing more of idlelib, From webhook-mailer at python.org Sun May 14 07:03:43 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 14 May 2023 11:03:43 -0000 Subject: [Python-checkins] gh-87092: avoid gcc warning on uninitialized struct field in assemble.c (#104460) Message-ID: <mailman.353.1684062224.13550.python-checkins@python.org> https://github.com/python/cpython/commit/178153c9a6f32da8d132aae591c0cfebea7c6366 commit: 178153c9a6f32da8d132aae591c0cfebea7c6366 branch: main author: Dong-hee Na <donghee.na at python.org> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-14T12:03:30+01:00 summary: gh-87092: avoid gcc warning on uninitialized struct field in assemble.c (#104460) files: M Python/assemble.c diff --git a/Python/assemble.c b/Python/assemble.c index 6889831ae3fe..8789d8ef978c 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -128,7 +128,7 @@ assemble_emit_exception_table_entry(struct assembler *a, int start, int end, assert(end > start); int target = handler->h_offset; int depth = handler->h_startdepth - 1; - if (handler->h_preserve_lasti) { + if (handler->h_preserve_lasti > 0) { depth -= 1; } assert(depth >= 0); @@ -146,6 +146,7 @@ assemble_exception_table(struct assembler *a, instr_sequence *instrs) int ioffset = 0; _PyCompile_ExceptHandlerInfo handler; handler.h_offset = -1; + handler.h_preserve_lasti = -1; int start = -1; for (int i = 0; i < instrs->s_used; i++) { instruction *instr = &instrs->s_instrs[i]; From webhook-mailer at python.org Sun May 14 07:53:23 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 14 May 2023 11:53:23 -0000 Subject: [Python-checkins] Minor improvements to typing docs (#104465) Message-ID: <mailman.354.1684065203.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2f7b5e458e9189fa1ffd44339848aa1e52add3fa commit: 2f7b5e458e9189fa1ffd44339848aa1e52add3fa branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-14T12:53:15+01:00 summary: Minor improvements to typing docs (#104465) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index fb1c916b141a..c300c4257f0e 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -19,7 +19,7 @@ This module provides runtime support for type hints. The most fundamental support consists of the types :data:`Any`, :data:`Union`, :data:`Callable`, -:class:`TypeVar`, and :class:`Generic`. For a full specification, please see +:class:`TypeVar`, and :class:`Generic`. For a specification, please see :pep:`484`. For a simplified introduction to type hints, see :pep:`483`. @@ -592,7 +592,7 @@ The module defines the following classes, functions and decorators. when the checked program targets Python 3.9 or newer. The deprecated types will be removed from the :mod:`typing` module - in the first Python version released 5 years after the release of Python 3.9.0. + no sooner than the first Python version released 5 years after the release of Python 3.9.0. See details in :pep:`585`?*Type Hinting Generics In Standard Collections*. @@ -1291,6 +1291,8 @@ These are not used in annotations. They are building blocks for creating generic U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method +.. _typing-constrained-typevar: + Using a *constrained* type variable, however, means that the ``TypeVar`` can only ever be solved as being exactly one of the constraints given:: @@ -1550,7 +1552,7 @@ These are not used in annotations. They are building blocks for creating generic .. data:: AnyStr - ``AnyStr`` is a :class:`constrained type variable <TypeVar>` defined as + ``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as ``AnyStr = TypeVar('AnyStr', str, bytes)``. It is meant to be used for functions that may accept any kind of string @@ -2112,7 +2114,7 @@ Other concrete types Python 2 is no longer supported, and most type checkers also no longer support type checking Python 2 code. Removal of the alias is not currently planned, but users are encouraged to use - :class:`str` instead of ``Text`` wherever possible. + :class:`str` instead of ``Text``. Abstract Base Classes --------------------- From webhook-mailer at python.org Sun May 14 08:01:04 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 14 May 2023 12:01:04 -0000 Subject: [Python-checkins] [3.11] Minor improvements to typing docs (GH-104465) (#104475) Message-ID: <mailman.355.1684065665.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f5f99756e13cff0e98844e8e15a29519c25a04e5 commit: f5f99756e13cff0e98844e8e15a29519c25a04e5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-14T13:00:57+01:00 summary: [3.11] Minor improvements to typing docs (GH-104465) (#104475) Minor improvements to typing docs (GH-104465) (cherry picked from commit 2f7b5e458e9189fa1ffd44339848aa1e52add3fa) Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index a99a35a7664f..443045469ad6 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -19,7 +19,7 @@ This module provides runtime support for type hints. The most fundamental support consists of the types :data:`Any`, :data:`Union`, :data:`Callable`, -:class:`TypeVar`, and :class:`Generic`. For a full specification, please see +:class:`TypeVar`, and :class:`Generic`. For a specification, please see :pep:`484`. For a simplified introduction to type hints, see :pep:`483`. @@ -587,7 +587,7 @@ The module defines the following classes, functions and decorators. when the checked program targets Python 3.9 or newer. The deprecated types will be removed from the :mod:`typing` module - in the first Python version released 5 years after the release of Python 3.9.0. + no sooner than the first Python version released 5 years after the release of Python 3.9.0. See details in :pep:`585`?*Type Hinting Generics In Standard Collections*. @@ -1286,6 +1286,8 @@ These are not used in annotations. They are building blocks for creating generic U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method +.. _typing-constrained-typevar: + Using a *constrained* type variable, however, means that the ``TypeVar`` can only ever be solved as being exactly one of the constraints given:: @@ -1528,7 +1530,7 @@ These are not used in annotations. They are building blocks for creating generic .. data:: AnyStr - ``AnyStr`` is a :class:`constrained type variable <TypeVar>` defined as + ``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as ``AnyStr = TypeVar('AnyStr', str, bytes)``. It is meant to be used for functions that may accept any kind of string @@ -2072,7 +2074,7 @@ Other concrete types Python 2 is no longer supported, and most type checkers also no longer support type checking Python 2 code. Removal of the alias is not currently planned, but users are encouraged to use - :class:`str` instead of ``Text`` wherever possible. + :class:`str` instead of ``Text``. Abstract Base Classes --------------------- From webhook-mailer at python.org Sun May 14 14:46:03 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 14 May 2023 18:46:03 -0000 Subject: [Python-checkins] gh-104337: Clarify random.gammavariate doc entry (#104410) Message-ID: <mailman.356.1684089963.13550.python-checkins@python.org> https://github.com/python/cpython/commit/88c5c586708dcff369c49edae947d487a80f0346 commit: 88c5c586708dcff369c49edae947d487a80f0346 branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-14T14:45:54-04:00 summary: gh-104337: Clarify random.gammavariate doc entry (#104410) * gh-104337: Clarify random.gammavariate doc entry * Fix parameter markup. files: M Doc/library/random.rst diff --git a/Doc/library/random.rst b/Doc/library/random.rst index c192919ac62e..76ae97a8be7e 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -334,8 +334,10 @@ be found in any statistics text. .. function:: gammavariate(alpha, beta) - Gamma distribution. (*Not* the gamma function!) Conditions on the - parameters are ``alpha > 0`` and ``beta > 0``. + Gamma distribution. (*Not* the gamma function!) The shape and + scale parameters, *alpha* and *beta*, must have positive values. + (Calling conventions vary and some sources define 'beta' + as the inverse of the scale). The probability distribution function is:: @@ -346,7 +348,8 @@ be found in any statistics text. .. function:: gauss(mu=0.0, sigma=1.0) - Normal distribution, also called the Gaussian distribution. *mu* is the mean, + Normal distribution, also called the Gaussian distribution. + *mu* is the mean, and *sigma* is the standard deviation. This is slightly faster than the :func:`normalvariate` function defined below. From webhook-mailer at python.org Sun May 14 14:58:20 2023 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 14 May 2023 18:58:20 -0000 Subject: [Python-checkins] gh-98539: Make _SSLTransportProtocol.abort() safe to call when closed (#104474) Message-ID: <mailman.357.1684090702.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fb8739f0b6291fb048a94d6312f59ba4d10a20ca commit: fb8739f0b6291fb048a94d6312f59ba4d10a20ca branch: main author: Sam Bull <git at sambull.org> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-14T11:58:13-07:00 summary: gh-98539: Make _SSLTransportProtocol.abort() safe to call when closed (#104474) files: M Lib/asyncio/sslproto.py diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index bbf9cad6bc7f..488e17d8bccd 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -244,7 +244,8 @@ def abort(self): called with None as its argument. """ self._closed = True - self._ssl_protocol._abort() + if self._ssl_protocol is not None: + self._ssl_protocol._abort() def _force_close(self, exc): self._closed = True From webhook-mailer at python.org Sun May 14 16:25:32 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 14 May 2023 20:25:32 -0000 Subject: [Python-checkins] [3.11] gh-104337: Clarify random.gammavariate doc entry (GH-104410) (#104481) Message-ID: <mailman.358.1684095932.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8e79414efcaf3e922a5d7e0eee57a7aeb7b3eea7 commit: 8e79414efcaf3e922a5d7e0eee57a7aeb7b3eea7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-14T16:25:25-04:00 summary: [3.11] gh-104337: Clarify random.gammavariate doc entry (GH-104410) (#104481) (cherry picked from commit 88c5c586708dcff369c49edae947d487a80f0346) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: M Doc/library/random.rst diff --git a/Doc/library/random.rst b/Doc/library/random.rst index c7620b032843..3109343a3c52 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -310,8 +310,10 @@ be found in any statistics text. .. function:: gammavariate(alpha, beta) - Gamma distribution. (*Not* the gamma function!) Conditions on the - parameters are ``alpha > 0`` and ``beta > 0``. + Gamma distribution. (*Not* the gamma function!) The shape and + scale parameters, *alpha* and *beta*, must have positive values. + (Calling conventions vary and some sources define 'beta' + as the inverse of the scale). The probability distribution function is:: @@ -322,7 +324,8 @@ be found in any statistics text. .. function:: gauss(mu=0.0, sigma=1.0) - Normal distribution, also called the Gaussian distribution. *mu* is the mean, + Normal distribution, also called the Gaussian distribution. + *mu* is the mean, and *sigma* is the standard deviation. This is slightly faster than the :func:`normalvariate` function defined below. From webhook-mailer at python.org Sun May 14 17:05:42 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 14 May 2023 21:05:42 -0000 Subject: [Python-checkins] gh-104456: Fix ref leak in _ctypes.COMError (#104457) Message-ID: <mailman.359.1684098343.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2cd1c87d2a23ffd00730b5d1648304593530326c commit: 2cd1c87d2a23ffd00730b5d1648304593530326c branch: main author: Kirill Podoprigora <kirill.bast9 at mail.ru> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-14T21:05:35Z summary: gh-104456: Fix ref leak in _ctypes.COMError (#104457) files: M Modules/_ctypes/_ctypes.c diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index f6cda45eaeac..534ef8c1d6cf 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5476,11 +5476,17 @@ comerror_init(PyObject *self, PyObject *args, PyObject *kwds) return 0; } +static int +comerror_clear(PyObject *self) +{ + return ((PyTypeObject *)PyExc_BaseException)->tp_clear(self); +} + static int comerror_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); - return 0; + return ((PyTypeObject *)PyExc_BaseException)->tp_traverse(self, visit, arg); } static void @@ -5488,6 +5494,7 @@ comerror_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); + (void)comerror_clear(self); tp->tp_free(self); Py_DECREF(tp); } @@ -5497,6 +5504,7 @@ static PyType_Slot comerror_slots[] = { {Py_tp_init, comerror_init}, {Py_tp_traverse, comerror_traverse}, {Py_tp_dealloc, comerror_dealloc}, + {Py_tp_clear, comerror_clear}, {0, NULL}, }; From webhook-mailer at python.org Sun May 14 17:24:13 2023 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 14 May 2023 21:24:13 -0000 Subject: [Python-checkins] [3.11] gh-98539: Make _SSLTransportProtocol.abort() safe to call when closed (GH-104474) (#104485) Message-ID: <mailman.360.1684099454.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1afc0a9591460d85626f26a32ff0c56bcc06b8d8 commit: 1afc0a9591460d85626f26a32ff0c56bcc06b8d8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-14T21:24:07Z summary: [3.11] gh-98539: Make _SSLTransportProtocol.abort() safe to call when closed (GH-104474) (#104485) (cherry picked from commit fb8739f0b6291fb048a94d6312f59ba4d10a20ca) Co-authored-by: Sam Bull <git at sambull.org> files: M Lib/asyncio/sslproto.py diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index bbf9cad6bc7f..488e17d8bccd 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -244,7 +244,8 @@ def abort(self): called with None as its argument. """ self._closed = True - self._ssl_protocol._abort() + if self._ssl_protocol is not None: + self._ssl_protocol._abort() def _force_close(self, exc): self._closed = True From webhook-mailer at python.org Sun May 14 23:44:46 2023 From: webhook-mailer at python.org (corona10) Date: Mon, 15 May 2023 03:44:46 -0000 Subject: [Python-checkins] gh-104469 Convert _testcapi/float.c to use AC (gh-104470) Message-ID: <mailman.361.1684122286.13550.python-checkins@python.org> https://github.com/python/cpython/commit/48b3617de491f00a3bf978b355074cc8e228d61b commit: 48b3617de491f00a3bf978b355074cc8e228d61b branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-15T12:44:00+09:00 summary: gh-104469 Convert _testcapi/float.c to use AC (gh-104470) files: A Modules/_testcapi/clinic/float.c.h M Modules/_testcapi/float.c diff --git a/Modules/_testcapi/clinic/float.c.h b/Modules/_testcapi/clinic/float.c.h new file mode 100644 index 000000000000..c1dff2a9ac57 --- /dev/null +++ b/Modules/_testcapi/clinic/float.c.h @@ -0,0 +1,88 @@ +/*[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(_testcapi_float_pack__doc__, +"float_pack($module, size, d, le, /)\n" +"--\n" +"\n" +"Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8()"); + +#define _TESTCAPI_FLOAT_PACK_METHODDEF \ + {"float_pack", _PyCFunction_CAST(_testcapi_float_pack), METH_FASTCALL, _testcapi_float_pack__doc__}, + +static PyObject * +_testcapi_float_pack_impl(PyObject *module, int size, double d, int le); + +static PyObject * +_testcapi_float_pack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int size; + double d; + int le; + + if (!_PyArg_CheckPositional("float_pack", nargs, 3, 3)) { + goto exit; + } + size = _PyLong_AsInt(args[0]); + if (size == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_CheckExact(args[1])) { + d = PyFloat_AS_DOUBLE(args[1]); + } + else + { + d = PyFloat_AsDouble(args[1]); + if (d == -1.0 && PyErr_Occurred()) { + goto exit; + } + } + le = _PyLong_AsInt(args[2]); + if (le == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _testcapi_float_pack_impl(module, size, d, le); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_float_unpack__doc__, +"float_unpack($module, data, le, /)\n" +"--\n" +"\n" +"Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8()"); + +#define _TESTCAPI_FLOAT_UNPACK_METHODDEF \ + {"float_unpack", _PyCFunction_CAST(_testcapi_float_unpack), METH_FASTCALL, _testcapi_float_unpack__doc__}, + +static PyObject * +_testcapi_float_unpack_impl(PyObject *module, const char *data, + Py_ssize_t data_length, int le); + +static PyObject * +_testcapi_float_unpack(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + const char *data; + Py_ssize_t data_length; + int le; + + if (!_PyArg_ParseStack(args, nargs, "y#i:float_unpack", + &data, &data_length, &le)) { + goto exit; + } + return_value = _testcapi_float_unpack_impl(module, data, data_length, le); + +exit: + return return_value; +} +/*[clinic end generated code: output=083e5df26cd5fbeb input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c index 26d99d990e00..33cbda83a81a 100644 --- a/Modules/_testcapi/float.c +++ b/Modules/_testcapi/float.c @@ -1,18 +1,29 @@ #define PY_SSIZE_T_CLEAN #include "parts.h" +#include "clinic/float.c.h" -// Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() +/*[clinic input] +module _testcapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ + +/*[clinic input] +_testcapi.float_pack + + size: int + d: double + le: int + / + +Test PyFloat_Pack2(), PyFloat_Pack4() and PyFloat_Pack8() +[clinic start generated code]*/ + static PyObject * -test_float_pack(PyObject *self, PyObject *args) +_testcapi_float_pack_impl(PyObject *module, int size, double d, int le) +/*[clinic end generated code: output=7899bd98f8b6cb04 input=52c9115121999c98]*/ { - int size; - double d; - int le; - if (!PyArg_ParseTuple(args, "idi", &size, &d, &le)) { - return NULL; - } switch (size) { case 2: @@ -47,19 +58,24 @@ test_float_pack(PyObject *self, PyObject *args) } -// Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8() +/*[clinic input] +_testcapi.float_unpack + + data: str(accept={robuffer}, zeroes=True) + le: int + / + +Test PyFloat_Unpack2(), PyFloat_Unpack4() and PyFloat_Unpack8() +[clinic start generated code]*/ + static PyObject * -test_float_unpack(PyObject *self, PyObject *args) +_testcapi_float_unpack_impl(PyObject *module, const char *data, + Py_ssize_t data_length, int le) +/*[clinic end generated code: output=617059f889ddbfe4 input=c095e4bb75a696cd]*/ { assert(!PyErr_Occurred()); - const char *data; - Py_ssize_t size; - int le; - if (!PyArg_ParseTuple(args, "y#i", &data, &size, &le)) { - return NULL; - } double d; - switch (size) + switch (data_length) { case 2: d = PyFloat_Unpack2(data, le); @@ -82,8 +98,8 @@ test_float_unpack(PyObject *self, PyObject *args) } static PyMethodDef test_methods[] = { - {"float_pack", test_float_pack, METH_VARARGS, NULL}, - {"float_unpack", test_float_unpack, METH_VARARGS, NULL}, + _TESTCAPI_FLOAT_PACK_METHODDEF + _TESTCAPI_FLOAT_UNPACK_METHODDEF {NULL}, }; From webhook-mailer at python.org Mon May 15 00:29:50 2023 From: webhook-mailer at python.org (corona10) Date: Mon, 15 May 2023 04:29:50 -0000 Subject: [Python-checkins] gh-101282: move BOLT config after PGO (gh-104493) Message-ID: <mailman.362.1684124991.13550.python-checkins@python.org> https://github.com/python/cpython/commit/27d8ecd7f3325a40a967d2d6b6b36b21d5328753 commit: 27d8ecd7f3325a40a967d2d6b6b36b21d5328753 branch: main author: Gregory Szorc <gregory.szorc at gmail.com> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-15T04:29:44Z summary: gh-101282: move BOLT config after PGO (gh-104493) files: M configure M configure.ac diff --git a/configure b/configure index c9ea72cf6efa..4d3520aee43d 100755 --- a/configure +++ b/configure @@ -883,6 +883,11 @@ CFLAGS_NODIST BASECFLAGS CFLAGS_ALIASING OPT +MERGE_FDATA +LLVM_BOLT +ac_ct_READELF +READELF +PREBOLT_RULE LLVM_PROF_FOUND LLVM_PROFDATA LLVM_PROF_ERR @@ -890,11 +895,6 @@ LLVM_PROF_FILE LLVM_PROF_MERGER PGO_PROF_USE_FLAG PGO_PROF_GEN_FLAG -MERGE_FDATA -LLVM_BOLT -ac_ct_READELF -READELF -PREBOLT_RULE LLVM_AR_FOUND LLVM_AR PROFILE_TASK @@ -7903,7 +7903,181 @@ fi LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS" fi -# Enable bolt flags +# Enable PGO flags. + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}llvm-profdata", so it can be a program name with args. +set dummy ${ac_tool_prefix}llvm-profdata; 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_path_LLVM_PROFDATA+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $LLVM_PROFDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in ${llvm_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_path_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" + $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 + + ;; +esac +fi +LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA +if test -n "$LLVM_PROFDATA"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_PROFDATA" >&5 +$as_echo "$LLVM_PROFDATA" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_LLVM_PROFDATA"; then + ac_pt_LLVM_PROFDATA=$LLVM_PROFDATA + # Extract the first word of "llvm-profdata", so it can be a program name with args. +set dummy llvm-profdata; 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_path_ac_pt_LLVM_PROFDATA+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_LLVM_PROFDATA in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_LLVM_PROFDATA="$ac_pt_LLVM_PROFDATA" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in ${llvm_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_path_ac_pt_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" + $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 + + ;; +esac +fi +ac_pt_LLVM_PROFDATA=$ac_cv_path_ac_pt_LLVM_PROFDATA +if test -n "$ac_pt_LLVM_PROFDATA"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_PROFDATA" >&5 +$as_echo "$ac_pt_LLVM_PROFDATA" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_LLVM_PROFDATA" = x; then + LLVM_PROFDATA="''" + 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 + LLVM_PROFDATA=$ac_pt_LLVM_PROFDATA + fi +else + LLVM_PROFDATA="$ac_cv_path_LLVM_PROFDATA" +fi + + +if test -n "${LLVM_PROFDATA}" -a -x "${LLVM_PROFDATA}" +then + LLVM_PROF_FOUND="found" +else + LLVM_PROF_FOUND="not-found" +fi +if test "$ac_sys_system" = "Darwin" -a "${LLVM_PROF_FOUND}" = "not-found" +then + found_llvm_profdata=`/usr/bin/xcrun -find llvm-profdata 2>/dev/null` + if test -n "${found_llvm_profdata}" + then + # llvm-profdata isn't directly in $PATH in some cases. + # https://apple.stackexchange.com/questions/197053/ + LLVM_PROFDATA='/usr/bin/xcrun llvm-profdata' + LLVM_PROF_FOUND=found + { $as_echo "$as_me:${as_lineno-$LINENO}: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&5 +$as_echo "$as_me: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&6;} + fi +fi +LLVM_PROF_ERR=no +case $CC in + *clang*) + # Any changes made here should be reflected in the GCC+Darwin case below + PGO_PROF_GEN_FLAG="-fprofile-instr-generate" + PGO_PROF_USE_FLAG="-fprofile-instr-use=code.profclangd" + LLVM_PROF_MERGER="${LLVM_PROFDATA} merge -output=code.profclangd *.profclangr" + LLVM_PROF_FILE="LLVM_PROFILE_FILE=\"code-%p.profclangr\"" + if test $LLVM_PROF_FOUND = not-found + then + LLVM_PROF_ERR=yes + if test "${REQUIRE_PGO}" = "yes" + then + as_fn_error $? "llvm-profdata is required for a --enable-optimizations build but could not be found." "$LINENO" 5 + fi + fi + ;; + *gcc*) + case $ac_sys_system in + Darwin*) + PGO_PROF_GEN_FLAG="-fprofile-instr-generate" + PGO_PROF_USE_FLAG="-fprofile-instr-use=code.profclangd" + LLVM_PROF_MERGER="${LLVM_PROFDATA} merge -output=code.profclangd *.profclangr" + LLVM_PROF_FILE="LLVM_PROFILE_FILE=\"code-%p.profclangr\"" + if test "${LLVM_PROF_FOUND}" = "not-found" + then + LLVM_PROF_ERR=yes + if test "${REQUIRE_PGO}" = "yes" + then + as_fn_error $? "llvm-profdata is required for a --enable-optimizations build but could not be found." "$LINENO" 5 + fi + fi + ;; + *) + PGO_PROF_GEN_FLAG="-fprofile-generate" + PGO_PROF_USE_FLAG="-fprofile-use -fprofile-correction" + LLVM_PROF_MERGER="true" + LLVM_PROF_FILE="" + ;; + esac + ;; + *icc*) + PGO_PROF_GEN_FLAG="-prof-gen" + PGO_PROF_USE_FLAG="-prof-use" + LLVM_PROF_MERGER="true" + LLVM_PROF_FILE="" + ;; +esac + +# BOLT optimization. Always configured after PGO since it always runs after PGO. Py_BOLT='false' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-bolt" >&5 $as_echo_n "checking for --enable-bolt... " >&6; } @@ -8300,180 +8474,6 @@ $as_echo "\"Found merge-fdata\"" >&6; } fi fi -# Enable PGO flags. - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}llvm-profdata", so it can be a program name with args. -set dummy ${ac_tool_prefix}llvm-profdata; 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_path_LLVM_PROFDATA+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $LLVM_PROFDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_LLVM_PROFDATA="$LLVM_PROFDATA" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in ${llvm_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_path_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" - $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 - - ;; -esac -fi -LLVM_PROFDATA=$ac_cv_path_LLVM_PROFDATA -if test -n "$LLVM_PROFDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LLVM_PROFDATA" >&5 -$as_echo "$LLVM_PROFDATA" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_path_LLVM_PROFDATA"; then - ac_pt_LLVM_PROFDATA=$LLVM_PROFDATA - # Extract the first word of "llvm-profdata", so it can be a program name with args. -set dummy llvm-profdata; 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_path_ac_pt_LLVM_PROFDATA+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $ac_pt_LLVM_PROFDATA in - [\\/]* | ?:[\\/]*) - ac_cv_path_ac_pt_LLVM_PROFDATA="$ac_pt_LLVM_PROFDATA" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in ${llvm_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_path_ac_pt_LLVM_PROFDATA="$as_dir/$ac_word$ac_exec_ext" - $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 - - ;; -esac -fi -ac_pt_LLVM_PROFDATA=$ac_cv_path_ac_pt_LLVM_PROFDATA -if test -n "$ac_pt_LLVM_PROFDATA"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LLVM_PROFDATA" >&5 -$as_echo "$ac_pt_LLVM_PROFDATA" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_pt_LLVM_PROFDATA" = x; then - LLVM_PROFDATA="''" - 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 - LLVM_PROFDATA=$ac_pt_LLVM_PROFDATA - fi -else - LLVM_PROFDATA="$ac_cv_path_LLVM_PROFDATA" -fi - - -if test -n "${LLVM_PROFDATA}" -a -x "${LLVM_PROFDATA}" -then - LLVM_PROF_FOUND="found" -else - LLVM_PROF_FOUND="not-found" -fi -if test "$ac_sys_system" = "Darwin" -a "${LLVM_PROF_FOUND}" = "not-found" -then - found_llvm_profdata=`/usr/bin/xcrun -find llvm-profdata 2>/dev/null` - if test -n "${found_llvm_profdata}" - then - # llvm-profdata isn't directly in $PATH in some cases. - # https://apple.stackexchange.com/questions/197053/ - LLVM_PROFDATA='/usr/bin/xcrun llvm-profdata' - LLVM_PROF_FOUND=found - { $as_echo "$as_me:${as_lineno-$LINENO}: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&5 -$as_echo "$as_me: llvm-profdata found via xcrun: ${LLVM_PROFDATA}" >&6;} - fi -fi -LLVM_PROF_ERR=no -case $CC in - *clang*) - # Any changes made here should be reflected in the GCC+Darwin case below - PGO_PROF_GEN_FLAG="-fprofile-instr-generate" - PGO_PROF_USE_FLAG="-fprofile-instr-use=code.profclangd" - LLVM_PROF_MERGER="${LLVM_PROFDATA} merge -output=code.profclangd *.profclangr" - LLVM_PROF_FILE="LLVM_PROFILE_FILE=\"code-%p.profclangr\"" - if test $LLVM_PROF_FOUND = not-found - then - LLVM_PROF_ERR=yes - if test "${REQUIRE_PGO}" = "yes" - then - as_fn_error $? "llvm-profdata is required for a --enable-optimizations build but could not be found." "$LINENO" 5 - fi - fi - ;; - *gcc*) - case $ac_sys_system in - Darwin*) - PGO_PROF_GEN_FLAG="-fprofile-instr-generate" - PGO_PROF_USE_FLAG="-fprofile-instr-use=code.profclangd" - LLVM_PROF_MERGER="${LLVM_PROFDATA} merge -output=code.profclangd *.profclangr" - LLVM_PROF_FILE="LLVM_PROFILE_FILE=\"code-%p.profclangr\"" - if test "${LLVM_PROF_FOUND}" = "not-found" - then - LLVM_PROF_ERR=yes - if test "${REQUIRE_PGO}" = "yes" - then - as_fn_error $? "llvm-profdata is required for a --enable-optimizations build but could not be found." "$LINENO" 5 - fi - fi - ;; - *) - PGO_PROF_GEN_FLAG="-fprofile-generate" - PGO_PROF_USE_FLAG="-fprofile-use -fprofile-correction" - LLVM_PROF_MERGER="true" - LLVM_PROF_FILE="" - ;; - esac - ;; - *icc*) - PGO_PROF_GEN_FLAG="-prof-gen" - PGO_PROF_USE_FLAG="-prof-use" - LLVM_PROF_MERGER="true" - LLVM_PROF_FILE="" - ;; -esac - # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be # merged with this chunk of code? diff --git a/configure.ac b/configure.ac index 10672bd3761d..0c63cde0363e 100644 --- a/configure.ac +++ b/configure.ac @@ -1929,68 +1929,6 @@ if test "$Py_LTO" = 'true' ; then LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS" fi -# Enable bolt flags -Py_BOLT='false' -AC_MSG_CHECKING(for --enable-bolt) -AC_ARG_ENABLE(bolt, AS_HELP_STRING( - [--enable-bolt], - [enable usage of the llvm-bolt post-link optimizer (default is no)]), -[ -if test "$enableval" != no -then - Py_BOLT='true' - AC_MSG_RESULT(yes); -else - Py_BOLT='false' - AC_MSG_RESULT(no); -fi], -[AC_MSG_RESULT(no)]) - -AC_SUBST(PREBOLT_RULE) -if test "$Py_BOLT" = 'true' ; then - PREBOLT_RULE="${DEF_MAKE_ALL_RULE}" - 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],[ - CFLAGS_NODIST="$CFLAGS_NODIST -fno-reorder-blocks-and-partition" - ]) - - # These flags are required for bolt to work: - LDFLAGS_NODIST="$LDFLAGS_NODIST -Wl,--emit-relocs" - - # These flags are required to get good performance from bolt: - CFLAGS_NODIST="$CFLAGS_NODIST -fno-pie" - # We want to add these no-pie flags to linking executables but not shared libraries: - LINKCC="$LINKCC -fno-pie -no-pie" - AC_SUBST(LLVM_BOLT) - AC_PATH_TOOL(LLVM_BOLT, llvm-bolt, '', ${llvm_path}) - if test -n "${LLVM_BOLT}" -a -x "${LLVM_BOLT}" - then - AC_MSG_RESULT("Found llvm-bolt") - else - AC_MSG_ERROR([llvm-bolt is required for a --enable-bolt build but could not be found.]) - fi - - AC_SUBST(MERGE_FDATA) - AC_PATH_TOOL(MERGE_FDATA, merge-fdata, '', ${llvm_path}) - if test -n "${MERGE_FDATA}" -a -x "${MERGE_FDATA}" - then - AC_MSG_RESULT("Found merge-fdata") - else - AC_MSG_ERROR([merge-fdata is required for a --enable-bolt build but could not be found.]) - fi -fi - # Enable PGO flags. AC_SUBST(PGO_PROF_GEN_FLAG) AC_SUBST(PGO_PROF_USE_FLAG) @@ -2067,6 +2005,68 @@ case $CC in ;; esac +# BOLT optimization. Always configured after PGO since it always runs after PGO. +Py_BOLT='false' +AC_MSG_CHECKING(for --enable-bolt) +AC_ARG_ENABLE(bolt, AS_HELP_STRING( + [--enable-bolt], + [enable usage of the llvm-bolt post-link optimizer (default is no)]), +[ +if test "$enableval" != no +then + Py_BOLT='true' + AC_MSG_RESULT(yes); +else + Py_BOLT='false' + AC_MSG_RESULT(no); +fi], +[AC_MSG_RESULT(no)]) + +AC_SUBST(PREBOLT_RULE) +if test "$Py_BOLT" = 'true' ; then + PREBOLT_RULE="${DEF_MAKE_ALL_RULE}" + 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],[ + CFLAGS_NODIST="$CFLAGS_NODIST -fno-reorder-blocks-and-partition" + ]) + + # These flags are required for bolt to work: + LDFLAGS_NODIST="$LDFLAGS_NODIST -Wl,--emit-relocs" + + # These flags are required to get good performance from bolt: + CFLAGS_NODIST="$CFLAGS_NODIST -fno-pie" + # We want to add these no-pie flags to linking executables but not shared libraries: + LINKCC="$LINKCC -fno-pie -no-pie" + AC_SUBST(LLVM_BOLT) + AC_PATH_TOOL(LLVM_BOLT, llvm-bolt, '', ${llvm_path}) + if test -n "${LLVM_BOLT}" -a -x "${LLVM_BOLT}" + then + AC_MSG_RESULT("Found llvm-bolt") + else + AC_MSG_ERROR([llvm-bolt is required for a --enable-bolt build but could not be found.]) + fi + + AC_SUBST(MERGE_FDATA) + AC_PATH_TOOL(MERGE_FDATA, merge-fdata, '', ${llvm_path}) + if test -n "${MERGE_FDATA}" -a -x "${MERGE_FDATA}" + then + AC_MSG_RESULT("Found merge-fdata") + else + AC_MSG_ERROR([merge-fdata is required for a --enable-bolt build but could not be found.]) + fi +fi + # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be # merged with this chunk of code? From webhook-mailer at python.org Mon May 15 04:03:24 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 15 May 2023 08:03:24 -0000 Subject: [Python-checkins] gh-104487: PYTHON_FOR_REGEN must be minimum Python 3.10 (#104488) Message-ID: <mailman.363.1684137805.13550.python-checkins@python.org> https://github.com/python/cpython/commit/146106a0f1cc61815fa33f0d3f808a3e3e3275be commit: 146106a0f1cc61815fa33f0d3f808a3e3e3275be branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-15T08:02:44Z summary: gh-104487: PYTHON_FOR_REGEN must be minimum Python 3.10 (#104488) Also include Python 3.12 in the list of accepted versions. files: A Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst M Doc/whatsnew/3.12.rst M configure M configure.ac diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index dc1178811e75..3e55b3fa0f47 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1204,6 +1204,8 @@ Build Changes (Contributed by Zhang Na in :gh:`90656`.) +* ``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. + C API Changes ============= diff --git a/Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst b/Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst new file mode 100644 index 000000000000..a3517ac0204b --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst @@ -0,0 +1 @@ +``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. diff --git a/configure b/configure index 4d3520aee43d..7aad4fe89e3c 100755 --- a/configure +++ b/configure @@ -3359,7 +3359,7 @@ fi -for ac_prog in python$PACKAGE_VERSION python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3 python +for ac_prog in python$PACKAGE_VERSION python3.12 python3.11 python3.10 python3 python do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 diff --git a/configure.ac b/configure.ac index 0c63cde0363e..115998e0753b 100644 --- a/configure.ac +++ b/configure.ac @@ -202,7 +202,7 @@ AC_SUBST([FREEZE_MODULE_DEPS]) AC_SUBST([PYTHON_FOR_BUILD_DEPS]) AC_CHECK_PROGS([PYTHON_FOR_REGEN], - [python$PACKAGE_VERSION python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3 python], + [python$PACKAGE_VERSION python3.12 python3.11 python3.10 python3 python], [python3]) AC_SUBST(PYTHON_FOR_REGEN) From webhook-mailer at python.org Mon May 15 04:13:21 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 15 May 2023 08:13:21 -0000 Subject: [Python-checkins] gh-67056: document that registering/unregistering an atexit func from within an atexit func is undefined (#104473) Message-ID: <mailman.364.1684138402.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b15a1a6ac6ea0d7792036e639e90f0e51400c2ee commit: b15a1a6ac6ea0d7792036e639e90f0e51400c2ee branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-15T09:12:52+01:00 summary: gh-67056: document that registering/unregistering an atexit func from within an atexit func is undefined (#104473) files: A Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst M Doc/library/atexit.rst diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst index f7f038107d11..a2bd85b31c9a 100644 --- a/Doc/library/atexit.rst +++ b/Doc/library/atexit.rst @@ -20,6 +20,9 @@ at interpreter termination time they will be run in the order ``C``, ``B``, program is killed by a signal not handled by Python, when a Python fatal internal error is detected, or when :func:`os._exit` is called. +**Note:** The effect of registering or unregistering functions from within +a cleanup function is undefined. + .. versionchanged:: 3.7 When used with C-API subinterpreters, registered functions are local to the interpreter they were registered in. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst b/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst new file mode 100644 index 000000000000..2c6ef1781072 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst @@ -0,0 +1,2 @@ +Document that the effect of registering or unregistering an :mod:`atexit` +cleanup function from within a registered cleanup function is undefined. From webhook-mailer at python.org Mon May 15 04:49:07 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 15 May 2023 08:49:07 -0000 Subject: [Python-checkins] gh-104490: Consistently define phony make targets (#104491) Message-ID: <mailman.365.1684140548.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a6bcc8fb92ffb75bb1907cc568ba9fff516979c3 commit: a6bcc8fb92ffb75bb1907cc568ba9fff516979c3 branch: main author: Gregory Szorc <gregory.szorc at gmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-15T08:48:34Z summary: gh-104490: Consistently define phony make targets (#104491) By convention make targets that don't refer to a file have a dependency on the fake .PHONY target/file. This ensures that these targets are always evaluated because there is no rule to create a .PHONY file and that will force make to think the rule is out of date and needs to be rebuilt. This commit consistently associates virtual targets with .PHONY by declaring the .PHONY dependency immediately above the make rule. This should avoid race conditions and avoidable rebuilds across multiple make invocations. files: A Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index 52cafabd1ab9..7c44b7be5dbe 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -603,12 +603,21 @@ LIBHACL_SHA2_HEADERS= \ # Default target all: @DEF_MAKE_ALL_RULE@ + +# First target in Makefile is implicit default. So .PHONY needs to come after +# all. +.PHONY: all + +.PHONY: build_all build_all: check-clean-src $(BUILDPYTHON) platform sharedmods \ gdbhooks Programs/_testembed scripts checksharedmods rundsymutil + +.PHONY: build_wasm build_wasm: check-clean-src $(BUILDPYTHON) platform sharedmods \ python-config checksharedmods # Check that the source is clean when building out of source. +.PHONY: check-clean-src check-clean-src: @if test -n "$(VPATH)" -a \( \ -f "$(srcdir)/Programs/python.o" \ @@ -652,23 +661,28 @@ profile-run-stamp: # to record its completion and avoid re-running it. touch $@ +.PHONY: build_all_generate_profile build_all_generate_profile: $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)" +.PHONY: run_profile_task run_profile_task: @ # FIXME: can't run for a cross build $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) || true +.PHONY: build_all_merge_profile build_all_merge_profile: $(LLVM_PROF_MERGER) # Compile Python binary with profile guided optimization. # To force re-running of the profile task, remove the profile-run-stamp file. +.PHONY: profile-opt profile-opt: profile-run-stamp @echo "Rebuilding with profile guided optimizations:" -rm -f profile-clean-stamp $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_USE_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST)" +.PHONY: bolt-opt bolt-opt: @PREBOLT_RULE@ rm -f *.fdata @if $(READELF) -p .note.bolt_info $(BUILDPYTHON) | grep BOLT > /dev/null; then\ @@ -685,12 +699,13 @@ bolt-opt: @PREBOLT_RULE@ # Compile and run with gcov -.PHONY=coverage coverage-lcov coverage-report +.PHONY: coverage coverage: @echo "Building with support for coverage checking:" $(MAKE) clean $(MAKE) @DEF_MAKE_RULE@ CFLAGS="$(CFLAGS) -O0 -pg --coverage" LDFLAGS="$(LDFLAGS) --coverage" +.PHONY: coverage-lcov coverage-lcov: @echo "Creating Coverage HTML report with LCOV:" @rm -f $(COVERAGE_INFO) @@ -722,6 +737,7 @@ coverage-lcov: @echo # Force regeneration of parser and frozen modules +.PHONY: coverage-report coverage-report: regen-token regen-frozen @ # build with coverage info $(MAKE) coverage @@ -731,7 +747,7 @@ coverage-report: regen-token regen-frozen $(MAKE) coverage-lcov # Run "Argument Clinic" over all source files -.PHONY=clinic +.PHONY: clinic clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c $(PYTHON_FOR_REGEN) $(srcdir)/Tools/clinic/clinic.py --make --srcdir $(srcdir) $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_global_objects.py @@ -796,6 +812,7 @@ Modules/python.exp: $(LIBRARY) # # Distributors are likely to want to install this somewhere else e.g. relative # to the stripped DWARF data for the shared library. +.PHONY: gdbhooks gdbhooks: $(BUILDPYTHON)-gdb.py SRC_GDB_HOOKS=$(srcdir)/Tools/gdb/libpython.py @@ -936,6 +953,7 @@ $(LIBHACL_SHA2_A): $(LIBHACL_SHA2_OBJS) # create relative links from build/lib.platform/egg.so to Modules/egg.so # pybuilddir.txt is created too late. We cannot use it in Makefile # targets. ln --relative is not portable. +.PHONY: sharedmods sharedmods: $(SHAREDMODS) pybuilddir.txt @target=`cat pybuilddir.txt`; \ $(MKDIR_P) $$target; \ @@ -946,9 +964,11 @@ sharedmods: $(SHAREDMODS) pybuilddir.txt done # dependency on BUILDPYTHON ensures that the target is run last +.PHONY: checksharedmods checksharedmods: sharedmods $(PYTHON_FOR_BUILD_DEPS) $(BUILDPYTHON) @$(RUNSHARED) $(PYTHON_FOR_BUILD) $(srcdir)/Tools/build/check_extension_modules.py +.PHONY: rundsymutil rundsymutil: sharedmods $(PYTHON_FOR_BUILD_DEPS) $(BUILDPYTHON) @if [ ! -z $(DSYMUTIL) ] ; then \ echo $(DSYMUTIL_PATH) $(BUILDPYTHON); \ @@ -1252,20 +1272,24 @@ regen-global-objects: $(srcdir)/Tools/build/generate_global_objects.py ############################################################################ # ABI +.PHONY: regen-abidump regen-abidump: all @$(MKDIR_P) $(srcdir)/Doc/data/ abidw "libpython$(LDVERSION).so" --no-architecture --out-file $(srcdir)/Doc/data/python$(LDVERSION).abi.new @$(UPDATE_FILE) --create $(srcdir)/Doc/data/python$(LDVERSION).abi $(srcdir)/Doc/data/python$(LDVERSION).abi.new +.PHONY: check-abidump check-abidump: all abidiff $(srcdir)/Doc/data/python$(LDVERSION).abi "libpython$(LDVERSION).so" --drop-private-types --no-architecture --no-added-syms +.PHONY: regen-limited-abi regen-limited-abi: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/stable_abi.py --generate-all $(srcdir)/Misc/stable_abi.toml ############################################################################ # Regenerate all generated files +.PHONY: regen-all regen-all: regen-cases regen-opcode regen-opcode-targets regen-typeslots \ regen-token regen-ast regen-keyword regen-sre regen-frozen clinic \ regen-pegen-metaparser regen-pegen regen-test-frozenmain \ @@ -1351,7 +1375,7 @@ regen-pegen: -o $(srcdir)/Parser/parser.new.c $(UPDATE_FILE) $(srcdir)/Parser/parser.c $(srcdir)/Parser/parser.new.c -.PHONY=regen-ast +.PHONY: regen-ast regen-ast: # Regenerate 3 files using using Parser/asdl_c.py: # - Include/internal/pycore_ast.h @@ -1424,6 +1448,7 @@ regen-stdlib-module-names: all Programs/_testembed > $(srcdir)/Python/stdlib_module_names.h.new $(UPDATE_FILE) $(srcdir)/Python/stdlib_module_names.h $(srcdir)/Python/stdlib_module_names.h.new +.PHONY: regen-sre regen-sre: # Regenerate Modules/_sre/sre_constants.h and Modules/_sre/sre_targets.h # from Lib/re/_constants.py using Tools/build/generate_sre_constants.py @@ -1762,15 +1787,15 @@ TESTPYTHON= $(RUNSHARED) $(PYTHON_FOR_BUILD) $(TESTPYTHONOPTS) TESTRUNNER= $(TESTPYTHON) $(srcdir)/Tools/scripts/run_tests.py TESTTIMEOUT= 1200 -.PHONY: test testall testuniversal buildbottest pythoninfo - # Remove "test_python_*" directories of previous failed test jobs. # Pass TESTOPTS options because it can contain --tempdir option. +.PHONY: cleantest cleantest: all $(TESTRUNNER) $(TESTOPTS) --cleanup # Run a basic set of regression tests. # This excludes some tests that are particularly resource-intensive. +.PHONY: test test: all $(TESTRUNNER) $(TESTOPTS) @@ -1781,6 +1806,7 @@ test: all # the bytecode read from a .pyc file had the bug, sometimes the directly # generated bytecode. This is sometimes a very shy bug needing a lot of # sample data. +.PHONY: testall testall: all -find $(srcdir)/Lib -name '*.py[co]' -print | xargs rm -f $(TESTPYTHON) -E $(srcdir)/Lib/compileall.py @@ -1790,6 +1816,7 @@ testall: all # Run the test suite for both architectures in a Universal build on OSX. # Must be run on an Intel box. +.PHONY: testuniversal testuniversal: all @if [ `arch` != 'i386' ]; then \ echo "This can only be used on OSX/i386" ;\ @@ -1801,6 +1828,7 @@ testuniversal: all # Like testall, but with only one pass and without multiple processes. # Run an optional script to include information about the build environment. +.PHONY: buildbottest buildbottest: all - at if which pybuildbot.identify >/dev/null 2>&1; then \ pybuildbot.identify "CC='$(CC)'" "CXX='$(CXX)'"; \ @@ -1808,9 +1836,11 @@ buildbottest: all $(TESTRUNNER) -j 1 -u all -W --slowest --fail-env-changed --timeout=$(TESTTIMEOUT) $(TESTOPTS) # Like testall, but run Python tests with HOSTRUNNER directly. +.PHONY: hostrunnertest hostrunnertest: all $(RUNSHARED) $(HOSTRUNNER) ./$(BUILDPYTHON) -m test -u all $(TESTOPTS) +.PHONY: pythoninfo pythoninfo: all $(RUNSHARED) $(HOSTRUNNER) ./$(BUILDPYTHON) -m test.pythoninfo @@ -1820,14 +1850,17 @@ QUICKTESTOPTS= $(TESTOPTS) -x test_subprocess test_io test_lib2to3 \ test_multiprocessing_forkserver \ test_mailbox test_nntplib test_socket test_poll \ test_select test_zipfile test_concurrent_futures + +.PHONY: quicktest quicktest: all $(TESTRUNNER) $(QUICKTESTOPTS) # SSL tests -.PHONY: multisslcompile multissltest +.PHONY: multisslcompile multisslcompile: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/ssl/multissltests.py --steps=modules +.PHONY: multissltest multissltest: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/ssl/multissltests.py @@ -1835,6 +1868,7 @@ multissltest: all # prevent race conditions with PGO builds. PGO builds use recursive make, # which can lead to two parallel `./python setup.py build` processes that # step on each others toes. +.PHONY: install install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@ if test "x$(ENSUREPIP)" != "xno" ; then \ case $(ENSUREPIP) in \ @@ -1845,6 +1879,7 @@ install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKI $$ensurepip --root=$(DESTDIR)/ ; \ fi +.PHONY: altinstall altinstall: commoninstall if test "x$(ENSUREPIP)" != "xno" ; then \ case $(ENSUREPIP) in \ @@ -1855,6 +1890,7 @@ altinstall: commoninstall $$ensurepip --root=$(DESTDIR)/ ; \ fi +.PHONY: commoninstall commoninstall: check-clean-src @FRAMEWORKALTINSTALLFIRST@ \ altbininstall libinstall inclinstall libainstall \ sharedinstall altmaninstall \ @@ -1863,6 +1899,7 @@ commoninstall: check-clean-src @FRAMEWORKALTINSTALLFIRST@ \ # Install shared libraries enabled by Setup DESTDIRS= $(exec_prefix) $(LIBDIR) $(BINLIBDEST) $(DESTSHARED) +.PHONY: sharedinstall sharedinstall: all @for i in $(DESTDIRS); \ do \ @@ -1885,6 +1922,7 @@ sharedinstall: all # Install the interpreter with $(VERSION) affixed # This goes into $(exec_prefix) +.PHONY: altbininstall altbininstall: $(BUILDPYTHON) @FRAMEWORKPYTHONW@ @for i in $(BINDIR) $(LIBDIR); \ do \ @@ -1950,7 +1988,7 @@ altbininstall: $(BUILDPYTHON) @FRAMEWORKPYTHONW@ fi \ fi - +.PHONY: bininstall bininstall: altbininstall if test ! -d $(DESTDIR)$(LIBPC); then \ echo "Creating directory $(LIBPC)"; \ @@ -1991,6 +2029,7 @@ bininstall: altbininstall fi # Install the versioned manual page +.PHONY: altmaninstall altmaninstall: @for i in $(MANDIR) $(MANDIR)/man1; \ do \ @@ -2004,6 +2043,7 @@ altmaninstall: $(DESTDIR)$(MANDIR)/man1/python$(VERSION).1 # Install the unversioned manual page +.PHONY: maninstall maninstall: altmaninstall -rm -f $(DESTDIR)$(MANDIR)/man1/python3.1 (cd $(DESTDIR)$(MANDIR)/man1; $(LN) -s python$(VERSION).1 python3.1) @@ -2162,6 +2202,8 @@ TESTSUBDIRS= idlelib/idle_test \ COMPILEALL_OPTS=-j0 TEST_MODULES=@TEST_MODULES@ + +.PHONY: libinstall libinstall: all $(srcdir)/Modules/xxmodule.c @for i in $(SCRIPTDIR) $(LIBDEST); \ do \ @@ -2282,10 +2324,13 @@ $(SCRIPT_PYDOC): $(srcdir)/Tools/scripts/pydoc3 sed -e "s,/usr/bin/env python3,$(EXENAME)," < $(srcdir)/Tools/scripts/pydoc3 > $@ @chmod +x $@ +.PHONY: scripts scripts: $(SCRIPT_2TO3) $(SCRIPT_IDLE) $(SCRIPT_PYDOC) python-config # Install the include files INCLDIRSTOMAKE=$(INCLUDEDIR) $(CONFINCLUDEDIR) $(INCLUDEPY) $(CONFINCLUDEPY) + +.PHONY: inclinstall inclinstall: @for i in $(INCLDIRSTOMAKE); \ do \ @@ -2329,6 +2374,7 @@ LIBPL= @LIBPL@ # pkgconfig directory LIBPC= $(LIBDIR)/pkgconfig +.PHONY: libainstall libainstall: all scripts @for i in $(LIBDIR) $(LIBPL) $(LIBPC) $(BINDIR); \ do \ @@ -2392,6 +2438,7 @@ libainstall: all scripts # # This target is here for backward compatibility, previous versions of Python # hadn't integrated framework installation in the normal install process. +.PHONY: frameworkinstall frameworkinstall: install # On install, we re-make the framework @@ -2400,8 +2447,10 @@ frameworkinstall: install # automatically set prefix to the location deep down in the framework, so we # only have to cater for the structural bits of the framework. +.PHONY: frameworkinstallframework frameworkinstallframework: frameworkinstallstructure install frameworkinstallmaclib +.PHONY: frameworkinstallstructure frameworkinstallstructure: $(LDLIBRARY) @if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \ echo Not configured with --enable-framework; \ @@ -2426,6 +2475,7 @@ frameworkinstallstructure: $(LDLIBRARY) # This installs Mac/Lib into the framework # Install a number of symlinks to keep software that expects a normal unix # install (which includes python-config) happy. +.PHONY: frameworkinstallmaclib frameworkinstallmaclib: $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(LIBPL)/libpython$(LDVERSION).a" $(LN) -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(LIBPL)/libpython$(LDVERSION).dylib" @@ -2435,25 +2485,30 @@ frameworkinstallmaclib: $(LN) -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" # This installs the IDE, the Launcher and other apps into /Applications +.PHONY: frameworkinstallapps frameworkinstallapps: cd Mac && $(MAKE) installapps DESTDIR="$(DESTDIR)" # Build the bootstrap executable that will spawn the interpreter inside # an app bundle within the framework. This allows the interpreter to # run OS X GUI APIs. +.PHONY: frameworkpythonw frameworkpythonw: cd Mac && $(MAKE) pythonw # This installs the python* and other bin symlinks in $prefix/bin or in # a bin directory relative to the framework root +.PHONY: frameworkinstallunixtools frameworkinstallunixtools: cd Mac && $(MAKE) installunixtools DESTDIR="$(DESTDIR)" +.PHONY: frameworkaltinstallunixtools frameworkaltinstallunixtools: cd Mac && $(MAKE) altinstallunixtools DESTDIR="$(DESTDIR)" # This installs the Tools into the applications directory. # It is not part of a normal frameworkinstall +.PHONY: frameworkinstallextras frameworkinstallextras: cd Mac && $(MAKE) installextras DESTDIR="$(DESTDIR)" @@ -2483,11 +2538,13 @@ Python/dtoa.o: Python/dtoa.c $(CC) -c $(PY_CORE_CFLAGS) $(CFLAGS_ALIASING) -o $@ $< # Run reindent on the library +.PHONY: reindent reindent: ./$(BUILDPYTHON) $(srcdir)/Tools/patchcheck/reindent.py -r $(srcdir)/Lib # Rerun configure with the same options as it was run last time, # provided the config.status script exists +.PHONY: recheck recheck: ./config.status --recheck ./config.status @@ -2524,10 +2581,12 @@ TAGS:: # Sanitation targets -- clean leaves libraries, executables and tags # files, which clobber removes as well +.PHONY: pycremoval pycremoval: -find $(srcdir) -depth -name '__pycache__' -exec rm -rf {} ';' -find $(srcdir) -name '*.py[co]' -exec rm -f {} ';' +.PHONY: rmtestturds rmtestturds: -rm -f *BAD *GOOD *SKIPPED -rm -rf OUT @@ -2535,11 +2594,13 @@ rmtestturds: -rm -f *.txt -rm -f gb-18030-2000.xml +.PHONY: docclean docclean: $(MAKE) -C $(srcdir)/Doc clean # like the 'clean' target but retain the profile guided optimization (PGO) # data. The PGO data is only valid if source code remains unchanged. +.PHONY: clean-retain-profile clean-retain-profile: pycremoval find . -name '*.[oa]' -exec rm -f {} ';' find . -name '*.s[ol]' -exec rm -f {} ';' @@ -2563,6 +2624,7 @@ clean-retain-profile: pycremoval -rm -f Include/pydtrace_probes.h -rm -f profile-gen-stamp +.PHONY: profile-removal profile-removal: find . -name '*.gc??' -exec rm -f {} ';' find . -name '*.profclang?' -exec rm -f {} ';' @@ -2571,12 +2633,14 @@ profile-removal: rm -rf $(COVERAGE_REPORT) rm -f profile-run-stamp +.PHONY: clean clean: clean-retain-profile @if test @DEF_MAKE_ALL_RULE@ = profile-opt; then \ rm -f profile-gen-stamp profile-clean-stamp; \ $(MAKE) profile-removal; \ fi +.PHONY: clobber clobber: clean -rm -f $(BUILDPYTHON) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ tags TAGS \ @@ -2588,6 +2652,7 @@ clobber: clean # Make things extra clean, before making a distribution: # remove all generated files, even Makefile[.pre] # Keep configure and Python-ast.[ch], it's possible they can't be generated +.PHONY: distclean distclean: clobber docclean for file in $(srcdir)/Lib/test/data/* ; do \ if test "$$file" != "$(srcdir)/Lib/test/data/README"; then rm "$$file"; fi; \ @@ -2608,16 +2673,19 @@ distclean: clobber docclean -exec rm -f {} ';' # Check that all symbols exported by libpython start with "Py" or "_Py" +.PHONY: smelly smelly: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/smelly.py # Check if any unsupported C global variables have been added. +.PHONY: check-c-globals check-c-globals: $(PYTHON_FOR_REGEN) $(srcdir)/Tools/c-analyzer/check-c-globals.py \ --format summary \ --traceback # Find files with funny names +.PHONY: funny funny: find $(SUBDIRS) $(SUBDIRSTOO) \ -type d \ @@ -2649,9 +2717,11 @@ funny: -o -print # Perform some verification checks on any modified files. +.PHONY: patchcheck patchcheck: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/patchcheck/patchcheck.py +.PHONY: check-limited-abi check-limited-abi: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/stable_abi.py --all $(srcdir)/Misc/stable_abi.toml @@ -2665,19 +2735,6 @@ update-config: Python/thread.o: @THREADHEADERS@ $(srcdir)/Python/condvar.h -# Declare targets that aren't real files -.PHONY: all build_all build_wasm check-clean-src -.PHONY: sharedmods checksharedmods test quicktest rundsymutil -.PHONY: install altinstall sharedinstall bininstall altbininstall -.PHONY: maninstall libinstall inclinstall libainstall -.PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure -.PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools -.PHONY: frameworkaltinstallunixtools recheck clean clobber distclean -.PHONY: smelly funny patchcheck touch altmaninstall commoninstall -.PHONY: clean-retain-profile profile-removal run_profile_task -.PHONY: build_all_generate_profile build_all_merge_profile -.PHONY: gdbhooks scripts - ########################################################################## # Module dependencies and platform-specific files diff --git a/Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst b/Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst new file mode 100644 index 000000000000..1315b5cb3c19 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst @@ -0,0 +1 @@ +Define ``.PHONY`` / virtual make targets consistently and properly. From webhook-mailer at python.org Mon May 15 04:49:35 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 15 May 2023 08:49:35 -0000 Subject: [Python-checkins] gh-104050: Run mypy on `clinic.py` in CI (#104421) Message-ID: <mailman.366.1684140576.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9d41f83c58e6dc2fc6eb4b91f803551850b0adeb commit: 9d41f83c58e6dc2fc6eb4b91f803551850b0adeb branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-15T08:49:28Z summary: gh-104050: Run mypy on `clinic.py` in CI (#104421) * Add basic mypy workflow to CI * Make the type check pass --------- Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> Co-authored-by: Nikita Sobolev <mail at sobolevn.me> Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> files: A .github/workflows/mypy.yml A Tools/clinic/mypy.ini A Tools/clinic/requirements-dev.txt M .github/dependabot.yml M Tools/clinic/clinic.py M Tools/clinic/cpp.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 555e246e402b..f026b0f5f945 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,3 +12,10 @@ updates: update-types: - "version-update:semver-minor" - "version-update:semver-patch" + - package-ecosystem: "pip" + directory: "/Tools/clinic/" + schedule: + interval: "monthly" + labels: + - "skip issue" + - "skip news" diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml new file mode 100644 index 000000000000..1315bb5a966f --- /dev/null +++ b/.github/workflows/mypy.yml @@ -0,0 +1,39 @@ +# Workflow to run mypy on select parts of the CPython repo +name: mypy + +on: + push: + branches: + - main + pull_request: + paths: + - "Tools/clinic/**" + - ".github/workflows/mypy.yml" + workflow_dispatch: + +permissions: + contents: read + +env: + PIP_DISABLE_PIP_VERSION_CHECK: 1 + FORCE_COLOR: 1 + TERM: xterm-256color # needed for FORCE_COLOR to work on mypy on Ubuntu, see https://github.com/python/mypy/issues/13817 + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + mypy: + name: Run mypy on Tools/clinic/ + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout at v3 + - uses: actions/setup-python at v4 + with: + python-version: "3.x" + cache: pip + cache-dependency-path: Tools/clinic/requirements-dev.txt + - run: pip install -r Tools/clinic/requirements-dev.txt + - run: mypy --config-file Tools/clinic/mypy.ini diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 19c4cd299f0b..4270fb3cc566 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -7,6 +7,7 @@ import abc import ast +import builtins as bltns import collections import contextlib import copy @@ -26,7 +27,9 @@ import traceback import types +from collections.abc import Callable from types import * +from typing import Any, NamedTuple # TODO: # @@ -78,8 +81,13 @@ def __repr__(self): sig_end_marker = '--' +Appender = Callable[[str], None] +Outputter = Callable[[None], str] -_text_accumulator_nt = collections.namedtuple("_text_accumulator", "text append output") +class _TextAccumulator(NamedTuple): + text: list[str] + append: Appender + output: Outputter def _text_accumulator(): text = [] @@ -87,10 +95,12 @@ def output(): s = ''.join(text) text.clear() return s - return _text_accumulator_nt(text, text.append, output) + return _TextAccumulator(text, text.append, output) -text_accumulator_nt = collections.namedtuple("text_accumulator", "text append") +class TextAccumulator(NamedTuple): + text: list[str] + append: Appender def text_accumulator(): """ @@ -104,7 +114,7 @@ def text_accumulator(): empties the accumulator. """ text, append, output = _text_accumulator() - return text_accumulator_nt(append, output) + return TextAccumulator(append, output) def warn_or_fail(fail=False, *args, filename=None, line_number=None): @@ -1925,8 +1935,10 @@ def dump(self): # maps strings to Language objects. # "languages" maps the name of the language ("C", "Python"). # "extensions" maps the file extension ("c", "py"). +LangDict = dict[str, Callable[[str], Language]] + languages = { 'C': CLanguage, 'Python': PythonLanguage } -extensions = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } +extensions: LangDict = { name: CLanguage for name in "c cc cpp cxx h hh hpp hxx".split() } extensions['py'] = PythonLanguage @@ -2558,15 +2570,15 @@ class CConverter(metaclass=CConverterAutoRegister): """ # The C name to use for this variable. - name = None + name: str | None = None # The Python name to use for this variable. - py_name = None + py_name: str | None = None # The C type to use for this variable. # 'type' should be a Python string specifying the type, e.g. "int". # If this is a pointer type, the type string should end with ' *'. - type = None + type: str | None = None # The Python default value for this parameter, as a Python value. # Or the magic value "unspecified" if there is no default. @@ -2577,15 +2589,15 @@ class CConverter(metaclass=CConverterAutoRegister): # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) - default_type = None + default_type: bltns.type[Any] | tuple[bltns.type[Any], ...] | None = None # "default" converted into a C value, as a string. # Or None if there is no default. - c_default = None + c_default: str | None = None # "default" converted into a Python value, as a string. # Or None if there is no default. - py_default = None + py_default: str | None = None # The default value used to initialize the C variable when # there is no default, but not specifying a default may @@ -2597,14 +2609,14 @@ class CConverter(metaclass=CConverterAutoRegister): # # This value is specified as a string. # Every non-abstract subclass should supply a valid value. - c_ignored_default = 'NULL' + c_ignored_default: str = 'NULL' # If true, wrap with Py_UNUSED. unused = False # The C converter *function* to be used, if any. # (If this is not None, format_unit must be 'O&'.) - converter = None + converter: str | None = None # Should Argument Clinic add a '&' before the name of # the variable when passing it into the _impl function? @@ -3432,7 +3444,7 @@ class robuffer: pass def str_converter_key(types, encoding, zeroes): return (frozenset(types), bool(encoding), bool(zeroes)) -str_converter_argument_map = {} +str_converter_argument_map: dict[str, str] = {} class str_converter(CConverter): type = 'const char *' diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index 77f5f9696a6d..bc2cc713aac3 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,7 +1,12 @@ import re import sys +from collections.abc import Callable -def negate(condition): + +TokenAndCondition = tuple[str, str] +TokenStack = list[TokenAndCondition] + +def negate(condition: str) -> str: """ Returns a CPP conditional that is the opposite of the conditional passed in. """ @@ -22,17 +27,18 @@ class Monitor: Anyway this implementation seems to work well enough for the CPython sources. """ + is_a_simple_defined: Callable[[str], re.Match[str] | None] is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match - def __init__(self, filename=None, *, verbose=False): - self.stack = [] + def __init__(self, filename=None, *, verbose: bool = False): + self.stack: TokenStack = [] self.in_comment = False - self.continuation = None + self.continuation: str | None = None self.line_number = 0 self.filename = filename self.verbose = verbose - def __repr__(self): + def __repr__(self) -> str: return ''.join(( '<Monitor ', str(id(self)), @@ -40,10 +46,10 @@ def __repr__(self): " condition=", repr(self.condition()), ">")) - def status(self): + def status(self) -> str: return str(self.line_number).rjust(4) + ": " + self.condition() - def condition(self): + def condition(self) -> str: """ Returns the current preprocessor state, as a single #if condition. """ @@ -62,15 +68,15 @@ def close(self): if self.stack: self.fail("Ended file while still in a preprocessor conditional block!") - def write(self, s): + def write(self, s: str) -> None: for line in s.split("\n"): self.writeline(line) - def writeline(self, line): + def writeline(self, line: str) -> None: self.line_number += 1 line = line.strip() - def pop_stack(): + def pop_stack() -> TokenAndCondition: if not self.stack: self.fail("#" + token + " without matching #if / #ifdef / #ifndef!") return self.stack.pop() diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini new file mode 100644 index 000000000000..3c5643e789be --- /dev/null +++ b/Tools/clinic/mypy.ini @@ -0,0 +1,11 @@ +[mypy] +# make sure clinic can still be run on Python 3.10 +python_version = 3.10 +pretty = True +enable_error_code = ignore-without-code +disallow_any_generics = True +strict_concatenate = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_unused_configs = True +files = Tools/clinic/ diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt new file mode 100644 index 000000000000..7e0aa37a46d7 --- /dev/null +++ b/Tools/clinic/requirements-dev.txt @@ -0,0 +1,2 @@ +# Requirements file for external linters and checks we run on Tools/clinic/ in CI +mypy==1.2.0 From webhook-mailer at python.org Mon May 15 04:54:54 2023 From: webhook-mailer at python.org (terryjreedy) Date: Mon, 15 May 2023 08:54:54 -0000 Subject: [Python-checkins] gh-104494: Update certain Tkinter pack/place tests for Tk 8.7 errors (#104495) Message-ID: <mailman.367.1684140894.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3cba61f111db9b5e8ef35632915309f81fff8c6c commit: 3cba61f111db9b5e8ef35632915309f81fff8c6c branch: main author: Christopher Chavez <chrischavez at gmx.us> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-15T04:54:41-04:00 summary: gh-104494: Update certain Tkinter pack/place tests for Tk 8.7 errors (#104495) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst M Lib/test/test_tkinter/test_geometry_managers.py diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index 3663048a145a..59fe592b492a 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -108,8 +108,8 @@ def test_pack_configure_in(self): a.pack_configure(in_=c) self.assertEqual(pack.pack_slaves(), [b, c, d]) self.assertEqual(c.pack_slaves(), [a]) - with self.assertRaisesRegex(TclError, - 'can\'t pack %s inside itself' % (a,)): + with self.assertRaisesRegex( + TclError, """can't pack "?%s"? inside itself""" % (a,)): a.pack_configure(in_=a) with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): a.pack_configure(in_='.foo') @@ -292,8 +292,10 @@ def create2(self): def test_place_configure_in(self): t, f, f2 = self.create2() self.assertEqual(f2.winfo_manager(), '') - with self.assertRaisesRegex(TclError, "can't place %s relative to " - "itself" % re.escape(str(f2))): + with self.assertRaisesRegex( + TclError, + """can't place "?%s"? relative to itself""" + % re.escape(str(f2))): f2.place_configure(in_=f2) self.assertEqual(f2.winfo_manager(), '') with self.assertRaisesRegex(TclError, 'bad window path name'): diff --git a/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst b/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst new file mode 100644 index 000000000000..a320c48428b5 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst @@ -0,0 +1,2 @@ +Update ``test_pack_configure_in`` and ``test_place_configure_in`` +for changes to error message formatting in Tk 8.7. From webhook-mailer at python.org Mon May 15 05:15:15 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 15 May 2023 09:15:15 -0000 Subject: [Python-checkins] [3.11] gh-67056: document that registering/unregistering an atexit func from within an atexit func is undefined (GH-104473) (#104500) Message-ID: <mailman.368.1684142116.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a712c5f42d5904e1a1cdaf11bd1f05852cfdd830 commit: a712c5f42d5904e1a1cdaf11bd1f05852cfdd830 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-15T10:15:07+01:00 summary: [3.11] gh-67056: document that registering/unregistering an atexit func from within an atexit func is undefined (GH-104473) (#104500) files: A Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst M Doc/library/atexit.rst diff --git a/Doc/library/atexit.rst b/Doc/library/atexit.rst index f7f038107d11..a2bd85b31c9a 100644 --- a/Doc/library/atexit.rst +++ b/Doc/library/atexit.rst @@ -20,6 +20,9 @@ at interpreter termination time they will be run in the order ``C``, ``B``, program is killed by a signal not handled by Python, when a Python fatal internal error is detected, or when :func:`os._exit` is called. +**Note:** The effect of registering or unregistering functions from within +a cleanup function is undefined. + .. versionchanged:: 3.7 When used with C-API subinterpreters, registered functions are local to the interpreter they were registered in. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst b/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst new file mode 100644 index 000000000000..2c6ef1781072 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst @@ -0,0 +1,2 @@ +Document that the effect of registering or unregistering an :mod:`atexit` +cleanup function from within a registered cleanup function is undefined. From webhook-mailer at python.org Mon May 15 05:17:56 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 15 May 2023 09:17:56 -0000 Subject: [Python-checkins] Bump mypy from 1.2.0 to 1.3.0 in /Tools/clinic (#104501) Message-ID: <mailman.369.1684142277.13550.python-checkins@python.org> https://github.com/python/cpython/commit/35bf0916d913b83cf1883b76e67ad8b1c9a25bbe commit: 35bf0916d913b83cf1883b76e67ad8b1c9a25bbe branch: main author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-15T09:17:48Z summary: Bump mypy from 1.2.0 to 1.3.0 in /Tools/clinic (#104501) build(deps-dev): bump mypy from 1.2.0 to 1.3.0 in /Tools/clinic Bumps [mypy](https://github.com/python/mypy) from 1.2.0 to 1.3.0. - [Commits](https://github.com/python/mypy/compare/v1.2.0...v1.3.0) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support at github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> files: M Tools/clinic/requirements-dev.txt diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt index 7e0aa37a46d7..154934003c31 100644 --- a/Tools/clinic/requirements-dev.txt +++ b/Tools/clinic/requirements-dev.txt @@ -1,2 +1,2 @@ # Requirements file for external linters and checks we run on Tools/clinic/ in CI -mypy==1.2.0 +mypy==1.3.0 From webhook-mailer at python.org Mon May 15 05:26:44 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Mon, 15 May 2023 09:26:44 -0000 Subject: [Python-checkins] gh-101819: Isolate `_io` (#101948) Message-ID: <mailman.370.1684142806.13550.python-checkins@python.org> https://github.com/python/cpython/commit/186bf39f5c6003912e4f445430c504db51b9a743 commit: 186bf39f5c6003912e4f445430c504db51b9a743 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-15T09:26:27Z summary: gh-101819: Isolate `_io` (#101948) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner at python.org> files: A Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst M Lib/test/test_io.py M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/bufferedio.c M Modules/_io/bytesio.c M Modules/_io/fileio.c M Modules/_io/iobase.c M Modules/_io/stringio.c M Modules/_io/textio.c M Modules/_io/winconsoleio.c M Python/pylifecycle.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 9bcc92a40c61..cc16804fe218 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -4242,6 +4242,7 @@ def test_warn_on_dealloc_fd(self): def test_pickling(self): # Pickling file objects is forbidden + msg = "cannot pickle" for kwargs in [ {"mode": "w"}, {"mode": "wb"}, @@ -4256,8 +4257,10 @@ def test_pickling(self): if "b" not in kwargs["mode"]: kwargs["encoding"] = "utf-8" for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - with self.open(os_helper.TESTFN, **kwargs) as f: - self.assertRaises(TypeError, pickle.dumps, f, protocol) + with self.subTest(protocol=protocol, kwargs=kwargs): + with self.open(os_helper.TESTFN, **kwargs) as f: + with self.assertRaisesRegex(TypeError, msg): + pickle.dumps(f, protocol) @unittest.skipIf( support.is_emscripten, "fstat() of a pipe fd is not supported" diff --git a/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst b/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst new file mode 100644 index 000000000000..4a73bbf32b37 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst @@ -0,0 +1,2 @@ +Isolate the :mod:`io` extension module by applying :pep:`687`. Patch by +Kumar Aditya, Victor Stinner, and Erlend E. Aasland. diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 2457cb124036..7b06c1bee5a8 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -561,25 +561,9 @@ PyNumber_AsOff_t(PyObject *item, PyObject *err) return result; } -_PyIO_State * -_PyIO_get_module_state(void) -{ - PyObject *mod = PyState_FindModule(&_PyIO_Module); - _PyIO_State *state; - if (mod == NULL || (state = get_io_state(mod)) == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "could not find io module state " - "(interpreter shutdown?)"); - return NULL; - } - return state; -} - static int iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { _PyIO_State *state = get_io_state(mod); - if (!state->initialized) - return 0; Py_VISIT(state->unsupported_operation); Py_VISIT(state->PyIOBase_Type); @@ -606,8 +590,6 @@ iomodule_traverse(PyObject *mod, visitproc visit, void *arg) { static int iomodule_clear(PyObject *mod) { _PyIO_State *state = get_io_state(mod); - if (!state->initialized) - return 0; Py_CLEAR(state->unsupported_operation); Py_CLEAR(state->PyIOBase_Type); @@ -652,115 +634,57 @@ static PyMethodDef module_methods[] = { {NULL, NULL} }; -struct PyModuleDef _PyIO_Module = { - PyModuleDef_HEAD_INIT, - "io", - module_doc, - sizeof(_PyIO_State), - module_methods, - NULL, - iomodule_traverse, - iomodule_clear, - (freefunc)iomodule_free, -}; - - -static PyTypeObject* static_types[] = { - // Base classes - &PyIOBase_Type, - - // PyIOBase_Type subclasses - &PyBufferedIOBase_Type, - &PyRawIOBase_Type, - &PyTextIOBase_Type, -}; - - -PyStatus -_PyIO_InitTypes(PyInterpreterState *interp) -{ - for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { - PyTypeObject *type = static_types[i]; - if (_PyStaticType_InitBuiltin(interp, type) < 0) { - return _PyStatus_ERR("Can't initialize builtin type"); - } - } - - return _PyStatus_OK(); -} - -void -_PyIO_FiniTypes(PyInterpreterState *interp) -{ - // Deallocate types in the reverse order to deallocate subclasses before - // their base classes. - for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { - PyTypeObject *type = static_types[i]; - _PyStaticType_Dealloc(interp, type); - } -} - #define ADD_TYPE(module, type, spec, base) \ do { \ type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \ (PyObject *)base); \ if (type == NULL) { \ - goto fail; \ + return -1; \ } \ if (PyModule_AddType(module, type) < 0) { \ - goto fail; \ + return -1; \ } \ } while (0) -PyMODINIT_FUNC -PyInit__io(void) +static int +iomodule_exec(PyObject *m) { - PyObject *m = PyModule_Create(&_PyIO_Module); - _PyIO_State *state = NULL; - if (m == NULL) - return NULL; - state = get_io_state(m); - state->initialized = 0; + _PyIO_State *state = get_io_state(m); /* DEFAULT_BUFFER_SIZE */ if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0) - goto fail; + return -1; /* UnsupportedOperation inherits from ValueError and OSError */ state->unsupported_operation = PyObject_CallFunction( (PyObject *)&PyType_Type, "s(OO){}", "UnsupportedOperation", PyExc_OSError, PyExc_ValueError); if (state->unsupported_operation == NULL) - goto fail; + return -1; if (PyModule_AddObjectRef(m, "UnsupportedOperation", state->unsupported_operation) < 0) { - goto fail; + return -1; } /* BlockingIOError, for compatibility */ if (PyModule_AddObjectRef(m, "BlockingIOError", (PyObject *) PyExc_BlockingIOError) < 0) { - goto fail; - } - - // Add types - for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { - PyTypeObject *type = static_types[i]; - if (PyModule_AddType(m, type) < 0) { - goto fail; - } + return -1; } // Base classes - state->PyIOBase_Type = (PyTypeObject *)Py_NewRef(&PyIOBase_Type); ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL); ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL); + ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL); // PyIOBase_Type subclasses - state->PyRawIOBase_Type = (PyTypeObject *)Py_NewRef(&PyRawIOBase_Type); - state->PyBufferedIOBase_Type = (PyTypeObject *)Py_NewRef(&PyBufferedIOBase_Type); - state->PyTextIOBase_Type = (PyTypeObject *)Py_NewRef(&PyTextIOBase_Type); + ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec, + state->PyIOBase_Type); + ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec, + state->PyIOBase_Type); + ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec, + state->PyIOBase_Type); // PyBufferedIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type); @@ -775,6 +699,7 @@ PyInit__io(void) // PyRawIOBase_Type(PyIOBase_Type) subclasses ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type); + #ifdef HAVE_WINDOWS_CONSOLE_IO ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec, state->PyRawIOBase_Type); @@ -785,11 +710,30 @@ PyInit__io(void) ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec, state->PyTextIOBase_Type); - state->initialized = 1; +#undef ADD_TYPE + return 0; +} - return m; +static struct PyModuleDef_Slot iomodule_slots[] = { + {Py_mod_exec, iomodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; - fail: - Py_DECREF(m); - return NULL; +struct PyModuleDef _PyIO_Module = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "io", + .m_doc = module_doc, + .m_size = sizeof(_PyIO_State), + .m_methods = module_methods, + .m_traverse = iomodule_traverse, + .m_clear = iomodule_clear, + .m_free = iomodule_free, + .m_slots = iomodule_slots, +}; + +PyMODINIT_FUNC +PyInit__io(void) +{ + return PyModuleDef_Init(&_PyIO_Module); } diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index ae06fecc48b4..afd638a120ba 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -8,13 +8,8 @@ #include "pycore_typeobject.h" // _PyType_GetModuleState() #include "structmember.h" -/* ABCs */ -extern PyTypeObject PyIOBase_Type; -extern PyTypeObject PyRawIOBase_Type; -extern PyTypeObject PyBufferedIOBase_Type; -extern PyTypeObject PyTextIOBase_Type; - /* Type specs */ +extern PyType_Spec bufferediobase_spec; extern PyType_Spec bufferedrandom_spec; extern PyType_Spec bufferedreader_spec; extern PyType_Spec bufferedrwpair_spec; @@ -22,8 +17,11 @@ extern PyType_Spec bufferedwriter_spec; extern PyType_Spec bytesio_spec; extern PyType_Spec bytesiobuf_spec; extern PyType_Spec fileio_spec; +extern PyType_Spec iobase_spec; extern PyType_Spec nldecoder_spec; +extern PyType_Spec rawiobase_spec; extern PyType_Spec stringio_spec; +extern PyType_Spec textiobase_spec; extern PyType_Spec textiowrapper_spec; #ifdef HAVE_WINDOWS_CONSOLE_IO @@ -168,9 +166,6 @@ struct _io_state { #endif }; -#define IO_MOD_STATE(mod) ((_PyIO_State *)PyModule_GetState(mod)) -#define IO_STATE() _PyIO_get_module_state() - static inline _PyIO_State * get_io_state(PyObject *module) { @@ -195,7 +190,7 @@ find_io_state_by_def(PyTypeObject *type) return get_io_state(mod); } -extern _PyIO_State *_PyIO_get_module_state(void); +extern PyObject *_PyIOBase_cannot_pickle(PyObject *self, PyObject *args); #ifdef HAVE_WINDOWS_CONSOLE_IO extern char _PyIO_get_console_type(PyObject *); diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 00e228bca437..d5cc047bd8d5 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -16,14 +16,14 @@ /*[clinic input] module _io -class _io._BufferedIOBase "PyObject *" "&PyBufferedIOBase_Type" -class _io._Buffered "buffered *" "&PyBufferedIOBase_Type" +class _io._BufferedIOBase "PyObject *" "clinic_state()->PyBufferedIOBase_Type" +class _io._Buffered "buffered *" "clinic_state()->PyBufferedIOBase_Type" class _io.BufferedReader "buffered *" "clinic_state()->PyBufferedReader_Type" class _io.BufferedWriter "buffered *" "clinic_state()->PyBufferedWriter_Type" class _io.BufferedRWPair "rwpair *" "clinic_state()->PyBufferedRWPair_Type" class _io.BufferedRandom "buffered *" "clinic_state()->PyBufferedRandom_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=abd685b9d94b9888]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=3b3ef9cbbbad4590]*/ /* * BufferedIOBase class, inherits from IOBase. @@ -128,7 +128,7 @@ static PyObject * _io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls) /*[clinic end generated code: output=b87b135d67cd4448 input=0b61a7b4357c1ea7]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "detach"); } @@ -162,7 +162,7 @@ _io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=4521b30940fd7b67 input=390205758adc8510]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "read"); } @@ -184,7 +184,7 @@ _io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=636fd241c21e050a input=ef546a1238c5b41c]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "read1"); } @@ -209,7 +209,7 @@ _io__BufferedIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=d51feea4bcac9892 input=f79b72c4dccb3dc2]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "write"); } @@ -394,6 +394,15 @@ _enter_buffered_busy(buffered *self) (self->buffer_size * (size / self->buffer_size))) +static int +buffered_clear(buffered *self) +{ + self->ok = 0; + Py_CLEAR(self->raw); + Py_CLEAR(self->dict); + return 0; +} + static void buffered_dealloc(buffered *self) { @@ -405,7 +414,6 @@ buffered_dealloc(buffered *self) self->ok = 0; if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); - Py_CLEAR(self->raw); if (self->buffer) { PyMem_Free(self->buffer); self->buffer = NULL; @@ -414,7 +422,7 @@ buffered_dealloc(buffered *self) PyThread_free_lock(self->lock); self->lock = NULL; } - Py_CLEAR(self->dict); + (void)buffered_clear(self); tp->tp_free((PyObject *)self); Py_DECREF(tp); } @@ -443,15 +451,6 @@ buffered_traverse(buffered *self, visitproc visit, void *arg) return 0; } -static int -buffered_clear(buffered *self) -{ - self->ok = 0; - Py_CLEAR(self->raw); - Py_CLEAR(self->dict); - return 0; -} - /* Because this can call arbitrary code, it shouldn't be called when the refcount is 0 (that is, not directly from tp_dealloc unless the refcount has been temporarily re-incremented). */ @@ -2220,6 +2219,8 @@ bufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); + Py_VISIT(self->reader); + Py_VISIT(self->writer); return 0; } @@ -2239,9 +2240,7 @@ bufferedrwpair_dealloc(rwpair *self) _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); - Py_CLEAR(self->reader); - Py_CLEAR(self->writer); - Py_CLEAR(self->dict); + (void)bufferedrwpair_clear(self); tp->tp_free((PyObject *) self); Py_DECREF(tp); } @@ -2424,6 +2423,12 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, #include "clinic/bufferedio.c.h" #undef clinic_state +static int +bufferediobase_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} static PyMethodDef bufferediobase_methods[] = { _IO__BUFFEREDIOBASE_DETACH_METHODDEF @@ -2435,57 +2440,19 @@ static PyMethodDef bufferediobase_methods[] = { {NULL, NULL} }; -PyTypeObject PyBufferedIOBase_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._BufferedIOBase", /*tp_name*/ - 0, /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*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, /*tp_flags*/ - bufferediobase_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - bufferediobase_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyIOBase_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot bufferediobase_slots[] = { + {Py_tp_doc, (void *)bufferediobase_doc}, + {Py_tp_methods, bufferediobase_methods}, + {Py_tp_traverse, bufferediobase_traverse}, + {0, NULL}, }; +PyType_Spec bufferediobase_spec = { + .name = "_io._BufferedIOBase", + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = bufferediobase_slots, +}; static PyMethodDef bufferedreader_methods[] = { /* BufferedIOMixin methods */ @@ -2508,6 +2475,9 @@ static PyMethodDef bufferedreader_methods[] = { _IO__BUFFERED_TELL_METHODDEF _IO__BUFFERED_TRUNCATE_METHODDEF _IO__BUFFERED___SIZEOF___METHODDEF + + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; @@ -2565,6 +2535,9 @@ static PyMethodDef bufferedwriter_methods[] = { _IO__BUFFERED_SEEK_METHODDEF _IO__BUFFERED_TELL_METHODDEF _IO__BUFFERED___SIZEOF___METHODDEF + + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; @@ -2680,6 +2653,9 @@ static PyMethodDef bufferedrandom_methods[] = { _IO__BUFFERED_PEEK_METHODDEF _IO_BUFFEREDWRITER_WRITE_METHODDEF _IO__BUFFERED___SIZEOF___METHODDEF + + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 3fddfc2ed0bc..807730586932 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -979,6 +979,7 @@ bytesio_traverse(bytesio *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); + Py_VISIT(self->buf); return 0; } @@ -986,6 +987,7 @@ static int bytesio_clear(bytesio *self) { Py_CLEAR(self->dict); + Py_CLEAR(self->buf); return 0; } diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 473f0a8a6bef..30944fc56bf7 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -536,7 +536,7 @@ fileio_dealloc(fileio *self) _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); - Py_CLEAR(self->dict); + (void)fileio_clear(self); tp->tp_free((PyObject *)self); Py_DECREF(tp); } @@ -1166,6 +1166,8 @@ static PyMethodDef fileio_methods[] = { _IO_FILEIO_FILENO_METHODDEF _IO_FILEIO_ISATTY_METHODDEF {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 26f2a3155bda..764c5fb33200 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -17,10 +17,10 @@ /*[clinic input] module _io -class _io._IOBase "PyObject *" "&PyIOBase_Type" -class _io._RawIOBase "PyObject *" "&PyRawIOBase_Type" +class _io._IOBase "PyObject *" "clinic_state()->PyIOBase_Type" +class _io._RawIOBase "PyObject *" "clinic_state()->PyRawIOBase_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d29a4d076c2b211c]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9006b7802ab8ea85]*/ /* * IOBase class, an abstract class @@ -101,7 +101,7 @@ static PyObject * _io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=1dd694ac9de260fa input=ebb5476eb22fc5d4]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "seek"); } @@ -134,7 +134,7 @@ static PyObject * _io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=b7eed4649cbe22c1 input=ad90582a1d8b5cc9]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "truncate"); } @@ -220,24 +220,32 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args) static PyObject * iobase_check_seekable(PyObject *self, PyObject *args) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); return _PyIOBase_check_seekable(state, self, args); } static PyObject * iobase_check_readable(PyObject *self, PyObject *args) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); return _PyIOBase_check_readable(state, self, args); } static PyObject * iobase_check_writable(PyObject *self, PyObject *args) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); return _PyIOBase_check_writable(state, self, args); } +PyObject * +_PyIOBase_cannot_pickle(PyObject *self, PyObject *args) +{ + PyErr_Format(PyExc_TypeError, + "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self))); + return NULL; +} + /* XXX: IOBase thinks it has to maintain its own internal state in `__IOBase_closed` and call flush() by itself, but it is redundant with whatever behaviour a non-trivial derived class will implement. */ @@ -351,6 +359,7 @@ _PyIOBase_finalize(PyObject *self) static int iobase_traverse(iobase *self, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(self)); Py_VISIT(self->dict); return 0; } @@ -380,11 +389,13 @@ iobase_dealloc(iobase *self) } return; } + PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); Py_CLEAR(self->dict); - Py_TYPE(self)->tp_free((PyObject *) self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } /* Inquiry methods */ @@ -523,7 +534,7 @@ static PyObject * _io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls) /*[clinic end generated code: output=7caaa32a6f4ada3d input=1927c8bea5c85099]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "fileno"); } @@ -821,7 +832,9 @@ _io__IOBase_writelines(PyObject *self, PyObject *lines) Py_RETURN_NONE; } +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/iobase.c.h" +#undef clinic_state static PyMethodDef iobase_methods[] = { _IO__IOBASE_SEEK_METHODDEF @@ -858,59 +871,34 @@ static PyGetSetDef iobase_getset[] = { {NULL} }; +static struct PyMemberDef iobase_members[] = { + {"__weaklistoffset__", T_PYSSIZET, offsetof(iobase, weakreflist), READONLY}, + {"__dictoffset__", T_PYSSIZET, offsetof(iobase, dict), READONLY}, + {NULL}, +}; + -PyTypeObject PyIOBase_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._IOBase", /*tp_name*/ - sizeof(iobase), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)iobase_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, /*tp_flags*/ - iobase_doc, /* tp_doc */ - (traverseproc)iobase_traverse, /* tp_traverse */ - (inquiry)iobase_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(iobase, weakreflist), /* tp_weaklistoffset */ - iobase_iter, /* tp_iter */ - iobase_iternext, /* tp_iternext */ - iobase_methods, /* tp_methods */ - 0, /* tp_members */ - iobase_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(iobase, dict), /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - 0, /* 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 */ - iobase_finalize, /* tp_finalize */ +static PyType_Slot iobase_slots[] = { + {Py_tp_dealloc, iobase_dealloc}, + {Py_tp_doc, (void *)iobase_doc}, + {Py_tp_traverse, iobase_traverse}, + {Py_tp_clear, iobase_clear}, + {Py_tp_iter, iobase_iter}, + {Py_tp_iternext, iobase_iternext}, + {Py_tp_methods, iobase_methods}, + {Py_tp_members, iobase_members}, + {Py_tp_getset, iobase_getset}, + {Py_tp_finalize, iobase_finalize}, + {0, NULL}, }; +PyType_Spec iobase_spec = { + .name = "_io._IOBase", + .basicsize = sizeof(iobase), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = iobase_slots, +}; /* * RawIOBase class, Inherits from IOBase. @@ -1045,6 +1033,13 @@ rawiobase_write(PyObject *self, PyObject *args) return NULL; } +static int +rawiobase_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static PyMethodDef rawiobase_methods[] = { _IO__RAWIOBASE_READ_METHODDEF _IO__RAWIOBASE_READALL_METHODDEF @@ -1053,53 +1048,16 @@ static PyMethodDef rawiobase_methods[] = { {NULL, NULL} }; -PyTypeObject PyRawIOBase_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._RawIOBase", /*tp_name*/ - 0, /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*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, /*tp_flags*/ - rawiobase_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - rawiobase_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyIOBase_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot rawiobase_slots[] = { + {Py_tp_doc, (void *)rawiobase_doc}, + {Py_tp_methods, rawiobase_methods}, + {Py_tp_traverse, rawiobase_traverse}, + {0, NULL}, +}; + +PyType_Spec rawiobase_spec = { + .name = "_io._RawIOBase", + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = rawiobase_slots, }; diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 13d3b870b39a..3eb25704b4aa 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -583,6 +583,9 @@ static int stringio_traverse(stringio *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->readnl); + Py_VISIT(self->writenl); + Py_VISIT(self->decoder); Py_VISIT(self->dict); return 0; } @@ -590,6 +593,9 @@ stringio_traverse(stringio *self, visitproc visit, void *arg) static int stringio_clear(stringio *self) { + Py_CLEAR(self->readnl); + Py_CLEAR(self->writenl); + Py_CLEAR(self->decoder); Py_CLEAR(self->dict); return 0; } @@ -605,10 +611,7 @@ stringio_dealloc(stringio *self) self->buf = NULL; } _PyUnicodeWriter_Dealloc(&self->writer); - Py_CLEAR(self->readnl); - Py_CLEAR(self->writenl); - Py_CLEAR(self->decoder); - Py_CLEAR(self->dict); + (void)stringio_clear(self); if (self->weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) self); } diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 3cc292cc3510..81dd3bed005a 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -62,7 +62,7 @@ static PyObject * _io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls) /*[clinic end generated code: output=50915f40c609eaa4 input=987ca3640d0a3776]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "detach"); } @@ -82,7 +82,7 @@ static PyObject * _io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=3adf28998831f461 input=cee1e84664a20de0]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "read"); } @@ -102,7 +102,7 @@ _io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=3073a948d02319f3 input=58f801259f7ff3ef]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "readline"); } @@ -122,7 +122,7 @@ static PyObject * _io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic end generated code: output=5d985eb529472bc4 input=21b6961b5cba9496]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "write"); } @@ -164,6 +164,12 @@ textiobase_errors_get(PyObject *self, void *context) Py_RETURN_NONE; } +static int +textiobase_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} static PyMethodDef textiobase_methods[] = { _IO__TEXTIOBASE_DETACH_METHODDEF @@ -180,57 +186,20 @@ static PyGetSetDef textiobase_getset[] = { {NULL} }; -PyTypeObject PyTextIOBase_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._TextIOBase", /*tp_name*/ - 0, /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*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, /*tp_flags*/ - textiobase_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - textiobase_methods, /* tp_methods */ - 0, /* tp_members */ - textiobase_getset, /* tp_getset */ - &PyIOBase_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* 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 */ - 0, /* tp_finalize */ +static PyType_Slot textiobase_slots[] = { + {Py_tp_doc, (void *)textiobase_doc}, + {Py_tp_methods, textiobase_methods}, + {Py_tp_getset, textiobase_getset}, + {Py_tp_traverse, textiobase_traverse}, + {0, NULL}, }; +PyType_Spec textiobase_spec = { + .name = "_io._TextIOBase", + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = textiobase_slots, +}; /* IncrementalNewlineDecoder */ @@ -1456,7 +1425,7 @@ textiowrapper_dealloc(textio *self) _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *)self); - textiowrapper_clear(self); + (void)textiowrapper_clear(self); tp->tp_free((PyObject *)self); Py_DECREF(tp); } @@ -3267,6 +3236,9 @@ static PyMethodDef textiowrapper_methods[] = { _IO_TEXTIOWRAPPER_SEEK_METHODDEF _IO_TEXTIOWRAPPER_TELL_METHODDEF _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF + + {"__reduce__", _PyIOBase_cannot_pickle, METH_VARARGS}, + {"__reduce_ex__", _PyIOBase_cannot_pickle, METH_VARARGS}, {NULL, NULL} }; diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index d65e247737a0..15f3053957da 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -1096,7 +1096,7 @@ _io__WindowsConsoleIO_isatty_impl(winconsoleio *self) Py_RETURN_TRUE; } -#define clinic_state() (IO_STATE()) +#define clinic_state() (find_io_state_by_def(Py_TYPE(self))) #include "clinic/winconsoleio.c.h" #undef clinic_state diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 61f87c5eba60..c5dc0f44a380 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -29,9 +29,6 @@ #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" -extern PyStatus _PyIO_InitTypes(PyInterpreterState *interp); -extern void _PyIO_FiniTypes(PyInterpreterState *interp); - #include <locale.h> // setlocale() #include <stdlib.h> // getenv() @@ -706,11 +703,6 @@ pycore_init_types(PyInterpreterState *interp) return _PyStatus_ERR("failed to initialize an exception type"); } - status = _PyIO_InitTypes(interp); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - status = _PyExc_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1667,8 +1659,6 @@ flush_std_files(void) static void finalize_interp_types(PyInterpreterState *interp) { - _PyIO_FiniTypes(interp); - _PyUnicode_FiniTypes(interp); _PySys_FiniTypes(interp); _PyExc_Fini(interp); diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 8afa92ef25d3..9863acdade30 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -317,10 +317,6 @@ Python/instrumentation.c - _PyInstrumentation_MISSING - ##----------------------- ## static types -Modules/_io/bufferedio.c - PyBufferedIOBase_Type - -Modules/_io/iobase.c - PyIOBase_Type - -Modules/_io/iobase.c - PyRawIOBase_Type - -Modules/_io/textio.c - PyTextIOBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorBase_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorDerived_Type - Modules/_testcapi/vectorcall.c - MethodDescriptorNopGet_Type - From webhook-mailer at python.org Mon May 15 07:22:13 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 15 May 2023 11:22:13 -0000 Subject: [Python-checkins] gh-101819: Fix _io clinic input for unused base class method stubs (#104418) Message-ID: <mailman.371.1684149733.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b378d991f8cd41c33416e590cb83472cce1d6b98 commit: b378d991f8cd41c33416e590cb83472cce1d6b98 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-15T13:21:38+02:00 summary: gh-101819: Fix _io clinic input for unused base class method stubs (#104418) When preparing the _io extension module for isolation, many methods were adapted to Argument Clinic. Some of these used the '*args: object' signature, which is incorrect. These are now corrected to an exact signature, and marked unused, since they are stub methods. files: M Modules/_io/bufferedio.c M Modules/_io/clinic/bufferedio.c.h M Modules/_io/clinic/iobase.c.h M Modules/_io/clinic/textio.c.h M Modules/_io/iobase.c M Modules/_io/textio.c diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index d5cc047bd8d5..6f291c344960 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -136,15 +136,15 @@ _io__BufferedIOBase_detach_impl(PyObject *self, PyTypeObject *cls) _io._BufferedIOBase.read cls: defining_class + size: int(unused=True) = -1 / - *args: object Read and return up to n bytes. -If the argument is omitted, None, or negative, read and +If the size argument is omitted, None, or negative, read and return all data until EOF. -If the argument is positive, and the underlying raw stream is +If the size argument is positive, and the underlying raw stream is not 'interactive', multiple raw reads may be issued to satisfy the byte count (unless EOF is reached first). However, for interactive raw streams (as well as sockets and pipes), @@ -159,8 +159,8 @@ mode and no data is available at the moment. static PyObject * _io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=4521b30940fd7b67 input=390205758adc8510]*/ + int Py_UNUSED(size)) +/*[clinic end generated code: output=aceb2765587b0a29 input=824f6f910465e61a]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "read"); @@ -170,10 +170,10 @@ _io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls, _io._BufferedIOBase.read1 cls: defining_class + size: int(unused=True) = -1 / - *args: object -Read and return up to n bytes, with at most one read() call to the underlying raw stream. +Read and return up to size bytes, with at most one read() call to the underlying raw stream. Return an empty bytes object on EOF. A short result does not imply that EOF is imminent. @@ -181,8 +181,8 @@ A short result does not imply that EOF is imminent. static PyObject * _io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=636fd241c21e050a input=ef546a1238c5b41c]*/ + int Py_UNUSED(size)) +/*[clinic end generated code: output=2e7fc62972487eaa input=af76380e020fd9e6]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "read1"); @@ -192,10 +192,10 @@ _io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls, _io._BufferedIOBase.write cls: defining_class + b: object(unused=True) / - *args: object -Write the given buffer to the IO stream. +Write buffer b to the IO stream. Return the number of bytes written, which is always the length of b in bytes. @@ -206,8 +206,8 @@ underlying raw stream cannot accept more data at the moment. static PyObject * _io__BufferedIOBase_write_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=d51feea4bcac9892 input=f79b72c4dccb3dc2]*/ + PyObject *Py_UNUSED(b)) +/*[clinic end generated code: output=712c635246bf2306 input=9793f5c8f71029ad]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return bufferediobase_unsupported(state, "write"); diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index e2ac90c54a10..4f40fdadf8ec 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -108,15 +108,15 @@ _io__BufferedIOBase_detach(PyObject *self, PyTypeObject *cls, PyObject *const *a } PyDoc_STRVAR(_io__BufferedIOBase_read__doc__, -"read($self, /, *args)\n" +"read($self, size=-1, /)\n" "--\n" "\n" "Read and return up to n bytes.\n" "\n" -"If the argument is omitted, None, or negative, read and\n" +"If the size argument is omitted, None, or negative, read and\n" "return all data until EOF.\n" "\n" -"If the argument is positive, and the underlying raw stream is\n" +"If the size argument is positive, and the underlying raw stream is\n" "not \'interactive\', multiple raw reads may be issued to satisfy\n" "the byte count (unless EOF is reached first).\n" "However, for interactive raw streams (as well as sockets and pipes),\n" @@ -133,7 +133,7 @@ PyDoc_STRVAR(_io__BufferedIOBase_read__doc__, static PyObject * _io__BufferedIOBase_read_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); + int Py_UNUSED(size)); static PyObject * _io__BufferedIOBase_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -145,7 +145,7 @@ _io__BufferedIOBase_read(PyObject *self, PyTypeObject *cls, PyObject *const *arg # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "read", @@ -153,25 +153,31 @@ _io__BufferedIOBase_read(PyObject *self, PyTypeObject *cls, PyObject *const *arg }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + int size = -1; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__BufferedIOBase_read_impl(self, cls, __clinic_args); + if (nargs < 1) { + goto skip_optional_posonly; + } + size = _PyLong_AsInt(args[0]); + if (size == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_posonly: + return_value = _io__BufferedIOBase_read_impl(self, cls, size); exit: - Py_XDECREF(__clinic_args); return return_value; } PyDoc_STRVAR(_io__BufferedIOBase_read1__doc__, -"read1($self, /, *args)\n" +"read1($self, size=-1, /)\n" "--\n" "\n" -"Read and return up to n bytes, with at most one read() call to the underlying raw stream.\n" +"Read and return up to size bytes, with at most one read() call to the underlying raw stream.\n" "\n" "Return an empty bytes object on EOF.\n" "A short result does not imply that EOF is imminent."); @@ -181,7 +187,7 @@ PyDoc_STRVAR(_io__BufferedIOBase_read1__doc__, static PyObject * _io__BufferedIOBase_read1_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); + int Py_UNUSED(size)); static PyObject * _io__BufferedIOBase_read1(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -193,7 +199,7 @@ _io__BufferedIOBase_read1(PyObject *self, PyTypeObject *cls, PyObject *const *ar # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "read1", @@ -201,25 +207,31 @@ _io__BufferedIOBase_read1(PyObject *self, PyTypeObject *cls, PyObject *const *ar }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + int size = -1; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__BufferedIOBase_read1_impl(self, cls, __clinic_args); + if (nargs < 1) { + goto skip_optional_posonly; + } + size = _PyLong_AsInt(args[0]); + if (size == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_posonly: + return_value = _io__BufferedIOBase_read1_impl(self, cls, size); exit: - Py_XDECREF(__clinic_args); return return_value; } PyDoc_STRVAR(_io__BufferedIOBase_write__doc__, -"write($self, /, *args)\n" +"write($self, b, /)\n" "--\n" "\n" -"Write the given buffer to the IO stream.\n" +"Write buffer b to the IO stream.\n" "\n" "Return the number of bytes written, which is always\n" "the length of b in bytes.\n" @@ -232,7 +244,7 @@ PyDoc_STRVAR(_io__BufferedIOBase_write__doc__, static PyObject * _io__BufferedIOBase_write_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); + PyObject *Py_UNUSED(b)); static PyObject * _io__BufferedIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -244,7 +256,7 @@ _io__BufferedIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *ar # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "write", @@ -252,17 +264,16 @@ _io__BufferedIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *ar }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + PyObject *b; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__BufferedIOBase_write_impl(self, cls, __clinic_args); + b = args[0]; + return_value = _io__BufferedIOBase_write_impl(self, cls, b); exit: - Py_XDECREF(__clinic_args); return return_value; } @@ -1087,4 +1098,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=d770e392e8702e12 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b7ddf84a5bc2bf34 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 7e6b3b5b78e8..773e00104770 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -9,7 +9,7 @@ preserve PyDoc_STRVAR(_io__IOBase_seek__doc__, -"seek($self, /, *args)\n" +"seek($self, offset, whence=os.SEEK_SET, /)\n" "--\n" "\n" "Change the stream position to the given byte offset.\n" @@ -17,9 +17,9 @@ PyDoc_STRVAR(_io__IOBase_seek__doc__, "The offset is interpreted relative to the position indicated by whence.\n" "Values for whence are:\n" "\n" -"* 0 -- start of stream (the default); offset should be zero or positive\n" -"* 1 -- current stream position; offset may be negative\n" -"* 2 -- end of stream; offset is usually negative\n" +"* os.SEEK_SET or 0 -- start of stream (the default); offset should be zero or positive\n" +"* os.SEEK_CUR or 1 -- current stream position; offset may be negative\n" +"* os.SEEK_END or 2 -- end of stream; offset is usually negative\n" "\n" "Return the new absolute position."); @@ -27,7 +27,8 @@ PyDoc_STRVAR(_io__IOBase_seek__doc__, {"seek", _PyCFunction_CAST(_io__IOBase_seek), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_seek__doc__}, static PyObject * -_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, PyObject *args); +_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, + int Py_UNUSED(offset), int Py_UNUSED(whence)); static PyObject * _io__IOBase_seek(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -39,25 +40,36 @@ _io__IOBase_seek(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ss # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", "", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "seek", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + PyObject *argsbuf[2]; + int offset; + int whence = 0; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__IOBase_seek_impl(self, cls, __clinic_args); + offset = _PyLong_AsInt(args[0]); + if (offset == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs < 2) { + goto skip_optional_posonly; + } + whence = _PyLong_AsInt(args[1]); + if (whence == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_posonly: + return_value = _io__IOBase_seek_impl(self, cls, offset, whence); exit: - Py_XDECREF(__clinic_args); return return_value; } @@ -80,7 +92,7 @@ _io__IOBase_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_io__IOBase_truncate__doc__, -"truncate($self, /, *args)\n" +"truncate($self, size=None, /)\n" "--\n" "\n" "Truncate file to size bytes.\n" @@ -92,7 +104,8 @@ PyDoc_STRVAR(_io__IOBase_truncate__doc__, {"truncate", _PyCFunction_CAST(_io__IOBase_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__IOBase_truncate__doc__}, static PyObject * -_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *args); +_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, + PyObject *Py_UNUSED(size)); static PyObject * _io__IOBase_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -104,7 +117,7 @@ _io__IOBase_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, P # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "truncate", @@ -112,17 +125,20 @@ _io__IOBase_truncate(PyObject *self, PyTypeObject *cls, PyObject *const *args, P }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + PyObject *size = Py_None; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__IOBase_truncate_impl(self, cls, __clinic_args); + if (nargs < 1) { + goto skip_optional_posonly; + } + size = args[0]; +skip_optional_posonly: + return_value = _io__IOBase_truncate_impl(self, cls, size); exit: - Py_XDECREF(__clinic_args); return return_value; } @@ -420,4 +436,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=63bc25a5bfcecaf0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=301b22f8f75ce3dc input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 01965013ec6a..33fc23bd4c0c 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -33,7 +33,7 @@ _io__TextIOBase_detach(PyObject *self, PyTypeObject *cls, PyObject *const *args, } PyDoc_STRVAR(_io__TextIOBase_read__doc__, -"read($self, /, *args)\n" +"read($self, size=-1, /)\n" "--\n" "\n" "Read at most size characters from stream.\n" @@ -45,7 +45,8 @@ PyDoc_STRVAR(_io__TextIOBase_read__doc__, {"read", _PyCFunction_CAST(_io__TextIOBase_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_read__doc__}, static PyObject * -_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args); +_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, + int Py_UNUSED(size)); static PyObject * _io__TextIOBase_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -57,7 +58,7 @@ _io__TextIOBase_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, P # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "read", @@ -65,34 +66,41 @@ _io__TextIOBase_read(PyObject *self, PyTypeObject *cls, PyObject *const *args, P }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + int size = -1; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__TextIOBase_read_impl(self, cls, __clinic_args); + if (nargs < 1) { + goto skip_optional_posonly; + } + size = _PyLong_AsInt(args[0]); + if (size == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_posonly: + return_value = _io__TextIOBase_read_impl(self, cls, size); exit: - Py_XDECREF(__clinic_args); return return_value; } PyDoc_STRVAR(_io__TextIOBase_readline__doc__, -"readline($self, /, *args)\n" +"readline($self, size=-1, /)\n" "--\n" "\n" "Read until newline or EOF.\n" "\n" -"Return an empty string if EOF is hit immediately."); +"Return an empty string if EOF is hit immediately.\n" +"If size is specified, at most size characters will be read."); #define _IO__TEXTIOBASE_READLINE_METHODDEF \ {"readline", _PyCFunction_CAST(_io__TextIOBase_readline), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_readline__doc__}, static PyObject * _io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, - PyObject *args); + int Py_UNUSED(size)); static PyObject * _io__TextIOBase_readline(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -104,7 +112,7 @@ _io__TextIOBase_readline(PyObject *self, PyTypeObject *cls, PyObject *const *arg # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "readline", @@ -112,25 +120,31 @@ _io__TextIOBase_readline(PyObject *self, PyTypeObject *cls, PyObject *const *arg }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + int size = -1; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__TextIOBase_readline_impl(self, cls, __clinic_args); + if (nargs < 1) { + goto skip_optional_posonly; + } + size = _PyLong_AsInt(args[0]); + if (size == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional_posonly: + return_value = _io__TextIOBase_readline_impl(self, cls, size); exit: - Py_XDECREF(__clinic_args); return return_value; } PyDoc_STRVAR(_io__TextIOBase_write__doc__, -"write($self, /, *args)\n" +"write($self, s, /)\n" "--\n" "\n" -"Write string to stream.\n" +"Write string s to stream.\n" "\n" "Return the number of characters written\n" "(which is always equal to the length of the string)."); @@ -139,7 +153,8 @@ PyDoc_STRVAR(_io__TextIOBase_write__doc__, {"write", _PyCFunction_CAST(_io__TextIOBase_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__TextIOBase_write__doc__}, static PyObject * -_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args); +_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, + const char *Py_UNUSED(s)); static PyObject * _io__TextIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -151,7 +166,7 @@ _io__TextIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, # define KWTUPLE NULL #endif - static const char * const _keywords[] = { NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "write", @@ -159,17 +174,28 @@ _io__TextIOBase_write(PyObject *self, PyTypeObject *cls, PyObject *const *args, }; #undef KWTUPLE PyObject *argsbuf[1]; - PyObject *__clinic_args = NULL; + const char *s; - args = _PyArg_UnpackKeywordsWithVararg(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); if (!args) { goto exit; } - __clinic_args = args[0]; - return_value = _io__TextIOBase_write_impl(self, cls, __clinic_args); + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("write", "argument 1", "str", args[0]); + goto exit; + } + Py_ssize_t s_length; + s = PyUnicode_AsUTF8AndSize(args[0], &s_length); + if (s == NULL) { + goto exit; + } + if (strlen(s) != (size_t)s_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + return_value = _io__TextIOBase_write_impl(self, cls, s); exit: - Py_XDECREF(__clinic_args); return return_value; } @@ -934,4 +960,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=d800e5a8a50d6720 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=42f592331302973f input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 764c5fb33200..14d48813aefe 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -82,24 +82,26 @@ iobase_unsupported(_PyIO_State *state, const char *message) /*[clinic input] _io._IOBase.seek cls: defining_class + offset: int(unused=True) + whence: int(unused=True, c_default='0') = os.SEEK_SET / - *args: object Change the stream position to the given byte offset. The offset is interpreted relative to the position indicated by whence. Values for whence are: -* 0 -- start of stream (the default); offset should be zero or positive -* 1 -- current stream position; offset may be negative -* 2 -- end of stream; offset is usually negative +* os.SEEK_SET or 0 -- start of stream (the default); offset should be zero or positive +* os.SEEK_CUR or 1 -- current stream position; offset may be negative +* os.SEEK_END or 2 -- end of stream; offset is usually negative Return the new absolute position. [clinic start generated code]*/ static PyObject * -_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, PyObject *args) -/*[clinic end generated code: output=1dd694ac9de260fa input=ebb5476eb22fc5d4]*/ +_io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, + int Py_UNUSED(offset), int Py_UNUSED(whence)) +/*[clinic end generated code: output=8bd74ea6538ded53 input=8d4e6adcd08292f2]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "seek"); @@ -121,8 +123,8 @@ _io__IOBase_tell_impl(PyObject *self) /*[clinic input] _io._IOBase.truncate cls: defining_class + size: object(unused=True) = None / - *args: object Truncate file to size bytes. @@ -131,8 +133,9 @@ as reported by tell(). Return the new size. [clinic start generated code]*/ static PyObject * -_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, PyObject *args) -/*[clinic end generated code: output=b7eed4649cbe22c1 input=ad90582a1d8b5cc9]*/ +_io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, + PyObject *Py_UNUSED(size)) +/*[clinic end generated code: output=2013179bff1fe8ef input=660ac20936612c27]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return iobase_unsupported(state, "truncate"); diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 81dd3bed005a..e858a1fb498f 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -69,8 +69,8 @@ _io__TextIOBase_detach_impl(PyObject *self, PyTypeObject *cls) /*[clinic input] _io._TextIOBase.read cls: defining_class + size: int(unused=True) = -1 / - *args: object Read at most size characters from stream. @@ -79,8 +79,9 @@ If size is negative or omitted, read until EOF. [clinic start generated code]*/ static PyObject * -_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args) -/*[clinic end generated code: output=3adf28998831f461 input=cee1e84664a20de0]*/ +_io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, + int Py_UNUSED(size)) +/*[clinic end generated code: output=51a5178a309ce647 input=f5e37720f9fc563f]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "read"); @@ -89,18 +90,19 @@ _io__TextIOBase_read_impl(PyObject *self, PyTypeObject *cls, PyObject *args) /*[clinic input] _io._TextIOBase.readline cls: defining_class + size: int(unused=True) = -1 / - *args: object Read until newline or EOF. Return an empty string if EOF is hit immediately. +If size is specified, at most size characters will be read. [clinic start generated code]*/ static PyObject * _io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, - PyObject *args) -/*[clinic end generated code: output=3073a948d02319f3 input=58f801259f7ff3ef]*/ + int Py_UNUSED(size)) +/*[clinic end generated code: output=3f47d7966d6d074e input=42eafec94107fa27]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "readline"); @@ -109,18 +111,19 @@ _io__TextIOBase_readline_impl(PyObject *self, PyTypeObject *cls, /*[clinic input] _io._TextIOBase.write cls: defining_class + s: str(unused=True) / - *args: object -Write string to stream. +Write string s to stream. Return the number of characters written (which is always equal to the length of the string). [clinic start generated code]*/ static PyObject * -_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, PyObject *args) -/*[clinic end generated code: output=5d985eb529472bc4 input=21b6961b5cba9496]*/ +_io__TextIOBase_write_impl(PyObject *self, PyTypeObject *cls, + const char *Py_UNUSED(s)) +/*[clinic end generated code: output=18b28231460275de input=e9cabaa5f6732b07]*/ { _PyIO_State *state = get_io_state_by_cls(cls); return _unsupported(state, "write"); From webhook-mailer at python.org Mon May 15 12:54:13 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 15 May 2023 16:54:13 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E9=5D_gh-102950=3A_Implement_P?= =?utf-8?q?EP_706_=E2=80=93_Filter_for_tarfile=2Eextractall_=28GH-102953?= =?utf-8?b?KSAoIzEwNDM4Mik=?= Message-ID: <mailman.372.1684169655.13550.python-checkins@python.org> https://github.com/python/cpython/commit/98016f7c92aa4c1232c68bac1ed6646db31782ec commit: 98016f7c92aa4c1232c68bac1ed6646db31782ec branch: 3.9 author: Petr Viktorin <encukou at gmail.com> committer: ambv <lukasz at langa.pl> date: 2023-05-15T18:53:58+02:00 summary: [3.9] gh-102950: Implement PEP 706 ? Filter for tarfile.extractall (GH-102953) (#104382) Backport of c8c3956d905e019101038b018129a4c90c9c9b8f files: A Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst M Doc/library/shutil.rst M Doc/library/tarfile.rst M Doc/whatsnew/3.9.rst M Lib/shutil.py M Lib/tarfile.py M Lib/test/test_shutil.py M Lib/test/test_tarfile.py diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index 193c01006171..b49e0c198ab7 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -614,7 +614,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Remove the archive format *name* from the list of supported formats. -.. function:: unpack_archive(filename[, extract_dir[, format]]) +.. function:: unpack_archive(filename[, extract_dir[, format[, filter]]]) Unpack an archive. *filename* is the full path of the archive. @@ -628,6 +628,15 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. registered for that extension. In case none is found, a :exc:`ValueError` is raised. + The keyword-only *filter* argument, which was added in Python 3.9.17, + is passed to the underlying unpacking function. + For zip files, *filter* is not accepted. + For tar files, it is recommended to set it to ``'data'``, + unless using features specific to tar and UNIX-like filesystems. + (See :ref:`tarfile-extraction-filter` for details.) + The ``'data'`` filter will become the default for tar files + in Python 3.14. + .. audit-event:: shutil.unpack_archive filename,extract_dir,format shutil.unpack_archive .. warning:: @@ -640,6 +649,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. .. versionchanged:: 3.7 Accepts a :term:`path-like object` for *filename* and *extract_dir*. + .. versionchanged:: 3.9.17 + Added the *filter* argument. + .. function:: register_unpack_format(name, extensions, function[, extra_args[, description]]) Registers an unpack format. *name* is the name of the format and @@ -647,11 +659,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. ``.zip`` for Zip files. *function* is the callable that will be used to unpack archives. The - callable will receive the path of the archive, followed by the directory - the archive must be extracted to. - - When provided, *extra_args* is a sequence of ``(name, value)`` tuples that - will be passed as keywords arguments to the callable. + callable will receive: + + - the path of the archive, as a positional argument; + - the directory the archive must be extracted to, as a positional argument; + - possibly a *filter* keyword argument, if it was given to + :func:`unpack_archive`; + - additional keyword arguments, specified by *extra_args* as a sequence + of ``(name, value)`` tuples. *description* can be provided to describe the format, and will be returned by the :func:`get_unpack_formats` function. diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 0dc7c6191487..f1d9bd34536b 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -206,6 +206,38 @@ The :mod:`tarfile` module defines the following exceptions: Is raised by :meth:`TarInfo.frombuf` if the buffer it gets is invalid. +.. exception:: FilterError + + Base class for members :ref:`refused <tarfile-extraction-refuse>` by + filters. + + .. attribute:: tarinfo + + Information about the member that the filter refused to extract, + as :ref:`TarInfo <tarinfo-objects>`. + +.. exception:: AbsolutePathError + + Raised to refuse extracting a member with an absolute path. + +.. exception:: OutsideDestinationError + + Raised to refuse extracting a member outside the destination directory. + +.. exception:: SpecialFileError + + Raised to refuse extracting a special file (e.g. a device or pipe). + +.. exception:: AbsoluteLinkError + + Raised to refuse extracting a symbolic link with an absolute path. + +.. exception:: LinkOutsideDestinationError + + Raised to refuse extracting a symbolic link pointing outside the destination + directory. + + The following constants are available at the module level: .. data:: ENCODING @@ -316,11 +348,8 @@ be finalized; only the internally used file object will be closed. See the *debug* can be set from ``0`` (no debug messages) up to ``3`` (all debug messages). The messages are written to ``sys.stderr``. - If *errorlevel* is ``0``, all errors are ignored when using :meth:`TarFile.extract`. - Nevertheless, they appear as error messages in the debug output, when debugging - is enabled. If ``1``, all *fatal* errors are raised as :exc:`OSError` - exceptions. If ``2``, all *non-fatal* errors are raised as :exc:`TarError` - exceptions as well. + *errorlevel* controls how extraction errors are handled, + see :attr:`the corresponding attribute <~TarFile.errorlevel>`. The *encoding* and *errors* arguments define the character encoding to be used for reading or writing the archive and how conversion errors are going @@ -387,7 +416,7 @@ be finalized; only the internally used file object will be closed. See the available. -.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False) +.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False, filter=None) Extract all members from the archive to the current working directory or directory *path*. If optional *members* is given, it must be a subset of the @@ -401,6 +430,12 @@ be finalized; only the internally used file object will be closed. See the are used to set the owner/group for the extracted files. Otherwise, the named values from the tarfile are used. + The *filter* argument, which was added in Python 3.9.17, specifies how + ``members`` are modified or rejected before extraction. + See :ref:`tarfile-extraction-filter` for details. + It is recommended to set this explicitly depending on which *tar* features + you need to support. + .. warning:: Never extract archives from untrusted sources without prior inspection. @@ -408,14 +443,20 @@ be finalized; only the internally used file object will be closed. See the that have absolute filenames starting with ``"/"`` or filenames with two dots ``".."``. + Set ``filter='data'`` to prevent the most dangerous security issues, + and read the :ref:`tarfile-extraction-filter` section for details. + .. versionchanged:: 3.5 Added the *numeric_owner* parameter. .. versionchanged:: 3.6 The *path* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.9.17 + Added the *filter* parameter. + -.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False) +.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False, filter=None) Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. *member* @@ -423,9 +464,8 @@ be finalized; only the internally used file object will be closed. See the directory using *path*. *path* may be a :term:`path-like object`. File attributes (owner, mtime, mode) are set unless *set_attrs* is false. - If *numeric_owner* is :const:`True`, the uid and gid numbers from the tarfile - are used to set the owner/group for the extracted files. Otherwise, the named - values from the tarfile are used. + The *numeric_owner* and *filter* arguments are the same as + for :meth:`extractall`. .. note:: @@ -436,6 +476,9 @@ be finalized; only the internally used file object will be closed. See the See the warning for :meth:`extractall`. + Set ``filter='data'`` to prevent the most dangerous security issues, + and read the :ref:`tarfile-extraction-filter` section for details. + .. versionchanged:: 3.2 Added the *set_attrs* parameter. @@ -445,6 +488,9 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.6 The *path* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.9.17 + Added the *filter* parameter. + .. method:: TarFile.extractfile(member) @@ -457,6 +503,57 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.3 Return an :class:`io.BufferedReader` object. +.. attribute:: TarFile.errorlevel + :type: int + + If *errorlevel* is ``0``, errors are ignored when using :meth:`TarFile.extract` + and :meth:`TarFile.extractall`. + Nevertheless, they appear as error messages in the debug output when + *debug* is greater than 0. + If ``1`` (the default), all *fatal* errors are raised as :exc:`OSError` or + :exc:`FilterError` exceptions. If ``2``, all *non-fatal* errors are raised + as :exc:`TarError` exceptions as well. + + Some exceptions, e.g. ones caused by wrong argument types or data + corruption, are always raised. + + Custom :ref:`extraction filters <tarfile-extraction-filter>` + should raise :exc:`FilterError` for *fatal* errors + and :exc:`ExtractError` for *non-fatal* ones. + + Note that when an exception is raised, the archive may be partially + extracted. It is the user?s responsibility to clean up. + +.. attribute:: TarFile.extraction_filter + + .. versionadded:: 3.9.17 + + The :ref:`extraction filter <tarfile-extraction-filter>` used + as a default for the *filter* argument of :meth:`~TarFile.extract` + and :meth:`~TarFile.extractall`. + + The attribute may be ``None`` or a callable. + String names are not allowed for this attribute, unlike the *filter* + argument to :meth:`~TarFile.extract`. + + If ``extraction_filter`` is ``None`` (the default), + calling an extraction method without a *filter* argument will + use the :func:`fully_trusted <fully_trusted_filter>` filter for + compatibility with previous Python versions. + + In Python 3.12+, leaving ``extraction_filter=None`` will emit a + ``DeprecationWarning``. + + In Python 3.14+, leaving ``extraction_filter=None`` will cause + extraction methods to use the :func:`data <data_filter>` filter by default. + + The attribute may be set on instances or overridden in subclasses. + It also is possible to set it on the ``TarFile`` class itself to set a + global default, although, since it affects all uses of *tarfile*, + it is best practice to only do so in top-level applications or + :mod:`site configuration <site>`. + To set a global default this way, a filter function needs to be wrapped in + :func:`staticmethod()` to prevent injection of a ``self`` argument. .. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None) @@ -532,7 +629,27 @@ permissions, owner etc.), it provides some useful methods to determine its type. It does *not* contain the file's data itself. :class:`TarInfo` objects are returned by :class:`TarFile`'s methods -:meth:`getmember`, :meth:`getmembers` and :meth:`gettarinfo`. +:meth:`~TarFile.getmember`, :meth:`~TarFile.getmembers` and +:meth:`~TarFile.gettarinfo`. + +Modifying the objects returned by :meth:`~!TarFile.getmember` or +:meth:`~!TarFile.getmembers` will affect all subsequent +operations on the archive. +For cases where this is unwanted, you can use :mod:`copy.copy() <copy>` or +call the :meth:`~TarInfo.replace` method to create a modified copy in one step. + +Several attributes can be set to ``None`` to indicate that a piece of metadata +is unused or unknown. +Different :class:`TarInfo` methods handle ``None`` differently: + +- The :meth:`~TarFile.extract` or :meth:`~TarFile.extractall` methods will + ignore the corresponding metadata, leaving it set to a default. +- :meth:`~TarFile.addfile` will fail. +- :meth:`~TarFile.list` will print a placeholder string. + + +.. versionchanged:: 3.9.17 + Added :meth:`~TarInfo.replace` and handling of ``None``. .. class:: TarInfo(name="") @@ -566,24 +683,39 @@ A ``TarInfo`` object has the following public data attributes: .. attribute:: TarInfo.name + :type: str Name of the archive member. .. attribute:: TarInfo.size + :type: int Size in bytes. .. attribute:: TarInfo.mtime + :type: int | float + + Time of last modification in seconds since the :ref:`epoch <epoch>`, + as in :attr:`os.stat_result.st_mtime`. - Time of last modification. + .. versionchanged:: 3.9.17 + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.mode + :type: int - Permission bits. + Permission bits, as for :func:`os.chmod`. + .. versionchanged:: 3.9.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.type @@ -595,35 +727,76 @@ A ``TarInfo`` object has the following public data attributes: .. attribute:: TarInfo.linkname + :type: str Name of the target file name, which is only present in :class:`TarInfo` objects of type :const:`LNKTYPE` and :const:`SYMTYPE`. .. attribute:: TarInfo.uid + :type: int User ID of the user who originally stored this member. + .. versionchanged:: 3.9.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.gid + :type: int Group ID of the user who originally stored this member. + .. versionchanged:: 3.9.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.uname + :type: str User name. + .. versionchanged:: 3.9.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.gname + :type: str Group name. + .. versionchanged:: 3.9.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.pax_headers + :type: dict A dictionary containing key-value pairs of an associated pax extended header. +.. method:: TarInfo.replace(name=..., mtime=..., mode=..., linkname=..., + uid=..., gid=..., uname=..., gname=..., + deep=True) + + .. versionadded:: 3.9.17 + + Return a *new* copy of the :class:`!TarInfo` object with the given attributes + changed. For example, to return a ``TarInfo`` with the group name set to + ``'staff'``, use:: + + new_tarinfo = old_tarinfo.replace(gname='staff') + + By default, a deep copy is made. + If *deep* is false, the copy is shallow, i.e. ``pax_headers`` + and any custom attributes are shared with the original ``TarInfo`` object. A :class:`TarInfo` object also provides some convenient query methods: @@ -673,9 +846,259 @@ A :class:`TarInfo` object also provides some convenient query methods: Return :const:`True` if it is one of character device, block device or FIFO. +.. _tarfile-extraction-filter: + +Extraction filters +------------------ + +.. versionadded:: 3.9.17 + +The *tar* format is designed to capture all details of a UNIX-like filesystem, +which makes it very powerful. +Unfortunately, the features make it easy to create tar files that have +unintended -- and possibly malicious -- effects when extracted. +For example, extracting a tar file can overwrite arbitrary files in various +ways (e.g. by using absolute paths, ``..`` path components, or symlinks that +affect later members). + +In most cases, the full functionality is not needed. +Therefore, *tarfile* supports extraction filters: a mechanism to limit +functionality, and thus mitigate some of the security issues. + +.. seealso:: + + :pep:`706` + Contains further motivation and rationale behind the design. + +The *filter* argument to :meth:`TarFile.extract` or :meth:`~TarFile.extractall` +can be: + +* the string ``'fully_trusted'``: Honor all metadata as specified in the + archive. + Should be used if the user trusts the archive completely, or implements + their own complex verification. + +* the string ``'tar'``: Honor most *tar*-specific features (i.e. features of + UNIX-like filesystems), but block features that are very likely to be + surprising or malicious. See :func:`tar_filter` for details. + +* the string ``'data'``: Ignore or block most features specific to UNIX-like + filesystems. Intended for extracting cross-platform data archives. + See :func:`data_filter` for details. + +* ``None`` (default): Use :attr:`TarFile.extraction_filter`. + + If that is also ``None`` (the default), the ``'fully_trusted'`` + filter will be used (for compatibility with earlier versions of Python). + + In Python 3.12, the default will emit a ``DeprecationWarning``. + + In Python 3.14, the ``'data'`` filter will become the default instead. + It's possible to switch earlier; see :attr:`TarFile.extraction_filter`. + +* A callable which will be called for each extracted member with a + :ref:`TarInfo <tarinfo-objects>` describing the member and the destination + path to where the archive is extracted (i.e. the same path is used for all + members):: + + filter(/, member: TarInfo, path: str) -> TarInfo | None + + The callable is called just before each member is extracted, so it can + take the current state of the disk into account. + It can: + + - return a :class:`TarInfo` object which will be used instead of the metadata + in the archive, or + - return ``None``, in which case the member will be skipped, or + - raise an exception to abort the operation or skip the member, + depending on :attr:`~TarFile.errorlevel`. + Note that when extraction is aborted, :meth:`~TarFile.extractall` may leave + the archive partially extracted. It does not attempt to clean up. + +Default named filters +~~~~~~~~~~~~~~~~~~~~~ + +The pre-defined, named filters are available as functions, so they can be +reused in custom filters: + +.. function:: fully_trusted_filter(/, member, path) + + Return *member* unchanged. + + This implements the ``'fully_trusted'`` filter. + +.. function:: tar_filter(/, member, path) + + Implements the ``'tar'`` filter. + + - Strip leading slashes (``/`` and :attr:`os.sep`) from filenames. + - :ref:`Refuse <tarfile-extraction-refuse>` to extract files with absolute + paths (in case the name is absolute + even after stripping slashes, e.g. ``C:/foo`` on Windows). + This raises :class:`~tarfile.AbsolutePathError`. + - :ref:`Refuse <tarfile-extraction-refuse>` to extract files whose absolute + path (after following symlinks) would end up outside the destination. + This raises :class:`~tarfile.OutsideDestinationError`. + - Clear high mode bits (setuid, setgid, sticky) and group/other write bits + (:attr:`~stat.S_IWGRP`|:attr:`~stat.S_IWOTH`). + + Return the modified ``TarInfo`` member. + +.. function:: data_filter(/, member, path) + + Implements the ``'data'`` filter. + In addition to what ``tar_filter`` does: + + - :ref:`Refuse <tarfile-extraction-refuse>` to extract links (hard or soft) + that link to absolute paths, or ones that link outside the destination. + + This raises :class:`~tarfile.AbsoluteLinkError` or + :class:`~tarfile.LinkOutsideDestinationError`. + + Note that such files are refused even on platforms that do not support + symbolic links. + + - :ref:`Refuse <tarfile-extraction-refuse>` to extract device files + (including pipes). + This raises :class:`~tarfile.SpecialFileError`. + + - For regular files, including hard links: + + - Set the owner read and write permissions + (:attr:`~stat.S_IRUSR`|:attr:`~stat.S_IWUSR`). + - Remove the group & other executable permission + (:attr:`~stat.S_IXGRP`|:attr:`~stat.S_IXOTH`) + if the owner doesn?t have it (:attr:`~stat.S_IXUSR`). + + - For other files (directories), set ``mode`` to ``None``, so + that extraction methods skip applying permission bits. + - Set user and group info (``uid``, ``gid``, ``uname``, ``gname``) + to ``None``, so that extraction methods skip setting it. + + Return the modified ``TarInfo`` member. + + +.. _tarfile-extraction-refuse: + +Filter errors +~~~~~~~~~~~~~ + +When a filter refuses to extract a file, it will raise an appropriate exception, +a subclass of :class:`~tarfile.FilterError`. +This will abort the extraction if :attr:`TarFile.errorlevel` is 1 or more. +With ``errorlevel=0`` the error will be logged and the member will be skipped, +but extraction will continue. + + +Hints for further verification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Even with ``filter='data'``, *tarfile* is not suited for extracting untrusted +files without prior inspection. +Among other issues, the pre-defined filters do not prevent denial-of-service +attacks. Users should do additional checks. + +Here is an incomplete list of things to consider: + +* Extract to a :func:`new temporary directory <tempfile.mkdtemp>` + to prevent e.g. exploiting pre-existing links, and to make it easier to + clean up after a failed extraction. +* When working with untrusted data, use external (e.g. OS-level) limits on + disk, memory and CPU usage. +* Check filenames against an allow-list of characters + (to filter out control characters, confusables, foreign path separators, + etc.). +* Check that filenames have expected extensions (discouraging files that + execute when you ?click on them?, or extension-less files like Windows special device names). +* Limit the number of extracted files, total size of extracted data, + filename length (including symlink length), and size of individual files. +* Check for files that would be shadowed on case-insensitive filesystems. + +Also note that: + +* Tar files may contain multiple versions of the same file. + Later ones are expected to overwrite any earlier ones. + This feature is crucial to allow updating tape archives, but can be abused + maliciously. +* *tarfile* does not protect against issues with ?live? data, + e.g. an attacker tinkering with the destination (or source) directory while + extraction (or archiving) is in progress. + + +Supporting older Python versions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extraction filters were added to Python 3.12, and are backported to older +versions as security updates. +To check whether the feature is available, use e.g. +``hasattr(tarfile, 'data_filter')`` rather than checking the Python version. + +The following examples show how to support Python versions with and without +the feature. +Note that setting ``extraction_filter`` will affect any subsequent operations. + +* Fully trusted archive:: + + my_tarfile.extraction_filter = (lambda member, path: member) + my_tarfile.extractall() + +* Use the ``'data'`` filter if available, but revert to Python 3.11 behavior + (``'fully_trusted'``) if this feature is not available:: + + my_tarfile.extraction_filter = getattr(tarfile, 'data_filter', + (lambda member, path: member)) + my_tarfile.extractall() + +* Use the ``'data'`` filter; *fail* if it is not available:: + + my_tarfile.extractall(filter=tarfile.data_filter) + + or:: + + my_tarfile.extraction_filter = tarfile.data_filter + my_tarfile.extractall() + +* Use the ``'data'`` filter; *warn* if it is not available:: + + if hasattr(tarfile, 'data_filter'): + my_tarfile.extractall(filter='data') + else: + # remove this when no longer needed + warn_the_user('Extracting may be unsafe; consider updating Python') + my_tarfile.extractall() + + +Stateful extraction filter example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While *tarfile*'s extraction methods take a simple *filter* callable, +custom filters may be more complex objects with an internal state. +It may be useful to write these as context managers, to be used like this:: + + with StatefulFilter() as filter_func: + tar.extractall(path, filter=filter_func) + +Such a filter can be written as, for example:: + + class StatefulFilter: + def __init__(self): + self.file_count = 0 + + def __enter__(self): + return self + + def __call__(self, member, path): + self.file_count += 1 + return member + + def __exit__(self, *exc_info): + print(f'{self.file_count} files extracted') + + .. _tarfile-commandline: .. program:: tarfile + Command-Line Interface ---------------------- @@ -745,6 +1168,15 @@ Command-line options Verbose output. +.. cmdoption:: --filter <filtername> + + Specifies the *filter* for ``--extract``. + See :ref:`tarfile-extraction-filter` for details. + Only string names are accepted (that is, ``fully_trusted``, ``tar``, + and ``data``). + + .. versionadded:: 3.9.17 + .. _tar-examples: Examples diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index dab4746a8f6e..0064e074a3ad 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1601,3 +1601,18 @@ line flag, or :mod:`sys` APIs. See the :ref:`integer string conversion length limitation <int_max_str_digits>` documentation. The default limit is 4300 digits in string form. +Notable Changes in 3.9.17 +========================= + +tarfile +------- + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile-extraction-filter` for details. + In Python 3.12, use without the *filter* argument will show a + :exc:`DeprecationWarning`. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) diff --git a/Lib/shutil.py b/Lib/shutil.py index 48a60c0d28d0..58b8d3b9f955 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1191,7 +1191,7 @@ def _unpack_zipfile(filename, extract_dir): finally: zip.close() -def _unpack_tarfile(filename, extract_dir): +def _unpack_tarfile(filename, extract_dir, *, filter=None): """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` """ import tarfile # late import for breaking circular dependency @@ -1201,7 +1201,7 @@ def _unpack_tarfile(filename, extract_dir): raise ReadError( "%s is not a compressed or uncompressed tar file" % filename) try: - tarobj.extractall(extract_dir) + tarobj.extractall(extract_dir, filter=filter) finally: tarobj.close() @@ -1229,7 +1229,7 @@ def _find_unpack_format(filename): return name return None -def unpack_archive(filename, extract_dir=None, format=None): +def unpack_archive(filename, extract_dir=None, format=None, *, filter=None): """Unpack an archive. `filename` is the name of the archive. @@ -1243,6 +1243,9 @@ def unpack_archive(filename, extract_dir=None, format=None): was registered for that extension. In case none is found, a ValueError is raised. + + If `filter` is given, it is passed to the underlying + extraction function. """ sys.audit("shutil.unpack_archive", filename, extract_dir, format) @@ -1252,6 +1255,10 @@ def unpack_archive(filename, extract_dir=None, format=None): extract_dir = os.fspath(extract_dir) filename = os.fspath(filename) + if filter is None: + filter_kwargs = {} + else: + filter_kwargs = {'filter': filter} if format is not None: try: format_info = _UNPACK_FORMATS[format] @@ -1259,7 +1266,7 @@ def unpack_archive(filename, extract_dir=None, format=None): raise ValueError("Unknown unpack format '{0}'".format(format)) from None func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) + func(filename, extract_dir, **dict(format_info[2]), **filter_kwargs) else: # we need to look at the registered unpackers supported extensions format = _find_unpack_format(filename) @@ -1267,7 +1274,7 @@ def unpack_archive(filename, extract_dir=None, format=None): raise ReadError("Unknown archive format '{0}'".format(filename)) func = _UNPACK_FORMATS[format][1] - kwargs = dict(_UNPACK_FORMATS[format][2]) + kwargs = dict(_UNPACK_FORMATS[format][2]) | filter_kwargs func(filename, extract_dir, **kwargs) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 9438b08ae396..b6ad7dbe2a4d 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -46,6 +46,7 @@ import struct import copy import re +import warnings try: import pwd @@ -71,6 +72,7 @@ "ENCODING", "USTAR_FORMAT", "GNU_FORMAT", "PAX_FORMAT", "DEFAULT_FORMAT", "open"] + #--------------------------------------------------------- # tar constants #--------------------------------------------------------- @@ -158,6 +160,8 @@ def stn(s, length, encoding, errors): """Convert a string to a null-terminated bytes object. """ + if s is None: + raise ValueError("metadata cannot contain None") s = s.encode(encoding, errors) return s[:length] + (length - len(s)) * NUL @@ -708,9 +712,127 @@ def __init__(self, tarfile, tarinfo): super().__init__(fileobj) #class ExFileObject + +#----------------------------- +# extraction filters (PEP 706) +#----------------------------- + +class FilterError(TarError): + pass + +class AbsolutePathError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'member {tarinfo.name!r} has an absolute path') + +class OutsideDestinationError(FilterError): + def __init__(self, tarinfo, path): + self.tarinfo = tarinfo + self._path = path + super().__init__(f'{tarinfo.name!r} would be extracted to {path!r}, ' + + 'which is outside the destination') + +class SpecialFileError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'{tarinfo.name!r} is a special file') + +class AbsoluteLinkError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'{tarinfo.name!r} is a symlink to an absolute path') + +class LinkOutsideDestinationError(FilterError): + def __init__(self, tarinfo, path): + self.tarinfo = tarinfo + self._path = path + super().__init__(f'{tarinfo.name!r} would link to {path!r}, ' + + 'which is outside the destination') + +def _get_filtered_attrs(member, dest_path, for_data=True): + new_attrs = {} + name = member.name + dest_path = os.path.realpath(dest_path) + # Strip leading / (tar's directory separator) from filenames. + # Include os.sep (target OS directory separator) as well. + if name.startswith(('/', os.sep)): + name = new_attrs['name'] = member.path.lstrip('/' + os.sep) + if os.path.isabs(name): + # Path is absolute even after stripping. + # For example, 'C:/foo' on Windows. + raise AbsolutePathError(member) + # Ensure we stay in the destination + target_path = os.path.realpath(os.path.join(dest_path, name)) + if os.path.commonpath([target_path, dest_path]) != dest_path: + raise OutsideDestinationError(member, target_path) + # Limit permissions (no high bits, and go-w) + mode = member.mode + if mode is not None: + # Strip high bits & group/other write bits + mode = mode & 0o755 + if for_data: + # For data, handle permissions & file types + if member.isreg() or member.islnk(): + if not mode & 0o100: + # Clear executable bits if not executable by user + mode &= ~0o111 + # Ensure owner can read & write + mode |= 0o600 + elif member.isdir() or member.issym(): + # Ignore mode for directories & symlinks + mode = None + else: + # Reject special files + raise SpecialFileError(member) + if mode != member.mode: + new_attrs['mode'] = mode + if for_data: + # Ignore ownership for 'data' + if member.uid is not None: + new_attrs['uid'] = None + if member.gid is not None: + new_attrs['gid'] = None + if member.uname is not None: + new_attrs['uname'] = None + if member.gname is not None: + new_attrs['gname'] = None + # Check link destination for 'data' + if member.islnk() or member.issym(): + if os.path.isabs(member.linkname): + raise AbsoluteLinkError(member) + target_path = os.path.realpath(os.path.join(dest_path, member.linkname)) + if os.path.commonpath([target_path, dest_path]) != dest_path: + raise LinkOutsideDestinationError(member, target_path) + return new_attrs + +def fully_trusted_filter(member, dest_path): + return member + +def tar_filter(member, dest_path): + new_attrs = _get_filtered_attrs(member, dest_path, False) + if new_attrs: + return member.replace(**new_attrs, deep=False) + return member + +def data_filter(member, dest_path): + new_attrs = _get_filtered_attrs(member, dest_path, True) + if new_attrs: + return member.replace(**new_attrs, deep=False) + return member + +_NAMED_FILTERS = { + "fully_trusted": fully_trusted_filter, + "tar": tar_filter, + "data": data_filter, +} + #------------------ # Exported Classes #------------------ + +# Sentinel for replace() defaults, meaning "don't change the attribute" +_KEEP = object() + class TarInfo(object): """Informational class which holds the details about an archive member given by a tar header block. @@ -791,12 +913,44 @@ def linkpath(self, linkname): def __repr__(self): return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) + def replace(self, *, + name=_KEEP, mtime=_KEEP, mode=_KEEP, linkname=_KEEP, + uid=_KEEP, gid=_KEEP, uname=_KEEP, gname=_KEEP, + deep=True, _KEEP=_KEEP): + """Return a deep copy of self with the given attributes replaced. + """ + if deep: + result = copy.deepcopy(self) + else: + result = copy.copy(self) + if name is not _KEEP: + result.name = name + if mtime is not _KEEP: + result.mtime = mtime + if mode is not _KEEP: + result.mode = mode + if linkname is not _KEEP: + result.linkname = linkname + if uid is not _KEEP: + result.uid = uid + if gid is not _KEEP: + result.gid = gid + if uname is not _KEEP: + result.uname = uname + if gname is not _KEEP: + result.gname = gname + return result + def get_info(self): """Return the TarInfo's attributes as a dictionary. """ + if self.mode is None: + mode = None + else: + mode = self.mode & 0o7777 info = { "name": self.name, - "mode": self.mode & 0o7777, + "mode": mode, "uid": self.uid, "gid": self.gid, "size": self.size, @@ -819,6 +973,9 @@ def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescap """Return a tar header as a string of 512 byte blocks. """ info = self.get_info() + for name, value in info.items(): + if value is None: + raise ValueError("%s may not be None" % name) if format == USTAR_FORMAT: return self.create_ustar_header(info, encoding, errors) @@ -949,6 +1106,12 @@ def _create_header(info, format, encoding, errors): devmajor = stn("", 8, encoding, errors) devminor = stn("", 8, encoding, errors) + # None values in metadata should cause ValueError. + # itn()/stn() do this for all fields except type. + filetype = info.get("type", REGTYPE) + if filetype is None: + raise ValueError("TarInfo.type must not be None") + parts = [ stn(info.get("name", ""), 100, encoding, errors), itn(info.get("mode", 0) & 0o7777, 8, format), @@ -957,7 +1120,7 @@ def _create_header(info, format, encoding, errors): itn(info.get("size", 0), 12, format), itn(info.get("mtime", 0), 12, format), b" ", # checksum field - info.get("type", REGTYPE), + filetype, stn(info.get("linkname", ""), 100, encoding, errors), info.get("magic", POSIX_MAGIC), stn(info.get("uname", ""), 32, encoding, errors), @@ -1457,6 +1620,8 @@ class TarFile(object): fileobject = ExFileObject # The file-object for extractfile(). + extraction_filter = None # The default filter for extraction. + def __init__(self, name=None, mode="r", fileobj=None, format=None, tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, errors="surrogateescape", pax_headers=None, debug=None, @@ -1926,7 +2091,10 @@ def list(self, verbose=True, *, members=None): members = self for tarinfo in members: if verbose: - _safe_print(stat.filemode(tarinfo.mode)) + if tarinfo.mode is None: + _safe_print("??????????") + else: + _safe_print(stat.filemode(tarinfo.mode)) _safe_print("%s/%s" % (tarinfo.uname or tarinfo.uid, tarinfo.gname or tarinfo.gid)) if tarinfo.ischr() or tarinfo.isblk(): @@ -1934,8 +2102,11 @@ def list(self, verbose=True, *, members=None): ("%d,%d" % (tarinfo.devmajor, tarinfo.devminor))) else: _safe_print("%10d" % tarinfo.size) - _safe_print("%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6]) + if tarinfo.mtime is None: + _safe_print("????-??-?? ??:??:??") + else: + _safe_print("%d-%02d-%02d %02d:%02d:%02d" \ + % time.localtime(tarinfo.mtime)[:6]) _safe_print(tarinfo.name + ("/" if tarinfo.isdir() else "")) @@ -2022,32 +2193,58 @@ def addfile(self, tarinfo, fileobj=None): self.members.append(tarinfo) - def extractall(self, path=".", members=None, *, numeric_owner=False): + def _get_filter_function(self, filter): + if filter is None: + filter = self.extraction_filter + if filter is None: + return fully_trusted_filter + if isinstance(filter, str): + raise TypeError( + 'String names are not supported for ' + + 'TarFile.extraction_filter. Use a function such as ' + + 'tarfile.data_filter directly.') + return filter + if callable(filter): + return filter + try: + return _NAMED_FILTERS[filter] + except KeyError: + raise ValueError(f"filter {filter!r} not found") from None + + def extractall(self, path=".", members=None, *, numeric_owner=False, + filter=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on directories afterwards. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by getmembers(). If `numeric_owner` is True, only the numbers for user/group names are used and not the names. + + The `filter` function will be called on each member just + before extraction. + It can return a changed TarInfo or None to skip the member. + String names of common filters are accepted. """ directories = [] + filter_function = self._get_filter_function(filter) if members is None: members = self - for tarinfo in members: + for member in members: + tarinfo = self._get_extract_tarinfo(member, filter_function, path) + if tarinfo is None: + continue if tarinfo.isdir(): - # Extract directories with a safe mode. + # For directories, delay setting attributes until later, + # since permissions can interfere with extraction and + # extracting contents can reset mtime. directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0o700 - # Do not set_attrs directories, as we will do that further down - self.extract(tarinfo, path, set_attrs=not tarinfo.isdir(), - numeric_owner=numeric_owner) + self._extract_one(tarinfo, path, set_attrs=not tarinfo.isdir(), + numeric_owner=numeric_owner) # Reverse sort directories. - directories.sort(key=lambda a: a.name) - directories.reverse() + directories.sort(key=lambda a: a.name, reverse=True) # Set correct owner, mtime and filemode on directories. for tarinfo in directories: @@ -2057,12 +2254,10 @@ def extractall(self, path=".", members=None, *, numeric_owner=False): self.utime(tarinfo, dirpath) self.chmod(tarinfo, dirpath) except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) + self._handle_nonfatal_error(e) - def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): + def extract(self, member, path="", set_attrs=True, *, numeric_owner=False, + filter=None): """Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. `member' may be a filename or a TarInfo object. You can @@ -2070,35 +2265,70 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): mtime, mode) are set unless `set_attrs' is False. If `numeric_owner` is True, only the numbers for user/group names are used and not the names. + + The `filter` function will be called before extraction. + It can return a changed TarInfo or None to skip the member. + String names of common filters are accepted. """ - self._check("r") + filter_function = self._get_filter_function(filter) + tarinfo = self._get_extract_tarinfo(member, filter_function, path) + if tarinfo is not None: + self._extract_one(tarinfo, path, set_attrs, numeric_owner) + def _get_extract_tarinfo(self, member, filter_function, path): + """Get filtered TarInfo (or None) from member, which might be a str""" if isinstance(member, str): tarinfo = self.getmember(member) else: tarinfo = member + unfiltered = tarinfo + try: + tarinfo = filter_function(tarinfo, path) + except (OSError, FilterError) as e: + self._handle_fatal_error(e) + except ExtractError as e: + self._handle_nonfatal_error(e) + if tarinfo is None: + self._dbg(2, "tarfile: Excluded %r" % unfiltered.name) + return None # Prepare the link target for makelink(). if tarinfo.islnk(): + tarinfo = copy.copy(tarinfo) tarinfo._link_target = os.path.join(path, tarinfo.linkname) + return tarinfo + + def _extract_one(self, tarinfo, path, set_attrs, numeric_owner): + """Extract from filtered tarinfo to disk""" + self._check("r") try: self._extract_member(tarinfo, os.path.join(path, tarinfo.name), set_attrs=set_attrs, numeric_owner=numeric_owner) except OSError as e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + self._handle_fatal_error(e) except ExtractError as e: - if self.errorlevel > 1: - raise + self._handle_nonfatal_error(e) + + def _handle_nonfatal_error(self, e): + """Handle non-fatal error (ExtractError) according to errorlevel""" + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def _handle_fatal_error(self, e): + """Handle "fatal" error according to self.errorlevel""" + if self.errorlevel > 0: + raise + elif isinstance(e, OSError): + if e.filename is None: + self._dbg(1, "tarfile: %s" % e.strerror) else: - self._dbg(1, "tarfile: %s" % e) + self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + else: + self._dbg(1, "tarfile: %s %s" % (type(e).__name__, e)) def extractfile(self, member): """Extract a member from the archive as a file object. `member' may be @@ -2185,9 +2415,13 @@ def makedir(self, tarinfo, targetpath): """Make a directory called targetpath. """ try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0o700) + if tarinfo.mode is None: + # Use the system's default mode + os.mkdir(targetpath) + else: + # Use a safe mode for the directory, the real mode is set + # later in _extract_member(). + os.mkdir(targetpath, 0o700) except FileExistsError: pass @@ -2230,6 +2464,9 @@ def makedev(self, tarinfo, targetpath): raise ExtractError("special devices not supported by system") mode = tarinfo.mode + if mode is None: + # Use mknod's default + mode = 0o600 if tarinfo.isblk(): mode |= stat.S_IFBLK else: @@ -2251,7 +2488,6 @@ def makelink(self, tarinfo, targetpath): os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: - # See extract(). if os.path.exists(tarinfo._link_target): os.link(tarinfo._link_target, targetpath) else: @@ -2276,15 +2512,19 @@ def chown(self, tarinfo, targetpath, numeric_owner): u = tarinfo.uid if not numeric_owner: try: - if grp: + if grp and tarinfo.gname: g = grp.getgrnam(tarinfo.gname)[2] except KeyError: pass try: - if pwd: + if pwd and tarinfo.uname: u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: pass + if g is None: + g = -1 + if u is None: + u = -1 try: if tarinfo.issym() and hasattr(os, "lchown"): os.lchown(targetpath, u, g) @@ -2296,6 +2536,8 @@ def chown(self, tarinfo, targetpath, numeric_owner): def chmod(self, tarinfo, targetpath): """Set file permissions of targetpath according to tarinfo. """ + if tarinfo.mode is None: + return try: os.chmod(targetpath, tarinfo.mode) except OSError: @@ -2304,10 +2546,13 @@ def chmod(self, tarinfo, targetpath): def utime(self, tarinfo, targetpath): """Set modification time of targetpath according to tarinfo. """ + mtime = tarinfo.mtime + if mtime is None: + return if not hasattr(os, 'utime'): return try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) + os.utime(targetpath, (mtime, mtime)) except OSError: raise ExtractError("could not change modification time") @@ -2383,13 +2628,26 @@ def _getmember(self, name, tarinfo=None, normalize=False): members = self.getmembers() # Limit the member search list up to tarinfo. + skipping = False if tarinfo is not None: - members = members[:members.index(tarinfo)] + try: + index = members.index(tarinfo) + except ValueError: + # The given starting point might be a (modified) copy. + # We'll later skip members until we find an equivalent. + skipping = True + else: + # Happy fast path + members = members[:index] if normalize: name = os.path.normpath(name) for member in reversed(members): + if skipping: + if tarinfo.offset == member.offset: + skipping = False + continue if normalize: member_name = os.path.normpath(member.name) else: @@ -2398,6 +2656,10 @@ def _getmember(self, name, tarinfo=None, normalize=False): if name == member_name: return member + if skipping: + # Starting point was not found + raise ValueError(tarinfo) + def _load(self): """Read through the entire archive file and look for readable members. @@ -2490,6 +2752,7 @@ def __exit__(self, type, value, traceback): #-------------------- # exported functions #-------------------- + def is_tarfile(name): """Return True if name points to a tar archive that we are able to handle, else return False. @@ -2516,6 +2779,10 @@ def main(): parser = argparse.ArgumentParser(description=description) parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose output') + parser.add_argument('--filter', metavar='<filtername>', + choices=_NAMED_FILTERS, + help='Filter for extraction') + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-l', '--list', metavar='<tarfile>', help='Show listing of a tarfile') @@ -2527,8 +2794,12 @@ def main(): help='Create tarfile from sources') group.add_argument('-t', '--test', metavar='<tarfile>', help='Test if a tarfile is valid') + args = parser.parse_args() + if args.filter and args.extract is None: + parser.exit(1, '--filter is only valid for extraction\n') + if args.test is not None: src = args.test if is_tarfile(src): @@ -2559,7 +2830,7 @@ def main(): if is_tarfile(src): with TarFile.open(src, 'r:*') as tf: - tf.extractall(path=curdir) + tf.extractall(path=curdir, filter=args.filter) if args.verbose: if curdir == '.': msg = '{!r} file is extracted.'.format(src) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 3890df93bbcc..9041e7aa368d 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -31,6 +31,7 @@ from test import support from test.support import TESTFN, FakePath +from test.support import warnings_helper TESTFN2 = TESTFN + "2" TESTFN_SRC = TESTFN + "_SRC" @@ -1578,12 +1579,14 @@ def test_register_archive_format(self): ### shutil.unpack_archive - def check_unpack_archive(self, format): - self.check_unpack_archive_with_converter(format, lambda path: path) - self.check_unpack_archive_with_converter(format, pathlib.Path) - self.check_unpack_archive_with_converter(format, FakePath) + def check_unpack_archive(self, format, **kwargs): + self.check_unpack_archive_with_converter( + format, lambda path: path, **kwargs) + self.check_unpack_archive_with_converter( + format, pathlib.Path, **kwargs) + self.check_unpack_archive_with_converter(format, FakePath, **kwargs) - def check_unpack_archive_with_converter(self, format, converter): + def check_unpack_archive_with_converter(self, format, converter, **kwargs): root_dir, base_dir = self._create_files() expected = rlistdir(root_dir) expected.remove('outer') @@ -1593,36 +1596,47 @@ def check_unpack_archive_with_converter(self, format, converter): # let's try to unpack it now tmpdir2 = self.mkdtemp() - unpack_archive(converter(filename), converter(tmpdir2)) + unpack_archive(converter(filename), converter(tmpdir2), **kwargs) self.assertEqual(rlistdir(tmpdir2), expected) # and again, this time with the format specified tmpdir3 = self.mkdtemp() - unpack_archive(converter(filename), converter(tmpdir3), format=format) + unpack_archive(converter(filename), converter(tmpdir3), format=format, + **kwargs) self.assertEqual(rlistdir(tmpdir3), expected) - self.assertRaises(shutil.ReadError, unpack_archive, converter(TESTFN)) - self.assertRaises(ValueError, unpack_archive, converter(TESTFN), format='xxx') + with self.assertRaises(shutil.ReadError): + unpack_archive(converter(TESTFN), **kwargs) + with self.assertRaises(ValueError): + unpack_archive(converter(TESTFN), format='xxx', **kwargs) + + def check_unpack_tarball(self, format): + self.check_unpack_archive(format, filter='fully_trusted') + self.check_unpack_archive(format, filter='data') + with warnings_helper.check_no_warnings(self): + self.check_unpack_archive(format) def test_unpack_archive_tar(self): - self.check_unpack_archive('tar') + self.check_unpack_tarball('tar') @support.requires_zlib() def test_unpack_archive_gztar(self): - self.check_unpack_archive('gztar') + self.check_unpack_tarball('gztar') @support.requires_bz2() def test_unpack_archive_bztar(self): - self.check_unpack_archive('bztar') + self.check_unpack_tarball('bztar') @support.requires_lzma() @unittest.skipIf(AIX and not _maxdataOK(), "AIX MAXDATA must be 0x20000000 or larger") def test_unpack_archive_xztar(self): - self.check_unpack_archive('xztar') + self.check_unpack_tarball('xztar') @support.requires_zlib() def test_unpack_archive_zip(self): self.check_unpack_archive('zip') + with self.assertRaises(TypeError): + self.check_unpack_archive('zip', filter='data') def test_unpack_registry(self): diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 1f48dbe47547..a66f7efd2d6c 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -5,6 +5,10 @@ from contextlib import contextmanager from random import Random import pathlib +import shutil +import re +import warnings +import stat import unittest import unittest.mock @@ -12,6 +16,7 @@ from test import support from test.support import script_helper +from test.support import warnings_helper # Check for our compression modules. try: @@ -2385,7 +2390,12 @@ def test__all__(self): 'EmptyHeaderError', 'TruncatedHeaderError', 'EOFHeaderError', 'InvalidHeaderError', 'SubsequentHeaderError', 'ExFileObject', - 'main'} + 'main', + 'fully_trusted_filter', 'data_filter', + 'tar_filter', 'FilterError', 'AbsoluteLinkError', + 'OutsideDestinationError', 'SpecialFileError', + 'AbsolutePathError', 'LinkOutsideDestinationError', + } support.check__all__(self, tarfile, blacklist=blacklist) @@ -2408,6 +2418,15 @@ def make_simple_tarfile(self, tar_name): for tardata in files: tf.add(tardata, arcname=os.path.basename(tardata)) + def make_evil_tarfile(self, tar_name): + files = [support.findfile('tokenize_tests.txt')] + self.addCleanup(support.unlink, tar_name) + with tarfile.open(tar_name, 'w') as tf: + benign = tarfile.TarInfo('benign') + tf.addfile(benign, fileobj=io.BytesIO(b'')) + evil = tarfile.TarInfo('../evil') + tf.addfile(evil, fileobj=io.BytesIO(b'')) + def test_bad_use(self): rc, out, err = self.tarfilecmd_failure() self.assertEqual(out, b'') @@ -2564,6 +2583,25 @@ def test_extract_command_verbose(self): finally: support.rmtree(tarextdir) + def test_extract_command_filter(self): + self.make_evil_tarfile(tmpname) + # Make an inner directory, so the member named '../evil' + # is still extracted into `tarextdir` + destdir = os.path.join(tarextdir, 'dest') + os.mkdir(tarextdir) + try: + with support.temp_cwd(destdir): + self.tarfilecmd_failure('-e', tmpname, + '-v', + '--filter', 'data') + out = self.tarfilecmd('-e', tmpname, + '-v', + '--filter', 'fully_trusted', + PYTHONIOENCODING='utf-8') + self.assertIn(b' file is extracted.', out) + finally: + support.rmtree(tarextdir) + def test_extract_command_different_directory(self): self.make_simple_tarfile(tmpname) try: @@ -2837,6 +2875,893 @@ def test_keyword_only(self, mock_geteuid): tarfl.extract, filename_1, TEMPDIR, False, True) +class ReplaceTests(ReadTest, unittest.TestCase): + def test_replace_name(self): + member = self.tar.getmember('ustar/regtype') + replaced = member.replace(name='misc/other') + self.assertEqual(replaced.name, 'misc/other') + self.assertEqual(member.name, 'ustar/regtype') + self.assertEqual(self.tar.getmember('ustar/regtype').name, + 'ustar/regtype') + + def test_replace_deep(self): + member = self.tar.getmember('pax/regtype1') + replaced = member.replace() + replaced.pax_headers['gname'] = 'not-bar' + self.assertEqual(member.pax_headers['gname'], 'bar') + self.assertEqual( + self.tar.getmember('pax/regtype1').pax_headers['gname'], 'bar') + + def test_replace_shallow(self): + member = self.tar.getmember('pax/regtype1') + replaced = member.replace(deep=False) + replaced.pax_headers['gname'] = 'not-bar' + self.assertEqual(member.pax_headers['gname'], 'not-bar') + self.assertEqual( + self.tar.getmember('pax/regtype1').pax_headers['gname'], 'not-bar') + + def test_replace_all(self): + member = self.tar.getmember('ustar/regtype') + for attr_name in ('name', 'mtime', 'mode', 'linkname', + 'uid', 'gid', 'uname', 'gname'): + with self.subTest(attr_name=attr_name): + replaced = member.replace(**{attr_name: None}) + self.assertEqual(getattr(replaced, attr_name), None) + self.assertNotEqual(getattr(member, attr_name), None) + + def test_replace_internal(self): + member = self.tar.getmember('ustar/regtype') + with self.assertRaises(TypeError): + member.replace(offset=123456789) + + +class NoneInfoExtractTests(ReadTest): + # These mainly check that all kinds of members are extracted successfully + # if some metadata is None. + # Some of the methods do additional spot checks. + + # We also test that the default filters can deal with None. + + extraction_filter = None + + @classmethod + def setUpClass(cls): + tar = tarfile.open(tarname, mode='r', encoding="iso8859-1") + cls.control_dir = pathlib.Path(TEMPDIR) / "extractall_ctrl" + tar.errorlevel = 0 + tar.extractall(cls.control_dir, filter=cls.extraction_filter) + tar.close() + cls.control_paths = set( + p.relative_to(cls.control_dir) + for p in pathlib.Path(cls.control_dir).glob('**/*')) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.control_dir) + + def check_files_present(self, directory): + got_paths = set( + p.relative_to(directory) + for p in pathlib.Path(directory).glob('**/*')) + self.assertEqual(self.control_paths, got_paths) + + @contextmanager + def extract_with_none(self, *attr_names): + DIR = pathlib.Path(TEMPDIR) / "extractall_none" + self.tar.errorlevel = 0 + for member in self.tar.getmembers(): + for attr_name in attr_names: + setattr(member, attr_name, None) + with support.temp_dir(DIR): + self.tar.extractall(DIR, filter='fully_trusted') + self.check_files_present(DIR) + yield DIR + + def test_extractall_none_mtime(self): + # mtimes of extracted files should be later than 'now' -- the mtime + # of a previously created directory. + now = pathlib.Path(TEMPDIR).stat().st_mtime + with self.extract_with_none('mtime') as DIR: + for path in pathlib.Path(DIR).glob('**/*'): + with self.subTest(path=path): + try: + mtime = path.stat().st_mtime + except OSError: + # Some systems can't stat symlinks, ignore those + if not path.is_symlink(): + raise + else: + self.assertGreaterEqual(path.stat().st_mtime, now) + + def test_extractall_none_mode(self): + # modes of directories and regular files should match the mode + # of a "normally" created directory or regular file + dir_mode = pathlib.Path(TEMPDIR).stat().st_mode + regular_file = pathlib.Path(TEMPDIR) / 'regular_file' + regular_file.write_text('') + regular_file_mode = regular_file.stat().st_mode + with self.extract_with_none('mode') as DIR: + for path in pathlib.Path(DIR).glob('**/*'): + with self.subTest(path=path): + if path.is_dir(): + self.assertEqual(path.stat().st_mode, dir_mode) + elif path.is_file(): + self.assertEqual(path.stat().st_mode, + regular_file_mode) + + def test_extractall_none_uid(self): + with self.extract_with_none('uid'): + pass + + def test_extractall_none_gid(self): + with self.extract_with_none('gid'): + pass + + def test_extractall_none_uname(self): + with self.extract_with_none('uname'): + pass + + def test_extractall_none_gname(self): + with self.extract_with_none('gname'): + pass + + def test_extractall_none_ownership(self): + with self.extract_with_none('uid', 'gid', 'uname', 'gname'): + pass + +class NoneInfoExtractTests_Data(NoneInfoExtractTests, unittest.TestCase): + extraction_filter = 'data' + +class NoneInfoExtractTests_FullyTrusted(NoneInfoExtractTests, + unittest.TestCase): + extraction_filter = 'fully_trusted' + +class NoneInfoExtractTests_Tar(NoneInfoExtractTests, unittest.TestCase): + extraction_filter = 'tar' + +class NoneInfoExtractTests_Default(NoneInfoExtractTests, + unittest.TestCase): + extraction_filter = None + +class NoneInfoTests_Misc(unittest.TestCase): + def test_add(self): + # When addfile() encounters None metadata, it raises a ValueError + bio = io.BytesIO() + for tarformat in (tarfile.USTAR_FORMAT, tarfile.GNU_FORMAT, + tarfile.PAX_FORMAT): + with self.subTest(tarformat=tarformat): + tar = tarfile.open(fileobj=bio, mode='w', format=tarformat) + tarinfo = tar.gettarinfo(tarname) + try: + tar.addfile(tarinfo) + except Exception: + if tarformat == tarfile.USTAR_FORMAT: + # In the old, limited format, adding might fail for + # reasons like the UID being too large + pass + else: + raise + else: + for attr_name in ('mtime', 'mode', 'uid', 'gid', + 'uname', 'gname'): + with self.subTest(attr_name=attr_name): + replaced = tarinfo.replace(**{attr_name: None}) + with self.assertRaisesRegex(ValueError, + f"{attr_name}"): + tar.addfile(replaced) + + def test_list(self): + # Change some metadata to None, then compare list() output + # word-for-word. We want list() to not raise, and to only change + # printout for the affected piece of metadata. + # (n.b.: some contents of the test archive are hardcoded.) + for attr_names in ({'mtime'}, {'mode'}, {'uid'}, {'gid'}, + {'uname'}, {'gname'}, + {'uid', 'uname'}, {'gid', 'gname'}): + with (self.subTest(attr_names=attr_names), + tarfile.open(tarname, encoding="iso8859-1") as tar): + tio_prev = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') + with support.swap_attr(sys, 'stdout', tio_prev): + tar.list() + for member in tar.getmembers(): + for attr_name in attr_names: + setattr(member, attr_name, None) + tio_new = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') + with support.swap_attr(sys, 'stdout', tio_new): + tar.list() + for expected, got in zip(tio_prev.detach().getvalue().split(), + tio_new.detach().getvalue().split()): + if attr_names == {'mtime'} and re.match(rb'2003-01-\d\d', expected): + self.assertEqual(got, b'????-??-??') + elif attr_names == {'mtime'} and re.match(rb'\d\d:\d\d:\d\d', expected): + self.assertEqual(got, b'??:??:??') + elif attr_names == {'mode'} and re.match( + rb'.([r-][w-][x-]){3}', expected): + self.assertEqual(got, b'??????????') + elif attr_names == {'uname'} and expected.startswith( + (b'tarfile/', b'lars/', b'foo/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertRegex(got_user, b'[0-9]+') + elif attr_names == {'gname'} and expected.endswith( + (b'/tarfile', b'/users', b'/bar')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertRegex(got_group, b'[0-9]+') + elif attr_names == {'uid'} and expected.startswith( + (b'1000/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertEqual(got_user, b'None') + elif attr_names == {'gid'} and expected.endswith((b'/100')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertEqual(got_group, b'None') + elif attr_names == {'uid', 'uname'} and expected.startswith( + (b'tarfile/', b'lars/', b'foo/', b'1000/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertEqual(got_user, b'None') + elif attr_names == {'gname', 'gid'} and expected.endswith( + (b'/tarfile', b'/users', b'/bar', b'/100')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertEqual(got_group, b'None') + else: + # In other cases the output should be the same + self.assertEqual(expected, got) + +def _filemode_to_int(mode): + """Inverse of `stat.filemode` (for permission bits) + + Using mode strings rather than numbers makes the later tests more readable. + """ + str_mode = mode[1:] + result = ( + {'r': stat.S_IRUSR, '-': 0}[str_mode[0]] + | {'w': stat.S_IWUSR, '-': 0}[str_mode[1]] + | {'x': stat.S_IXUSR, '-': 0, + 's': stat.S_IXUSR | stat.S_ISUID, + 'S': stat.S_ISUID}[str_mode[2]] + | {'r': stat.S_IRGRP, '-': 0}[str_mode[3]] + | {'w': stat.S_IWGRP, '-': 0}[str_mode[4]] + | {'x': stat.S_IXGRP, '-': 0, + 's': stat.S_IXGRP | stat.S_ISGID, + 'S': stat.S_ISGID}[str_mode[5]] + | {'r': stat.S_IROTH, '-': 0}[str_mode[6]] + | {'w': stat.S_IWOTH, '-': 0}[str_mode[7]] + | {'x': stat.S_IXOTH, '-': 0, + 't': stat.S_IXOTH | stat.S_ISVTX, + 'T': stat.S_ISVTX}[str_mode[8]] + ) + # check we did this right + assert stat.filemode(result)[1:] == mode[1:] + + return result + +class ArchiveMaker: + """Helper to create a tar file with specific contents + + Usage: + + with ArchiveMaker() as t: + t.add('filename', ...) + + with t.open() as tar: + ... # `tar` is now a TarFile with 'filename' in it! + """ + def __init__(self): + self.bio = io.BytesIO() + + def __enter__(self): + self.tar_w = tarfile.TarFile(mode='w', fileobj=self.bio) + return self + + def __exit__(self, *exc): + self.tar_w.close() + self.contents = self.bio.getvalue() + self.bio = None + + def add(self, name, *, type=None, symlink_to=None, hardlink_to=None, + mode=None, **kwargs): + """Add a member to the test archive. Call within `with`.""" + name = str(name) + tarinfo = tarfile.TarInfo(name).replace(**kwargs) + if mode: + tarinfo.mode = _filemode_to_int(mode) + if symlink_to is not None: + type = tarfile.SYMTYPE + tarinfo.linkname = str(symlink_to) + if hardlink_to is not None: + type = tarfile.LNKTYPE + tarinfo.linkname = str(hardlink_to) + if name.endswith('/') and type is None: + type = tarfile.DIRTYPE + if type is not None: + tarinfo.type = type + if tarinfo.isreg(): + fileobj = io.BytesIO(bytes(tarinfo.size)) + else: + fileobj = None + self.tar_w.addfile(tarinfo, fileobj) + + def open(self, **kwargs): + """Open the resulting archive as TarFile. Call after `with`.""" + bio = io.BytesIO(self.contents) + return tarfile.open(fileobj=bio, **kwargs) + + +class TestExtractionFilters(unittest.TestCase): + + # A temporary directory for the extraction results. + # All files that "escape" the destination path should still end + # up in this directory. + outerdir = pathlib.Path(TEMPDIR) / 'outerdir' + + # The destination for the extraction, within `outerdir` + destdir = outerdir / 'dest' + + @contextmanager + def check_context(self, tar, filter): + """Extracts `tar` to `self.destdir` and allows checking the result + + If an error occurs, it must be checked using `expect_exception` + + Otherwise, all resulting files must be checked using `expect_file`, + except the destination directory itself and parent directories of + other files. + When checking directories, do so before their contents. + """ + with support.temp_dir(self.outerdir): + try: + tar.extractall(self.destdir, filter=filter) + except Exception as exc: + self.raised_exception = exc + self.expected_paths = set() + else: + self.raised_exception = None + self.expected_paths = set(self.outerdir.glob('**/*')) + self.expected_paths.discard(self.destdir) + try: + yield + finally: + tar.close() + if self.raised_exception: + raise self.raised_exception + self.assertEqual(self.expected_paths, set()) + + def expect_file(self, name, type=None, symlink_to=None, mode=None): + """Check a single file. See check_context.""" + if self.raised_exception: + raise self.raised_exception + # use normpath() rather than resolve() so we don't follow symlinks + path = pathlib.Path(os.path.normpath(self.destdir / name)) + self.assertIn(path, self.expected_paths) + self.expected_paths.remove(path) + + # When checking mode, ignore Windows (which can only set user read and + # user write bits). Newer versions of Python use `os_helper.can_chmod()` + # instead of hardcoding Windows. + if mode is not None and sys.platform != 'win32': + got = stat.filemode(stat.S_IMODE(path.stat().st_mode)) + self.assertEqual(got, mode) + + if type is None and isinstance(name, str) and name.endswith('/'): + type = tarfile.DIRTYPE + if symlink_to is not None: + got = (self.destdir / name).readlink() + expected = pathlib.Path(symlink_to) + # The symlink might be the same (textually) as what we expect, + # but some systems change the link to an equivalent path, so + # we fall back to samefile(). + if expected != got: + self.assertTrue(got.samefile(expected)) + elif type == tarfile.REGTYPE or type is None: + self.assertTrue(path.is_file()) + elif type == tarfile.DIRTYPE: + self.assertTrue(path.is_dir()) + elif type == tarfile.FIFOTYPE: + self.assertTrue(path.is_fifo()) + else: + raise NotImplementedError(type) + for parent in path.parents: + self.expected_paths.discard(parent) + + def expect_exception(self, exc_type, message_re='.'): + with self.assertRaisesRegex(exc_type, message_re): + if self.raised_exception is not None: + raise self.raised_exception + self.raised_exception = None + + def test_benign_file(self): + with ArchiveMaker() as arc: + arc.add('benign.txt') + for filter in 'fully_trusted', 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_file('benign.txt') + + def test_absolute(self): + # Test handling a member with an absolute path + # Inspired by 'absolute1' in https://github.com/jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add(self.outerdir / 'escaped.evil') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('../escaped.evil') + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + if str(self.outerdir).startswith('/'): + # We strip leading slashes, as e.g. GNU tar does + # (without --absolute-filenames). + outerdir_stripped = str(self.outerdir).lstrip('/') + self.expect_file(f'{outerdir_stripped}/escaped.evil') + else: + # On this system, absolute paths don't have leading + # slashes. + # So, there's nothing to strip. We refuse to unpack + # to an absolute path, nonetheless. + self.expect_exception( + tarfile.AbsolutePathError, + """['"].*escaped.evil['"] has an absolute path""") + + def test_parent_symlink(self): + # Test interplaying symlinks + # Inspired by 'dirsymlink2a' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('current', symlink_to='.') + arc.add('parent', symlink_to='current/..') + arc.add('parent/evil') + + if support.can_symlink(): + with self.check_context(arc.open(), 'fully_trusted'): + if self.raised_exception is not None: + # Windows will refuse to create a file that's a symlink to itself + # (and tarfile doesn't swallow that exception) + self.expect_exception(FileExistsError) + # The other cases will fail with this error too. + # Skip the rest of this test. + return + else: + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='current/..') + self.expect_file('../evil') + + with self.check_context(arc.open(), 'tar'): + self.expect_exception( + tarfile.OutsideDestinationError, + """'parent/evil' would be extracted to ['"].*evil['"], """ + + "which is outside the destination") + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'parent' would link to ['"].*outerdir['"], """ + + "which is outside the destination") + + else: + # No symlink support. The symlinks are ignored. + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('parent/evil') + with self.check_context(arc.open(), 'tar'): + self.expect_file('parent/evil') + with self.check_context(arc.open(), 'data'): + self.expect_file('parent/evil') + + def test_parent_symlink2(self): + # Test interplaying symlinks + # Inspired by 'dirsymlink2b' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('current', symlink_to='.') + arc.add('current/parent', symlink_to='..') + arc.add('parent/evil') + + with self.check_context(arc.open(), 'fully_trusted'): + if support.can_symlink(): + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='..') + self.expect_file('../evil') + else: + self.expect_file('current/') + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'tar'): + if support.can_symlink(): + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + self.expect_file('current/') + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'current/parent' would link to ['"].*['"], """ + + "which is outside the destination") + + def test_absolute_symlink(self): + # Test symlink to an absolute path + # Inspired by 'dirsymlink' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('parent', symlink_to=self.outerdir) + arc.add('parent/evil') + + with self.check_context(arc.open(), 'fully_trusted'): + if support.can_symlink(): + self.expect_file('parent', symlink_to=self.outerdir) + self.expect_file('../evil') + else: + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'tar'): + if support.can_symlink(): + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.AbsoluteLinkError, + "'parent' is a symlink to an absolute path") + + def test_sly_relative0(self): + # Inspired by 'relative0' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('../moo', symlink_to='..//tmp/moo') + + try: + with self.check_context(arc.open(), filter='fully_trusted'): + if support.can_symlink(): + if isinstance(self.raised_exception, FileExistsError): + # XXX TarFile happens to fail creating a parent + # directory. + # This might be a bug, but fixing it would hurt + # security. + # Note that e.g. GNU `tar` rejects '..' components, + # so you could argue this is an invalid archive and we + # just raise an bad type of exception. + self.expect_exception(FileExistsError) + else: + self.expect_file('../moo', symlink_to='..//tmp/moo') + else: + # The symlink can't be extracted and is ignored + pass + except FileExistsError: + pass + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_exception( + tarfile.OutsideDestinationError, + "'../moo' would be extracted to " + + "'.*moo', which is outside " + + "the destination") + + def test_sly_relative2(self): + # Inspired by 'relative2' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('tmp/') + arc.add('tmp/../../moo', symlink_to='tmp/../..//tmp/moo') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('tmp', type=tarfile.DIRTYPE) + if support.can_symlink(): + self.expect_file('../moo', symlink_to='tmp/../../tmp/moo') + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_exception( + tarfile.OutsideDestinationError, + "'tmp/../../moo' would be extracted to " + + """['"].*moo['"], which is outside the """ + + "destination") + + def test_modes(self): + # Test how file modes are extracted + # (Note that the modes are ignored on platforms without working chmod) + with ArchiveMaker() as arc: + arc.add('all_bits', mode='?rwsrwsrwt') + arc.add('perm_bits', mode='?rwxrwxrwx') + arc.add('exec_group_other', mode='?rw-rwxrwx') + arc.add('read_group_only', mode='?---r-----') + arc.add('no_bits', mode='?---------') + arc.add('dir/', mode='?---rwsrwt') + + # On some systems, setting the sticky bit is a no-op. + # Check if that's the case. + tmp_filename = os.path.join(TEMPDIR, "tmp.file") + with open(tmp_filename, 'w'): + pass + os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) + have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + os.unlink(tmp_filename) + + os.mkdir(tmp_filename) + os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) + have_sticky_dirs = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + os.rmdir(tmp_filename) + + with self.check_context(arc.open(), 'fully_trusted'): + if have_sticky_files: + self.expect_file('all_bits', mode='?rwsrwsrwt') + else: + self.expect_file('all_bits', mode='?rwsrwsrwx') + self.expect_file('perm_bits', mode='?rwxrwxrwx') + self.expect_file('exec_group_other', mode='?rw-rwxrwx') + self.expect_file('read_group_only', mode='?---r-----') + self.expect_file('no_bits', mode='?---------') + if have_sticky_dirs: + self.expect_file('dir/', mode='?---rwsrwt') + else: + self.expect_file('dir/', mode='?---rwsrwx') + + with self.check_context(arc.open(), 'tar'): + self.expect_file('all_bits', mode='?rwxr-xr-x') + self.expect_file('perm_bits', mode='?rwxr-xr-x') + self.expect_file('exec_group_other', mode='?rw-r-xr-x') + self.expect_file('read_group_only', mode='?---r-----') + self.expect_file('no_bits', mode='?---------') + self.expect_file('dir/', mode='?---r-xr-x') + + with self.check_context(arc.open(), 'data'): + normal_dir_mode = stat.filemode(stat.S_IMODE( + self.outerdir.stat().st_mode)) + self.expect_file('all_bits', mode='?rwxr-xr-x') + self.expect_file('perm_bits', mode='?rwxr-xr-x') + self.expect_file('exec_group_other', mode='?rw-r--r--') + self.expect_file('read_group_only', mode='?rw-r-----') + self.expect_file('no_bits', mode='?rw-------') + self.expect_file('dir/', mode=normal_dir_mode) + + def test_pipe(self): + # Test handling of a special file + with ArchiveMaker() as arc: + arc.add('foo', type=tarfile.FIFOTYPE) + + for filter in 'fully_trusted', 'tar': + with self.check_context(arc.open(), filter): + if hasattr(os, 'mkfifo'): + self.expect_file('foo', type=tarfile.FIFOTYPE) + else: + # The pipe can't be extracted and is skipped. + pass + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.SpecialFileError, + "'foo' is a special file") + + def test_special_files(self): + # Creating device files is tricky. Instead of attempting that let's + # only check the filter result. + for special_type in tarfile.FIFOTYPE, tarfile.CHRTYPE, tarfile.BLKTYPE: + tarinfo = tarfile.TarInfo('foo') + tarinfo.type = special_type + trusted = tarfile.fully_trusted_filter(tarinfo, '') + self.assertIs(trusted, tarinfo) + tar = tarfile.tar_filter(tarinfo, '') + self.assertEqual(tar.type, special_type) + with self.assertRaises(tarfile.SpecialFileError) as cm: + tarfile.data_filter(tarinfo, '') + self.assertIsInstance(cm.exception.tarinfo, tarfile.TarInfo) + self.assertEqual(cm.exception.tarinfo.name, 'foo') + + def test_fully_trusted_filter(self): + # The 'fully_trusted' filter returns the original TarInfo objects. + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + filtered = tarfile.fully_trusted_filter(tarinfo, '') + self.assertIs(filtered, tarinfo) + + def test_tar_filter(self): + # The 'tar' filter returns TarInfo objects with the same name/type. + # (It can also fail for particularly "evil" input, but we don't have + # that in the test archive.) + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + filtered = tarfile.tar_filter(tarinfo, '') + self.assertIs(filtered.name, tarinfo.name) + self.assertIs(filtered.type, tarinfo.type) + + def test_data_filter(self): + # The 'data' filter either raises, or returns TarInfo with the same + # name/type. + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + try: + filtered = tarfile.data_filter(tarinfo, '') + except tarfile.FilterError: + continue + self.assertIs(filtered.name, tarinfo.name) + self.assertIs(filtered.type, tarinfo.type) + + def test_default_filter_warns_not(self): + """Ensure the default filter does not warn (like in 3.12)""" + with ArchiveMaker() as arc: + arc.add('foo') + with warnings_helper.check_no_warnings(self): + with self.check_context(arc.open(), None): + self.expect_file('foo') + + def test_change_default_filter_on_instance(self): + tar = tarfile.TarFile(tarname, 'r') + def strict_filter(tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + tar.extraction_filter = strict_filter + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_on_class(self): + def strict_filter(tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + tar = tarfile.TarFile(tarname, 'r') + with support.swap_attr(tarfile.TarFile, 'extraction_filter', + staticmethod(strict_filter)): + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_on_subclass(self): + class TarSubclass(tarfile.TarFile): + def extraction_filter(self, tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + + tar = TarSubclass(tarname, 'r') + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_to_string(self): + tar = tarfile.TarFile(tarname, 'r') + tar.extraction_filter = 'data' + with self.check_context(tar, None): + self.expect_exception(TypeError) + + def test_custom_filter(self): + def custom_filter(tarinfo, path): + self.assertIs(path, self.destdir) + if tarinfo.name == 'move_this': + return tarinfo.replace(name='moved') + if tarinfo.name == 'ignore_this': + return None + return tarinfo + + with ArchiveMaker() as arc: + arc.add('move_this') + arc.add('ignore_this') + arc.add('keep') + with self.check_context(arc.open(), custom_filter): + self.expect_file('moved') + self.expect_file('keep') + + def test_bad_filter_name(self): + with ArchiveMaker() as arc: + arc.add('foo') + with self.check_context(arc.open(), 'bad filter name'): + self.expect_exception(ValueError) + + def test_stateful_filter(self): + # Stateful filters should be possible. + # (This doesn't really test tarfile. Rather, it demonstrates + # that third parties can implement a stateful filter.) + class StatefulFilter: + def __enter__(self): + self.num_files_processed = 0 + return self + + def __call__(self, tarinfo, path): + try: + tarinfo = tarfile.data_filter(tarinfo, path) + except tarfile.FilterError: + return None + self.num_files_processed += 1 + return tarinfo + + def __exit__(self, *exc_info): + self.done = True + + with ArchiveMaker() as arc: + arc.add('good') + arc.add('bad', symlink_to='/') + arc.add('good') + with StatefulFilter() as custom_filter: + with self.check_context(arc.open(), custom_filter): + self.expect_file('good') + self.assertEqual(custom_filter.num_files_processed, 2) + self.assertEqual(custom_filter.done, True) + + def test_errorlevel(self): + def extracterror_filter(tarinfo, path): + raise tarfile.ExtractError('failed with ExtractError') + def filtererror_filter(tarinfo, path): + raise tarfile.FilterError('failed with FilterError') + def oserror_filter(tarinfo, path): + raise OSError('failed with OSError') + def tarerror_filter(tarinfo, path): + raise tarfile.TarError('failed with base TarError') + def valueerror_filter(tarinfo, path): + raise ValueError('failed with ValueError') + + with ArchiveMaker() as arc: + arc.add('file') + + # If errorlevel is 0, errors affected by errorlevel are ignored + + with self.check_context(arc.open(errorlevel=0), extracterror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), filtererror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), oserror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=0), valueerror_filter): + self.expect_exception(ValueError) + + # If 1, all fatal errors are raised + + with self.check_context(arc.open(errorlevel=1), extracterror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=1), filtererror_filter): + self.expect_exception(tarfile.FilterError) + + with self.check_context(arc.open(errorlevel=1), oserror_filter): + self.expect_exception(OSError) + + with self.check_context(arc.open(errorlevel=1), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=1), valueerror_filter): + self.expect_exception(ValueError) + + # If 2, all non-fatal errors are raised as well. + + with self.check_context(arc.open(errorlevel=2), extracterror_filter): + self.expect_exception(tarfile.ExtractError) + + with self.check_context(arc.open(errorlevel=2), filtererror_filter): + self.expect_exception(tarfile.FilterError) + + with self.check_context(arc.open(errorlevel=2), oserror_filter): + self.expect_exception(OSError) + + with self.check_context(arc.open(errorlevel=2), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=2), valueerror_filter): + self.expect_exception(ValueError) + + # We only handle ExtractionError, FilterError & OSError specially. + + with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter): + self.expect_exception(TypeError) # errorlevel is not int + + def setUpModule(): support.unlink(TEMPDIR) os.makedirs(TEMPDIR) diff --git a/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst new file mode 100644 index 000000000000..48a105a4a17b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst @@ -0,0 +1,4 @@ +The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, +have a new a *filter* argument that allows limiting tar features than may be +surprising or dangerous, such as creating files outside the destination +directory. See :ref:`tarfile-extraction-filter` for details. From webhook-mailer at python.org Mon May 15 13:33:39 2023 From: webhook-mailer at python.org (barneygale) Date: Mon, 15 May 2023 17:33:39 -0000 Subject: [Python-checkins] GH-102613: Fix recursion error from `pathlib.Path.glob()` (GH-104373) Message-ID: <mailman.373.1684172020.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cb88ae635e96d7020ba6187bcfd45ace4dcd8395 commit: cb88ae635e96d7020ba6187bcfd45ace4dcd8395 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-15T18:33:32+01:00 summary: GH-102613: Fix recursion error from `pathlib.Path.glob()` (GH-104373) Use `Path.walk()` to implement the recursive wildcard `**`. This method uses an iterative (rather than recursive) walk - see GH-100282. files: A Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 40b72930e1f0..ef7c47c9e775 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -164,30 +164,15 @@ class _RecursiveWildcardSelector(_Selector): def __init__(self, pat, child_parts, flavour, case_sensitive): _Selector.__init__(self, child_parts, flavour, case_sensitive) - def _iterate_directories(self, parent_path, scandir): + def _iterate_directories(self, parent_path): yield parent_path - try: - # We must close the scandir() object before proceeding to - # avoid exhausting file descriptors when globbing deep trees. - with scandir(parent_path) as scandir_it: - entries = list(scandir_it) - except OSError: - pass - else: - for entry in entries: - entry_is_dir = False - try: - entry_is_dir = entry.is_dir(follow_symlinks=False) - except OSError: - pass - if entry_is_dir: - path = parent_path._make_child_relpath(entry.name) - for p in self._iterate_directories(path, scandir): - yield p + for dirpath, dirnames, _ in parent_path.walk(): + for dirname in dirnames: + yield dirpath._make_child_relpath(dirname) def _select_from(self, parent_path, scandir): successor_select = self.successor._select_from - for starting_point in self._iterate_directories(parent_path, scandir): + for starting_point in self._iterate_directories(parent_path): for p in successor_select(starting_point, scandir): yield p diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 67ca4795962b..46a5248499c5 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1972,6 +1972,17 @@ def test_glob_long_symlink(self): bad_link.symlink_to("bad" * 200) self.assertEqual(sorted(base.glob('**/*')), [bad_link]) + def test_glob_above_recursion_limit(self): + recursion_limit = 40 + # directory_depth > recursion_limit + directory_depth = recursion_limit + 10 + base = pathlib.Path(os_helper.TESTFN, 'deep') + path = pathlib.Path(base, *(['d'] * directory_depth)) + path.mkdir(parents=True) + + with set_recursion_limit(recursion_limit): + list(base.glob('**')) + def _check_resolve(self, p, expected, strict=True): q = p.resolve(strict) self.assertEqual(q, expected) diff --git a/Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst b/Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst new file mode 100644 index 000000000000..3b06964dc8d2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst @@ -0,0 +1,2 @@ +Fix issue where :meth:`pathlib.Path.glob` raised :exc:`RecursionError` when +walking deep directory trees. From webhook-mailer at python.org Mon May 15 15:59:33 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 15 May 2023 19:59:33 -0000 Subject: [Python-checkins] gh-104341: Adjust tstate_must_exit() to Respect Interpreter Finalization (gh-104437) Message-ID: <mailman.374.1684180774.13550.python-checkins@python.org> https://github.com/python/cpython/commit/26baa747c2ebc2beeff769bb07b5fb5a51ad5f4b commit: 26baa747c2ebc2beeff769bb07b5fb5a51ad5f4b branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-15T13:59:26-06:00 summary: gh-104341: Adjust tstate_must_exit() to Respect Interpreter Finalization (gh-104437) With the move to a per-interpreter GIL, this check slipped through the cracks. files: M Include/cpython/pylifecycle.h M Include/internal/pycore_interp.h M Modules/_asynciomodule.c M Modules/_io/bufferedio.c M Modules/_sqlite/connection.c M Modules/_winapi.c M Python/_warnings.c M Python/ceval_gil.c M Python/pylifecycle.c M Python/pystate.c M Python/sysmodule.c diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index 08569ee683ce..314a5cc5b942 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -52,6 +52,7 @@ PyAPI_FUNC(const char *) _Py_gitidentifier(void); PyAPI_FUNC(const char *) _Py_gitversion(void); PyAPI_FUNC(int) _Py_IsFinalizing(void); +PyAPI_FUNC(int) _Py_IsInterpreterFinalizing(PyInterpreterState *interp); /* Random */ PyAPI_FUNC(int) _PyOS_URandom(void *buffer, Py_ssize_t size); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 527b2121148f..edc076fc04f6 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -83,6 +83,13 @@ struct _is { int _initialized; int finalizing; + /* Set by Py_EndInterpreter(). + + Use _PyInterpreterState_GetFinalizing() + and _PyInterpreterState_SetFinalizing() + to access it, don't access it directly. */ + _Py_atomic_address _finalizing; + struct _obmalloc_state obmalloc; struct _ceval_state ceval; @@ -191,6 +198,17 @@ struct _is { extern void _PyInterpreterState_Clear(PyThreadState *tstate); +static inline PyThreadState* +_PyInterpreterState_GetFinalizing(PyInterpreterState *interp) { + return (PyThreadState*)_Py_atomic_load_relaxed(&interp->_finalizing); +} + +static inline void +_PyInterpreterState_SetFinalizing(PyInterpreterState *interp, PyThreadState *tstate) { + _Py_atomic_store_relaxed(&interp->_finalizing, (uintptr_t)tstate); +} + + /* cross-interpreter data registry */ /* For now we use a global registry of shareable classes. An diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 3830245abe87..7e33558dba3e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -526,7 +526,7 @@ future_init(FutureObj *fut, PyObject *loop) if (is_true < 0) { return -1; } - if (is_true && !_Py_IsFinalizing()) { + if (is_true && !_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) { /* Only try to capture the traceback if the interpreter is not being finalized. The original motivation to add a `_Py_IsFinalizing()` call was to prevent SIGSEGV when a Future is created in a __del__ diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 6f291c344960..7a0c516411c7 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -293,7 +293,8 @@ _enter_buffered_busy(buffered *self) "reentrant call inside %R", self); return 0; } - relax_locking = _Py_IsFinalizing(); + PyInterpreterState *interp = PyInterpreterState_Get(); + relax_locking = _Py_IsInterpreterFinalizing(interp); Py_BEGIN_ALLOW_THREADS if (!relax_locking) st = PyThread_acquire_lock(self->lock, 1); diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 7bbb462ed54d..5c57a4101c4a 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -419,7 +419,7 @@ connection_close(pysqlite_Connection *self) { /* If close is implicitly called as a result of interpreter * tear-down, we must not call back into Python. */ - if (_Py_IsFinalizing()) { + if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) { remove_callbacks(self->db); } (void)connection_exec_stmt(self, "ROLLBACK"); diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 473bcb4736e9..1e02dbc1a4bf 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -133,7 +133,7 @@ overlapped_dealloc(OverlappedObject *self) { /* The operation is no longer pending -- nothing to do. */ } - else if (_Py_IsFinalizing()) + else if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) { /* The operation is still pending -- give a warning. This will probably only happen on Windows XP. */ diff --git a/Python/_warnings.c b/Python/_warnings.c index 5644db9a3770..dec658680241 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -198,7 +198,7 @@ get_warnings_attr(PyInterpreterState *interp, PyObject *attr, int try_import) PyObject *warnings_module, *obj; /* don't try to import after the start of the Python finallization */ - if (try_import && !_Py_IsFinalizing()) { + if (try_import && !_Py_IsInterpreterFinalizing(interp)) { warnings_module = PyImport_Import(&_Py_ID(warnings)); if (warnings_module == NULL) { /* Fallback to the C implementation if we cannot get diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 42e1436bc913..b9bdb74fcedf 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -332,6 +332,9 @@ tstate_must_exit(PyThreadState *tstate) After Py_Finalize() has been called, tstate can be a dangling pointer: point to PyThreadState freed memory. */ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); + if (finalizing == NULL) { + finalizing = _PyInterpreterState_GetFinalizing(tstate->interp); + } return (finalizing != NULL && finalizing != tstate); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index c5dc0f44a380..cb87f2c08601 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1788,6 +1788,7 @@ Py_FinalizeEx(void) /* Remaining daemon threads will automatically exit when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ + _PyInterpreterState_SetFinalizing(tstate->interp, tstate); _PyRuntimeState_SetFinalizing(runtime, tstate); runtime->initialized = 0; runtime->core_initialized = 0; @@ -2142,6 +2143,10 @@ Py_EndInterpreter(PyThreadState *tstate) Py_FatalError("not the last thread"); } + /* Remaining daemon threads will automatically exit + when they attempt to take the GIL (ex: PyEval_RestoreThread()). */ + _PyInterpreterState_SetFinalizing(interp, tstate); + // XXX Call something like _PyImport_Disable() here? _PyImport_FiniExternal(tstate->interp); @@ -2152,6 +2157,18 @@ Py_EndInterpreter(PyThreadState *tstate) finalize_interp_delete(tstate->interp); } +int +_Py_IsInterpreterFinalizing(PyInterpreterState *interp) +{ + /* We check the runtime first since, in a daemon thread, + interp might be dangling pointer. */ + PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(&_PyRuntime); + if (finalizing == NULL) { + finalizing = _PyInterpreterState_GetFinalizing(interp); + } + return finalizing != NULL; +} + /* Add the __main__ module */ static PyStatus diff --git a/Python/pystate.c b/Python/pystate.c index 26debf1f88b9..25e655a20279 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1436,11 +1436,13 @@ PyThreadState_Clear(PyThreadState *tstate) if (verbose && tstate->cframe->current_frame != NULL) { /* bpo-20526: After the main thread calls - _PyRuntimeState_SetFinalizing() in Py_FinalizeEx(), threads must - exit when trying to take the GIL. If a thread exit in the middle of - _PyEval_EvalFrameDefault(), tstate->frame is not reset to its - previous value. It is more likely with daemon threads, but it can - happen with regular threads if threading._shutdown() fails + _PyInterpreterState_SetFinalizing() in Py_FinalizeEx() + (or in Py_EndInterpreter() for subinterpreters), + threads must exit when trying to take the GIL. + If a thread exit in the middle of _PyEval_EvalFrameDefault(), + tstate->frame is not reset to its previous value. + It is more likely with daemon threads, but it can happen + with regular threads if threading._shutdown() fails (ex: interrupted by CTRL+C). */ fprintf(stderr, "PyThreadState_Clear: warning: thread still has a frame\n"); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 894a3e8a98fd..c116c40538a2 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -332,6 +332,7 @@ _PySys_ClearAuditHooks(PyThreadState *ts) } _PyRuntimeState *runtime = ts->interp->runtime; + /* The hooks are global so we have to check for runtime finalization. */ PyThreadState *finalizing = _PyRuntimeState_GetFinalizing(runtime); assert(finalizing == ts); if (finalizing != ts) { @@ -2039,6 +2040,9 @@ sys__clear_type_cache_impl(PyObject *module) Py_RETURN_NONE; } +/* Note that, for now, we do not have a per-interpreter equivalent + for sys.is_finalizing(). */ + /*[clinic input] sys.is_finalizing From webhook-mailer at python.org Mon May 15 16:54:02 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 15 May 2023 20:54:02 -0000 Subject: [Python-checkins] gh-104482: Fix error handling bugs in ast.c (#104483) Message-ID: <mailman.375.1684184044.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8a3702f0c79e5a99fcef61e35724f4b9ea3453b8 commit: 8a3702f0c79e5a99fcef61e35724f4b9ea3453b8 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-15T21:53:55+01:00 summary: gh-104482: Fix error handling bugs in ast.c (#104483) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst M Lib/test/test_ast.py M Python/ast.c M Python/compile.c diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index fdd21aca06ff..34808ed8562e 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -2035,6 +2035,12 @@ def test_stdlib_validates(self): kwd_attrs=[], kwd_patterns=[ast.MatchStar()] ), + ast.MatchClass( + constant_true, # invalid name + patterns=[], + kwd_attrs=['True'], + kwd_patterns=[pattern_1] + ), ast.MatchSequence( [ ast.MatchStar("True") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst new file mode 100644 index 000000000000..07c09a3a84a6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst @@ -0,0 +1 @@ +Fix three error handling bugs in ast.c's validation of pattern matching statements. diff --git a/Python/ast.c b/Python/ast.c index 50fc8e01fb3f..f079e64bbdfc 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -46,6 +46,7 @@ static int validate_pattern(struct validator *, pattern_ty, int); static int validate_name(PyObject *name) { + assert(!PyErr_Occurred()); assert(PyUnicode_Check(name)); static const char * const forbidden[] = { "None", @@ -65,12 +66,12 @@ validate_name(PyObject *name) static int validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) { - Py_ssize_t i; + assert(!PyErr_Occurred()); if (!asdl_seq_LEN(gens)) { PyErr_SetString(PyExc_ValueError, "comprehension with no generators"); return 0; } - for (i = 0; i < asdl_seq_LEN(gens); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(gens); i++) { comprehension_ty comp = asdl_seq_GET(gens, i); if (!validate_expr(state, comp->target, Store) || !validate_expr(state, comp->iter, Load) || @@ -83,8 +84,8 @@ validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) static int validate_keywords(struct validator *state, asdl_keyword_seq *keywords) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(keywords); i++) + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(keywords); i++) if (!validate_expr(state, (asdl_seq_GET(keywords, i))->value, Load)) return 0; return 1; @@ -93,8 +94,8 @@ validate_keywords(struct validator *state, asdl_keyword_seq *keywords) static int validate_args(struct validator *state, asdl_arg_seq *args) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(args); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = asdl_seq_GET(args, i); VALIDATE_POSITIONS(arg); if (arg->annotation && !validate_expr(state, arg->annotation, Load)) @@ -121,6 +122,7 @@ expr_context_name(expr_context_ty ctx) static int validate_arguments(struct validator *state, arguments_ty args) { + assert(!PyErr_Occurred()); if (!validate_args(state, args->posonlyargs) || !validate_args(state, args->args)) { return 0; } @@ -149,6 +151,7 @@ validate_arguments(struct validator *state, arguments_ty args) static int validate_constant(struct validator *state, PyObject *value) { + assert(!PyErr_Occurred()); if (value == Py_None || value == Py_Ellipsis) return 1; @@ -205,6 +208,7 @@ validate_constant(struct validator *state, PyObject *value) static int validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(exp); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { @@ -465,6 +469,7 @@ ensure_literal_complex(expr_ty exp) static int validate_pattern_match_value(struct validator *state, expr_ty exp) { + assert(!PyErr_Occurred()); if (!validate_expr(state, exp, Load)) { return 0; } @@ -518,6 +523,7 @@ validate_pattern_match_value(struct validator *state, expr_ty exp) static int validate_capture(PyObject *name) { + assert(!PyErr_Occurred()); if (_PyUnicode_EqualToASCIIString(name, "_")) { PyErr_Format(PyExc_ValueError, "can't capture name '_' in patterns"); return 0; @@ -528,6 +534,7 @@ validate_capture(PyObject *name) static int validate_pattern(struct validator *state, pattern_ty p, int star_ok) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(p); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { @@ -580,7 +587,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } - + if (ret == 0) { + break; + } ret = validate_patterns(state, p->v.MatchMapping.patterns, /*star_ok=*/0); break; case MatchClass_kind: @@ -611,6 +620,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } + if (ret == 0) { + break; + } for (Py_ssize_t i = 0; i < asdl_seq_LEN(p->v.MatchClass.kwd_attrs); i++) { PyObject *identifier = asdl_seq_GET(p->v.MatchClass.kwd_attrs, i); @@ -619,6 +631,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } + if (ret == 0) { + break; + } if (!validate_patterns(state, p->v.MatchClass.patterns, /*star_ok=*/0)) { ret = 0; @@ -685,6 +700,7 @@ _validate_nonempty_seq(asdl_seq *seq, const char *what, const char *owner) static int validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_context_ty ctx) { + assert(!PyErr_Occurred()); return validate_nonempty_seq(targets, "targets", ctx == Del ? "Delete" : "Assign") && validate_exprs(state, targets, ctx, 0); } @@ -692,15 +708,16 @@ validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_contex static int validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner) { + assert(!PyErr_Occurred()); return validate_nonempty_seq(body, "body", owner) && validate_stmts(state, body); } static int validate_stmt(struct validator *state, stmt_ty stmt) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(stmt); int ret = -1; - Py_ssize_t i; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); @@ -771,7 +788,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) case With_kind: if (!validate_nonempty_seq(stmt->v.With.items, "items", "With")) return 0; - for (i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.With.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) @@ -782,7 +799,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) case AsyncWith_kind: if (!validate_nonempty_seq(stmt->v.AsyncWith.items, "items", "AsyncWith")) return 0; - for (i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.AsyncWith.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) @@ -795,7 +812,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) || !validate_nonempty_seq(stmt->v.Match.cases, "cases", "Match")) { return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { match_case_ty m = asdl_seq_GET(stmt->v.Match.cases, i); if (!validate_pattern(state, m->pattern, /*star_ok=*/0) || (m->guard && !validate_expr(state, m->guard, Load)) @@ -830,7 +847,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) PyErr_SetString(PyExc_ValueError, "Try has orelse but no except handlers"); return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i); VALIDATE_POSITIONS(handler); if ((handler->v.ExceptHandler.type && @@ -856,7 +873,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) PyErr_SetString(PyExc_ValueError, "TryStar has orelse but no except handlers"); return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.TryStar.handlers, i); if ((handler->v.ExceptHandler.type && !validate_expr(state, handler->v.ExceptHandler.type, Load)) || @@ -916,8 +933,8 @@ validate_stmt(struct validator *state, stmt_ty stmt) static int validate_stmts(struct validator *state, asdl_stmt_seq *seq) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(seq); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(seq); i++) { stmt_ty stmt = asdl_seq_GET(seq, i); if (stmt) { if (!validate_stmt(state, stmt)) @@ -935,8 +952,8 @@ validate_stmts(struct validator *state, asdl_stmt_seq *seq) static int validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ctx, int null_ok) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(exprs); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(exprs); i++) { expr_ty expr = asdl_seq_GET(exprs, i); if (expr) { if (!validate_expr(state, expr, ctx)) @@ -955,8 +972,8 @@ validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ct static int validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ok) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(patterns); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(patterns); i++) { pattern_ty pattern = asdl_seq_GET(patterns, i); if (!validate_pattern(state, pattern, star_ok)) { return 0; @@ -972,6 +989,7 @@ validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ int _PyAST_Validate(mod_ty mod) { + assert(!PyErr_Occurred()); int res = -1; struct validator state; PyThreadState *tstate; diff --git a/Python/compile.c b/Python/compile.c index f8d0197e9f06..bf5e4a52482a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -567,6 +567,7 @@ PyCodeObject * _PyAST_Compile(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, int optimize, PyArena *arena) { + assert(!PyErr_Occurred()); struct compiler *c = new_compiler(mod, filename, pflags, optimize, arena); if (c == NULL) { return NULL; From webhook-mailer at python.org Mon May 15 16:59:48 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 15 May 2023 20:59:48 -0000 Subject: [Python-checkins] gh-104469: Convert _testcapi/watchers.c to use Argument Clinic (#104503) Message-ID: <mailman.376.1684184388.13550.python-checkins@python.org> https://github.com/python/cpython/commit/456d56698db6c6287500f591927c900a5f5221ca commit: 456d56698db6c6287500f591927c900a5f5221ca branch: main author: Nikita Sobolev <mail at sobolevn.me> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-15T22:59:41+02:00 summary: gh-104469: Convert _testcapi/watchers.c to use Argument Clinic (#104503) Remove boilerplate code by converting the following functions: - _testcapi.watch_dict - _testcapi.unwatch_dict - _testcapi.watch_type - _testcapi.unwatch_type - _testcapi.set_func_defaults_via_capi - _testcapi.set_func_kwdefaults_via_capi files: A Modules/_testcapi/clinic/watchers.c.h M Modules/_testcapi/watchers.c diff --git a/Modules/_testcapi/clinic/watchers.c.h b/Modules/_testcapi/clinic/watchers.c.h new file mode 100644 index 000000000000..975244bd59a3 --- /dev/null +++ b/Modules/_testcapi/clinic/watchers.c.h @@ -0,0 +1,198 @@ +/*[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(_testcapi_watch_dict__doc__, +"watch_dict($module, watcher_id, dict, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_WATCH_DICT_METHODDEF \ + {"watch_dict", _PyCFunction_CAST(_testcapi_watch_dict), METH_FASTCALL, _testcapi_watch_dict__doc__}, + +static PyObject * +_testcapi_watch_dict_impl(PyObject *module, int watcher_id, PyObject *dict); + +static PyObject * +_testcapi_watch_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int watcher_id; + PyObject *dict; + + if (!_PyArg_CheckPositional("watch_dict", nargs, 2, 2)) { + goto exit; + } + watcher_id = _PyLong_AsInt(args[0]); + if (watcher_id == -1 && PyErr_Occurred()) { + goto exit; + } + dict = args[1]; + return_value = _testcapi_watch_dict_impl(module, watcher_id, dict); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_unwatch_dict__doc__, +"unwatch_dict($module, watcher_id, dict, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_UNWATCH_DICT_METHODDEF \ + {"unwatch_dict", _PyCFunction_CAST(_testcapi_unwatch_dict), METH_FASTCALL, _testcapi_unwatch_dict__doc__}, + +static PyObject * +_testcapi_unwatch_dict_impl(PyObject *module, int watcher_id, PyObject *dict); + +static PyObject * +_testcapi_unwatch_dict(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int watcher_id; + PyObject *dict; + + if (!_PyArg_CheckPositional("unwatch_dict", nargs, 2, 2)) { + goto exit; + } + watcher_id = _PyLong_AsInt(args[0]); + if (watcher_id == -1 && PyErr_Occurred()) { + goto exit; + } + dict = args[1]; + return_value = _testcapi_unwatch_dict_impl(module, watcher_id, dict); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_watch_type__doc__, +"watch_type($module, watcher_id, type, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_WATCH_TYPE_METHODDEF \ + {"watch_type", _PyCFunction_CAST(_testcapi_watch_type), METH_FASTCALL, _testcapi_watch_type__doc__}, + +static PyObject * +_testcapi_watch_type_impl(PyObject *module, int watcher_id, PyObject *type); + +static PyObject * +_testcapi_watch_type(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int watcher_id; + PyObject *type; + + if (!_PyArg_CheckPositional("watch_type", nargs, 2, 2)) { + goto exit; + } + watcher_id = _PyLong_AsInt(args[0]); + if (watcher_id == -1 && PyErr_Occurred()) { + goto exit; + } + type = args[1]; + return_value = _testcapi_watch_type_impl(module, watcher_id, type); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_unwatch_type__doc__, +"unwatch_type($module, watcher_id, type, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_UNWATCH_TYPE_METHODDEF \ + {"unwatch_type", _PyCFunction_CAST(_testcapi_unwatch_type), METH_FASTCALL, _testcapi_unwatch_type__doc__}, + +static PyObject * +_testcapi_unwatch_type_impl(PyObject *module, int watcher_id, PyObject *type); + +static PyObject * +_testcapi_unwatch_type(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int watcher_id; + PyObject *type; + + if (!_PyArg_CheckPositional("unwatch_type", nargs, 2, 2)) { + goto exit; + } + watcher_id = _PyLong_AsInt(args[0]); + if (watcher_id == -1 && PyErr_Occurred()) { + goto exit; + } + type = args[1]; + return_value = _testcapi_unwatch_type_impl(module, watcher_id, type); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_set_func_defaults_via_capi__doc__, +"set_func_defaults_via_capi($module, func, defaults, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_SET_FUNC_DEFAULTS_VIA_CAPI_METHODDEF \ + {"set_func_defaults_via_capi", _PyCFunction_CAST(_testcapi_set_func_defaults_via_capi), METH_FASTCALL, _testcapi_set_func_defaults_via_capi__doc__}, + +static PyObject * +_testcapi_set_func_defaults_via_capi_impl(PyObject *module, PyObject *func, + PyObject *defaults); + +static PyObject * +_testcapi_set_func_defaults_via_capi(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *defaults; + + if (!_PyArg_CheckPositional("set_func_defaults_via_capi", nargs, 2, 2)) { + goto exit; + } + func = args[0]; + defaults = args[1]; + return_value = _testcapi_set_func_defaults_via_capi_impl(module, func, defaults); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_set_func_kwdefaults_via_capi__doc__, +"set_func_kwdefaults_via_capi($module, func, defaults, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_SET_FUNC_KWDEFAULTS_VIA_CAPI_METHODDEF \ + {"set_func_kwdefaults_via_capi", _PyCFunction_CAST(_testcapi_set_func_kwdefaults_via_capi), METH_FASTCALL, _testcapi_set_func_kwdefaults_via_capi__doc__}, + +static PyObject * +_testcapi_set_func_kwdefaults_via_capi_impl(PyObject *module, PyObject *func, + PyObject *defaults); + +static PyObject * +_testcapi_set_func_kwdefaults_via_capi(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *defaults; + + if (!_PyArg_CheckPositional("set_func_kwdefaults_via_capi", nargs, 2, 2)) { + goto exit; + } + func = args[0]; + defaults = args[1]; + return_value = _testcapi_set_func_kwdefaults_via_capi_impl(module, func, defaults); + +exit: + return return_value; +} +/*[clinic end generated code: output=12c375089125d165 input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index 1284fdc2767b..d2c71fb401d3 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -1,9 +1,16 @@ #include "parts.h" +#include "clinic/watchers.c.h" + #define Py_BUILD_CORE #include "pycore_function.h" // FUNC_MAX_WATCHERS #include "pycore_code.h" // CODE_MAX_WATCHERS +/*[clinic input] +module _testcapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ + // Test dict watching static PyObject *g_dict_watch_events; static int g_dict_watchers_installed; @@ -119,28 +126,31 @@ clear_dict_watcher(PyObject *self, PyObject *watcher_id) Py_RETURN_NONE; } +/*[clinic input] +_testcapi.watch_dict + watcher_id: int + dict: object + / +[clinic start generated code]*/ + static PyObject * -watch_dict(PyObject *self, PyObject *args) +_testcapi_watch_dict_impl(PyObject *module, int watcher_id, PyObject *dict) +/*[clinic end generated code: output=1426e0273cebe2d8 input=269b006d60c358bd]*/ { - PyObject *dict; - int watcher_id; - if (!PyArg_ParseTuple(args, "iO", &watcher_id, &dict)) { - return NULL; - } if (PyDict_Watch(watcher_id, dict)) { return NULL; } Py_RETURN_NONE; } +/*[clinic input] +_testcapi.unwatch_dict = _testcapi.watch_dict +[clinic start generated code]*/ + static PyObject * -unwatch_dict(PyObject *self, PyObject *args) +_testcapi_unwatch_dict_impl(PyObject *module, int watcher_id, PyObject *dict) +/*[clinic end generated code: output=512b1a71ae33c351 input=cae7dc1b6f7713b8]*/ { - PyObject *dict; - int watcher_id; - if (!PyArg_ParseTuple(args, "iO", &watcher_id, &dict)) { - return NULL; - } if (PyDict_Unwatch(watcher_id, dict)) { return NULL; } @@ -250,28 +260,31 @@ get_type_modified_events(PyObject *self, PyObject *Py_UNUSED(args)) return Py_NewRef(g_type_modified_events); } +/*[clinic input] +_testcapi.watch_type + watcher_id: int + type: object + / +[clinic start generated code]*/ + static PyObject * -watch_type(PyObject *self, PyObject *args) +_testcapi_watch_type_impl(PyObject *module, int watcher_id, PyObject *type) +/*[clinic end generated code: output=fdf4777126724fc4 input=5a808bf12be7e3ed]*/ { - PyObject *type; - int watcher_id; - if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) { - return NULL; - } if (PyType_Watch(watcher_id, type)) { return NULL; } Py_RETURN_NONE; } +/*[clinic input] +_testcapi.unwatch_type = _testcapi.watch_type +[clinic start generated code]*/ + static PyObject * -unwatch_type(PyObject *self, PyObject *args) +_testcapi_unwatch_type_impl(PyObject *module, int watcher_id, PyObject *type) +/*[clinic end generated code: output=0389672d4ad5f68b input=6701911fb45edc9e]*/ { - PyObject *type; - int watcher_id; - if (!PyArg_ParseTuple(args, "iO", &watcher_id, &type)) { - return NULL; - } if (PyType_Unwatch(watcher_id, type)) { return NULL; } @@ -605,29 +618,34 @@ allocate_too_many_func_watchers(PyObject *self, PyObject *args) Py_RETURN_NONE; } +/*[clinic input] +_testcapi.set_func_defaults_via_capi + func: object + defaults: object + / +[clinic start generated code]*/ + static PyObject * -set_func_defaults(PyObject *self, PyObject *args) +_testcapi_set_func_defaults_via_capi_impl(PyObject *module, PyObject *func, + PyObject *defaults) +/*[clinic end generated code: output=caf0cb39db31ac24 input=e04a8508ca9d42fc]*/ { - PyObject *func = NULL; - PyObject *defaults = NULL; - if (!PyArg_ParseTuple(args, "OO", &func, &defaults)) { - return NULL; - } if (PyFunction_SetDefaults(func, defaults) < 0) { return NULL; } Py_RETURN_NONE; } +/*[clinic input] +_testcapi.set_func_kwdefaults_via_capi = _testcapi.set_func_defaults_via_capi +[clinic start generated code]*/ + static PyObject * -set_func_kwdefaults(PyObject *self, PyObject *args) +_testcapi_set_func_kwdefaults_via_capi_impl(PyObject *module, PyObject *func, + PyObject *defaults) +/*[clinic end generated code: output=9ed3b08177025070 input=f3cd1ca3c18de8ce]*/ { - PyObject *func = NULL; - PyObject *kwdefaults = NULL; - if (!PyArg_ParseTuple(args, "OO", &func, &kwdefaults)) { - return NULL; - } - if (PyFunction_SetKwDefaults(func, kwdefaults) < 0) { + if (PyFunction_SetKwDefaults(func, defaults) < 0) { return NULL; } Py_RETURN_NONE; @@ -637,16 +655,16 @@ static PyMethodDef test_methods[] = { // Dict watchers. {"add_dict_watcher", add_dict_watcher, METH_O, NULL}, {"clear_dict_watcher", clear_dict_watcher, METH_O, NULL}, - {"watch_dict", watch_dict, METH_VARARGS, NULL}, - {"unwatch_dict", unwatch_dict, METH_VARARGS, NULL}, + _TESTCAPI_WATCH_DICT_METHODDEF + _TESTCAPI_UNWATCH_DICT_METHODDEF {"get_dict_watcher_events", (PyCFunction) get_dict_watcher_events, METH_NOARGS, NULL}, // Type watchers. {"add_type_watcher", add_type_watcher, METH_O, NULL}, {"clear_type_watcher", clear_type_watcher, METH_O, NULL}, - {"watch_type", watch_type, METH_VARARGS, NULL}, - {"unwatch_type", unwatch_type, METH_VARARGS, NULL}, + _TESTCAPI_WATCH_TYPE_METHODDEF + _TESTCAPI_UNWATCH_TYPE_METHODDEF {"get_type_modified_events", (PyCFunction) get_type_modified_events, METH_NOARGS, NULL}, @@ -663,8 +681,8 @@ static PyMethodDef test_methods[] = { // Function watchers. {"add_func_watcher", add_func_watcher, METH_O, NULL}, {"clear_func_watcher", clear_func_watcher, METH_O, NULL}, - {"set_func_defaults_via_capi", set_func_defaults, METH_VARARGS, NULL}, - {"set_func_kwdefaults_via_capi", set_func_kwdefaults, METH_VARARGS, NULL}, + _TESTCAPI_SET_FUNC_DEFAULTS_VIA_CAPI_METHODDEF + _TESTCAPI_SET_FUNC_KWDEFAULTS_VIA_CAPI_METHODDEF {"allocate_too_many_func_watchers", allocate_too_many_func_watchers, METH_NOARGS, NULL}, {NULL}, From webhook-mailer at python.org Mon May 15 22:23:00 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 16 May 2023 02:23:00 -0000 Subject: [Python-checkins] gh-104461: Run tkinter test_configure_screen on X11 only (GH-104462) Message-ID: <mailman.377.1684203781.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fdafdc235e74f2f4fedc1f745bf8b90141daa162 commit: fdafdc235e74f2f4fedc1f745bf8b90141daa162 branch: main author: Christopher Chavez <chrischavez at gmx.us> committer: ned-deily <nad at python.org> date: 2023-05-15T22:22:53-04:00 summary: gh-104461: Run tkinter test_configure_screen on X11 only (GH-104462) files: A Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst M Lib/test/test_tkinter/test_widgets.py diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index ba4ef49078c5..b45245162f24 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -76,6 +76,8 @@ def test_configure_menu(self): def test_configure_screen(self): widget = self.create() + if widget._windowingsystem != 'x11': + self.skipTest('Not using Tk for X11') self.assertEqual(widget['screen'], '') try: display = os.environ['DISPLAY'] diff --git a/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst b/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst new file mode 100644 index 000000000000..ae69f623e945 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst @@ -0,0 +1,3 @@ +Run test_configure_screen on X11 only, since the ``DISPLAY`` +environment variable and ``-screen`` option for toplevels +are not useful on Tk for Win32 or Aqua. From webhook-mailer at python.org Mon May 15 22:47:58 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 16 May 2023 02:47:58 -0000 Subject: [Python-checkins] [3.11] gh-104461: Run tkinter test_configure_screen on X11 only (GH-104526) Message-ID: <mailman.378.1684205278.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7779027084d57ae4892a25a6d5429feb205a237c commit: 7779027084d57ae4892a25a6d5429feb205a237c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily <nad at python.org> date: 2023-05-16T02:47:51Z summary: [3.11] gh-104461: Run tkinter test_configure_screen on X11 only (GH-104526) Co-authored-by: Christopher Chavez <chrischavez at gmx.us> files: A Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst M Lib/tkinter/test/test_tkinter/test_widgets.py diff --git a/Lib/tkinter/test/test_tkinter/test_widgets.py b/Lib/tkinter/test/test_tkinter/test_widgets.py index a756276ec769..f0149153512f 100644 --- a/Lib/tkinter/test/test_tkinter/test_widgets.py +++ b/Lib/tkinter/test/test_tkinter/test_widgets.py @@ -77,6 +77,8 @@ def test_configure_menu(self): def test_configure_screen(self): widget = self.create() + if widget._windowingsystem != 'x11': + self.skipTest('Not using Tk for X11') self.assertEqual(widget['screen'], '') try: display = os.environ['DISPLAY'] diff --git a/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst b/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst new file mode 100644 index 000000000000..ae69f623e945 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst @@ -0,0 +1,3 @@ +Run test_configure_screen on X11 only, since the ``DISPLAY`` +environment variable and ``-screen`` option for toplevels +are not useful on Tk for Win32 or Aqua. From webhook-mailer at python.org Mon May 15 23:37:05 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 16 May 2023 03:37:05 -0000 Subject: [Python-checkins] gh-103763: Implement PEP 695 (#103764) Message-ID: <mailman.379.1684208226.13550.python-checkins@python.org> https://github.com/python/cpython/commit/24d8b88420b81fc60aeb0cbcacef1e72d633824a commit: 24d8b88420b81fc60aeb0cbcacef1e72d633824a branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-15T20:36:23-07:00 summary: gh-103763: Implement PEP 695 (#103764) This implements PEP 695, Type Parameter Syntax. It adds support for: - Generic functions (def func[T](): ...) - Generic classes (class X[T](): ...) - Type aliases (type X = ...) - New scoping when the new syntax is used within a class body - Compiler and interpreter changes to support the new syntax and scoping rules Co-authored-by: Marc Mueller <30130371+cdce8p at users.noreply.github.com> Co-authored-by: Eric Traut <eric at traut.com> Co-authored-by: Larry Hastings <larry at hastings.org> Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: A Include/internal/pycore_typevarobject.h A Lib/test/test_type_aliases.py A Lib/test/test_type_params.py A Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst A Objects/clinic/typevarobject.c.h A Objects/typevarobject.c M Doc/library/ast.rst M Grammar/python.gram M Include/cpython/funcobject.h M Include/internal/pycore_ast.h M Include/internal/pycore_ast_state.h M Include/internal/pycore_function.h M Include/internal/pycore_global_objects.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_intrinsics.h M Include/internal/pycore_opcode.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_symtable.h M Include/internal/pycore_unicodeobject_generated.h M Include/opcode.h M Lib/ast.py M Lib/importlib/_bootstrap_external.py M Lib/keyword.py M Lib/opcode.py M Lib/test/support/__init__.py M Lib/test/test_ast.py M Lib/test/test_keyword.py M Lib/test/test_sys.py M Lib/test/test_typing.py M Lib/typing.py M Makefile.pre.in M Modules/Setup.bootstrap.in M Modules/Setup.stdlib.in M Modules/_typingmodule.c M Objects/funcobject.c M Objects/object.c M Objects/typeobject.c M Objects/unionobject.c M PCbuild/_freeze_module.vcxproj M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Parser/Python.asdl M Parser/action_helpers.c M Parser/parser.c M Python/Python-ast.c M Python/ast.c M Python/ast_opt.c M Python/bytecodes.c M Python/compile.c M Python/generated_cases.c.h M Python/intrinsics.c M Python/opcode_metadata.h M Python/opcode_targets.h M Python/pylifecycle.c M Python/symtable.c diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 0811b3fa0e78..eb6a973cac62 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1724,6 +1724,7 @@ Function and class definitions body=[ FunctionDef( name='f', + typeparams=[], args=arguments( posonlyargs=[], args=[ @@ -1847,6 +1848,7 @@ Function and class definitions body=[ ClassDef( name='Foo', + typeparams=[], bases=[ Name(id='base1', ctx=Load()), Name(id='base2', ctx=Load())], @@ -1885,6 +1887,7 @@ Async and await body=[ AsyncFunctionDef( name='f', + typeparams=[], args=arguments( posonlyargs=[], args=[], diff --git a/Grammar/python.gram b/Grammar/python.gram index 6361dcd0985b..c79207b9cb51 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -112,6 +112,7 @@ simple_stmts[asdl_stmt_seq*]: # will throw a SyntaxError. simple_stmt[stmt_ty] (memo): | assignment + | &"type" type_alias | e=star_expressions { _PyAST_Expr(e, EXTRA) } | &'return' return_stmt | &('import' | 'from') import_stmt @@ -252,8 +253,8 @@ class_def[stmt_ty]: class_def_raw[stmt_ty]: | invalid_class_def_raw - | 'class' a=NAME b=['(' z=[arguments] ')' { z }] ':' c=block { - _PyAST_ClassDef(a->v.Name.id, + | 'class' a=NAME t=[type_params] b=['(' z=[arguments] ')' { z }] ':' c=block { + _PyAST_ClassDef(a->v.Name.id, t, (b) ? ((expr_ty) b)->v.Call.args : NULL, (b) ? ((expr_ty) b)->v.Call.keywords : NULL, c, NULL, EXTRA) } @@ -267,16 +268,16 @@ function_def[stmt_ty]: function_def_raw[stmt_ty]: | invalid_def_raw - | 'def' n=NAME &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { - _PyAST_FunctionDef(n->v.Name.id, + | 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { + _PyAST_FunctionDef(n->v.Name.id, t, (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) } - | ASYNC 'def' n=NAME &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { + | ASYNC 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block { CHECK_VERSION( stmt_ty, 5, "Async functions are", - _PyAST_AsyncFunctionDef(n->v.Name.id, + _PyAST_AsyncFunctionDef(n->v.Name.id, t, (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) ) } @@ -628,6 +629,39 @@ keyword_patterns[asdl_seq*]: keyword_pattern[KeyPatternPair*]: | arg=NAME '=' value=pattern { _PyPegen_key_pattern_pair(p, arg, value) } +# Type statement +# --------------- + +type_alias[stmt_ty]: + | "type" n=NAME t=[type_params] '=' b=expression { + CHECK_VERSION(stmt_ty, 12, "Type statement is", + _PyAST_TypeAlias(CHECK(expr_ty, _PyPegen_set_expr_context(p, n, Store)), t, b, EXTRA)) } + +# Type parameter declaration +# -------------------------- + +type_params[asdl_typeparam_seq*]: '[' t=type_param_seq ']' { + CHECK_VERSION(asdl_typeparam_seq *, 12, "Type parameter lists are", t) } + +type_param_seq[asdl_typeparam_seq*]: a[asdl_typeparam_seq*]=','.type_param+ [','] { a } + +type_param[typeparam_ty] (memo): + | a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) } + | '*' a=NAME colon=":" e=expression { + RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind + ? "cannot use constraints with TypeVarTuple" + : "cannot use bound with TypeVarTuple") + } + | '*' a=NAME { _PyAST_TypeVarTuple(a->v.Name.id, EXTRA) } + | '**' a=NAME colon=":" e=expression { + RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind + ? "cannot use constraints with ParamSpec" + : "cannot use bound with ParamSpec") + } + | '**' a=NAME { _PyAST_ParamSpec(a->v.Name.id, EXTRA) } + +type_param_bound[expr_ty]: ":" e=expression { e } + # EXPRESSIONS # ----------- diff --git a/Include/cpython/funcobject.h b/Include/cpython/funcobject.h index c716330cc3fb..6f78f5868d01 100644 --- a/Include/cpython/funcobject.h +++ b/Include/cpython/funcobject.h @@ -41,6 +41,7 @@ typedef struct { PyObject *func_weakreflist; /* List of weak references */ PyObject *func_module; /* The __module__ attribute, can be anything */ PyObject *func_annotations; /* Annotations, a dict or NULL */ + PyObject *func_typeparams; /* Tuple of active type variables or NULL */ vectorcallfunc vectorcall; /* Version number for use by specializer. * Can set to non-zero when we want to specialize. diff --git a/Include/internal/pycore_ast.h b/Include/internal/pycore_ast.h index 36277efe9c5c..9f1cef054150 100644 --- a/Include/internal/pycore_ast.h +++ b/Include/internal/pycore_ast.h @@ -51,6 +51,8 @@ typedef struct _pattern *pattern_ty; typedef struct _type_ignore *type_ignore_ty; +typedef struct _typeparam *typeparam_ty; + typedef struct { _ASDL_SEQ_HEAD @@ -147,6 +149,13 @@ typedef struct { asdl_type_ignore_seq *_Py_asdl_type_ignore_seq_new(Py_ssize_t size, PyArena *arena); +typedef struct { + _ASDL_SEQ_HEAD + typeparam_ty typed_elements[1]; +} asdl_typeparam_seq; + +asdl_typeparam_seq *_Py_asdl_typeparam_seq_new(Py_ssize_t size, PyArena *arena); + enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, FunctionType_kind=4}; @@ -176,17 +185,19 @@ struct _mod { enum _stmt_kind {FunctionDef_kind=1, AsyncFunctionDef_kind=2, ClassDef_kind=3, Return_kind=4, Delete_kind=5, Assign_kind=6, - AugAssign_kind=7, AnnAssign_kind=8, For_kind=9, - AsyncFor_kind=10, While_kind=11, If_kind=12, With_kind=13, - AsyncWith_kind=14, Match_kind=15, Raise_kind=16, Try_kind=17, - TryStar_kind=18, Assert_kind=19, Import_kind=20, - ImportFrom_kind=21, Global_kind=22, Nonlocal_kind=23, - Expr_kind=24, Pass_kind=25, Break_kind=26, Continue_kind=27}; + TypeAlias_kind=7, AugAssign_kind=8, AnnAssign_kind=9, + For_kind=10, AsyncFor_kind=11, While_kind=12, If_kind=13, + With_kind=14, AsyncWith_kind=15, Match_kind=16, + Raise_kind=17, Try_kind=18, TryStar_kind=19, Assert_kind=20, + Import_kind=21, ImportFrom_kind=22, Global_kind=23, + Nonlocal_kind=24, Expr_kind=25, Pass_kind=26, Break_kind=27, + Continue_kind=28}; struct _stmt { enum _stmt_kind kind; union { struct { identifier name; + asdl_typeparam_seq *typeparams; arguments_ty args; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; @@ -196,6 +207,7 @@ struct _stmt { struct { identifier name; + asdl_typeparam_seq *typeparams; arguments_ty args; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; @@ -205,6 +217,7 @@ struct _stmt { struct { identifier name; + asdl_typeparam_seq *typeparams; asdl_expr_seq *bases; asdl_keyword_seq *keywords; asdl_stmt_seq *body; @@ -225,6 +238,12 @@ struct _stmt { string type_comment; } Assign; + struct { + expr_ty name; + asdl_typeparam_seq *typeparams; + expr_ty value; + } TypeAlias; + struct { expr_ty target; operator_ty op; @@ -630,6 +649,30 @@ struct _type_ignore { } v; }; +enum _typeparam_kind {TypeVar_kind=1, ParamSpec_kind=2, TypeVarTuple_kind=3}; +struct _typeparam { + enum _typeparam_kind kind; + union { + struct { + identifier name; + expr_ty bound; + } TypeVar; + + struct { + identifier name; + } ParamSpec; + + struct { + identifier name; + } TypeVarTuple; + + } v; + int lineno; + int col_offset; + int end_lineno; + int end_col_offset; +}; + // Note: these macros affect function definitions, not only call sites. mod_ty _PyAST_Module(asdl_stmt_seq * body, asdl_type_ignore_seq * type_ignores, @@ -638,21 +681,22 @@ mod_ty _PyAST_Interactive(asdl_stmt_seq * body, PyArena *arena); mod_ty _PyAST_Expression(expr_ty body, PyArena *arena); mod_ty _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena); -stmt_ty _PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * - body, asdl_expr_seq * decorator_list, expr_ty - returns, string type_comment, int lineno, int - col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -stmt_ty _PyAST_AsyncFunctionDef(identifier name, arguments_ty args, - asdl_stmt_seq * body, asdl_expr_seq * - decorator_list, expr_ty returns, string - type_comment, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -stmt_ty _PyAST_ClassDef(identifier name, asdl_expr_seq * bases, - asdl_keyword_seq * keywords, asdl_stmt_seq * body, - asdl_expr_seq * decorator_list, int lineno, int - col_offset, int end_lineno, int end_col_offset, PyArena - *arena); +stmt_ty _PyAST_FunctionDef(identifier name, asdl_typeparam_seq * typeparams, + arguments_ty args, asdl_stmt_seq * body, + asdl_expr_seq * decorator_list, expr_ty returns, + string type_comment, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +stmt_ty _PyAST_AsyncFunctionDef(identifier name, asdl_typeparam_seq * + typeparams, arguments_ty args, asdl_stmt_seq * + body, asdl_expr_seq * decorator_list, expr_ty + returns, string type_comment, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); +stmt_ty _PyAST_ClassDef(identifier name, asdl_typeparam_seq * typeparams, + asdl_expr_seq * bases, asdl_keyword_seq * keywords, + asdl_stmt_seq * body, asdl_expr_seq * decorator_list, + int lineno, int col_offset, int end_lineno, int + end_col_offset, PyArena *arena); stmt_ty _PyAST_Return(expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); stmt_ty _PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int @@ -660,6 +704,9 @@ stmt_ty _PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int stmt_ty _PyAST_Assign(asdl_expr_seq * targets, expr_ty value, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); +stmt_ty _PyAST_TypeAlias(expr_ty name, asdl_typeparam_seq * typeparams, expr_ty + value, int lineno, int col_offset, int end_lineno, int + end_col_offset, PyArena *arena); stmt_ty _PyAST_AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); @@ -844,6 +891,14 @@ pattern_ty _PyAST_MatchOr(asdl_pattern_seq * patterns, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); type_ignore_ty _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena); +typeparam_ty _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); +typeparam_ty _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +typeparam_ty _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena + *arena); PyObject* PyAST_mod2obj(mod_ty t); diff --git a/Include/internal/pycore_ast_state.h b/Include/internal/pycore_ast_state.h index f15b4905eed1..e723ead577b8 100644 --- a/Include/internal/pycore_ast_state.h +++ b/Include/internal/pycore_ast_state.h @@ -118,6 +118,7 @@ struct ast_state { PyObject *Not_type; PyObject *Or_singleton; PyObject *Or_type; + PyObject *ParamSpec_type; PyObject *Pass_type; PyObject *Pow_singleton; PyObject *Pow_type; @@ -137,7 +138,10 @@ struct ast_state { PyObject *TryStar_type; PyObject *Try_type; PyObject *Tuple_type; + PyObject *TypeAlias_type; PyObject *TypeIgnore_type; + PyObject *TypeVarTuple_type; + PyObject *TypeVar_type; PyObject *UAdd_singleton; PyObject *UAdd_type; PyObject *USub_singleton; @@ -166,6 +170,7 @@ struct ast_state { PyObject *bases; PyObject *body; PyObject *boolop_type; + PyObject *bound; PyObject *cases; PyObject *cause; PyObject *cls; @@ -243,6 +248,8 @@ struct ast_state { PyObject *type_comment; PyObject *type_ignore_type; PyObject *type_ignores; + PyObject *typeparam_type; + PyObject *typeparams; PyObject *unaryop_type; PyObject *upper; PyObject *value; diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 11988149843f..ecbb7001e7d8 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -17,6 +17,8 @@ struct _py_func_state { extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr); extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func); +extern PyObject *_Py_set_function_type_params( + PyThreadState* unused, PyObject *func, PyObject *type_params); #ifdef __cplusplus } diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 64d9384df9c5..40cc04d5d170 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -68,6 +68,14 @@ struct _Py_interp_cached_objects { PyObject *type_slots_pname; pytype_slotdef *type_slots_ptrs[MAX_EQUIV]; + /* TypeVar and related types */ + PyTypeObject *generic_type; + PyTypeObject *typevar_type; + PyTypeObject *typevartuple_type; + PyTypeObject *paramspec_type; + PyTypeObject *paramspecargs_type; + PyTypeObject *paramspeckwargs_type; + PyTypeObject *typealias_type; }; #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \ diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 7e495817981f..24a268ac8c43 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -555,15 +555,19 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dbl_close_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dbl_open_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dbl_percent)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(defaults)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(dot_locals)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(empty)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(generic_base)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(json_decoder)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(kwdefaults)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(list_err)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(newline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(open_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(percent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(shim_name)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(FINISHED)); @@ -602,6 +606,8 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__class__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__class_getitem__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__classcell__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__classdict__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__classdictcell__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__complex__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__contains__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__copy__)); @@ -724,6 +730,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__subclasshook__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__truediv__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__trunc__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__type_params__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__typing_is_unpacked_typevartuple__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__typing_prepare_subst__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__typing_subst__)); @@ -779,8 +786,11 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(after_in_child)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(after_in_parent)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(aggregate_class)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(alias)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(append)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(arg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(argdefs)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(args)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(arguments)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(argv)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(as_integer_ratio)); @@ -795,6 +805,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(big)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(binary_form)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(block)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(bound)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(buffer)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(buffer_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(buffer_size)); @@ -850,11 +861,13 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(compile_mode)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(consts)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(context)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(contravariant)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cookie)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(copy)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(copyreg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(coro)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(count)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(covariant)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cwd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(d)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(data)); @@ -964,6 +977,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(incoming)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(indexgroup)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(inf)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(infer_variance)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(inheritable)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(initial)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(initial_bytes)); @@ -1080,6 +1094,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(optimize)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(options)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(order)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(origin)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(out_fd)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(outgoing)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(overlapped)); @@ -1213,6 +1228,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(twice)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(txt)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(type)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tz)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tzname)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(uid)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 8ebfee85c87c..c1005d051552 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -40,15 +40,19 @@ struct _Py_global_strings { STRUCT_FOR_STR(dbl_close_br, "}}") STRUCT_FOR_STR(dbl_open_br, "{{") STRUCT_FOR_STR(dbl_percent, "%%") + STRUCT_FOR_STR(defaults, ".defaults") STRUCT_FOR_STR(dot, ".") STRUCT_FOR_STR(dot_locals, ".<locals>") STRUCT_FOR_STR(empty, "") + STRUCT_FOR_STR(generic_base, ".generic_base") STRUCT_FOR_STR(json_decoder, "json.decoder") + STRUCT_FOR_STR(kwdefaults, ".kwdefaults") STRUCT_FOR_STR(list_err, "list index out of range") STRUCT_FOR_STR(newline, "\n") STRUCT_FOR_STR(open_br, "{") STRUCT_FOR_STR(percent, "%") STRUCT_FOR_STR(shim_name, "<shim>") + STRUCT_FOR_STR(type_params, ".type_params") STRUCT_FOR_STR(utf_8, "utf-8") } literals; @@ -90,6 +94,8 @@ struct _Py_global_strings { STRUCT_FOR_ID(__class__) STRUCT_FOR_ID(__class_getitem__) STRUCT_FOR_ID(__classcell__) + STRUCT_FOR_ID(__classdict__) + STRUCT_FOR_ID(__classdictcell__) STRUCT_FOR_ID(__complex__) STRUCT_FOR_ID(__contains__) STRUCT_FOR_ID(__copy__) @@ -212,6 +218,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__subclasshook__) STRUCT_FOR_ID(__truediv__) STRUCT_FOR_ID(__trunc__) + STRUCT_FOR_ID(__type_params__) STRUCT_FOR_ID(__typing_is_unpacked_typevartuple__) STRUCT_FOR_ID(__typing_prepare_subst__) STRUCT_FOR_ID(__typing_subst__) @@ -267,8 +274,11 @@ struct _Py_global_strings { STRUCT_FOR_ID(after_in_child) STRUCT_FOR_ID(after_in_parent) STRUCT_FOR_ID(aggregate_class) + STRUCT_FOR_ID(alias) STRUCT_FOR_ID(append) + STRUCT_FOR_ID(arg) STRUCT_FOR_ID(argdefs) + STRUCT_FOR_ID(args) STRUCT_FOR_ID(arguments) STRUCT_FOR_ID(argv) STRUCT_FOR_ID(as_integer_ratio) @@ -283,6 +293,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(big) STRUCT_FOR_ID(binary_form) STRUCT_FOR_ID(block) + STRUCT_FOR_ID(bound) STRUCT_FOR_ID(buffer) STRUCT_FOR_ID(buffer_callback) STRUCT_FOR_ID(buffer_size) @@ -338,11 +349,13 @@ struct _Py_global_strings { STRUCT_FOR_ID(compile_mode) STRUCT_FOR_ID(consts) STRUCT_FOR_ID(context) + STRUCT_FOR_ID(contravariant) STRUCT_FOR_ID(cookie) STRUCT_FOR_ID(copy) STRUCT_FOR_ID(copyreg) STRUCT_FOR_ID(coro) STRUCT_FOR_ID(count) + STRUCT_FOR_ID(covariant) STRUCT_FOR_ID(cwd) STRUCT_FOR_ID(d) STRUCT_FOR_ID(data) @@ -452,6 +465,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(incoming) STRUCT_FOR_ID(indexgroup) STRUCT_FOR_ID(inf) + STRUCT_FOR_ID(infer_variance) STRUCT_FOR_ID(inheritable) STRUCT_FOR_ID(initial) STRUCT_FOR_ID(initial_bytes) @@ -568,6 +582,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(optimize) STRUCT_FOR_ID(options) STRUCT_FOR_ID(order) + STRUCT_FOR_ID(origin) STRUCT_FOR_ID(out_fd) STRUCT_FOR_ID(outgoing) STRUCT_FOR_ID(overlapped) @@ -701,6 +716,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(twice) STRUCT_FOR_ID(txt) STRUCT_FOR_ID(type) + STRUCT_FOR_ID(type_params) STRUCT_FOR_ID(tz) STRUCT_FOR_ID(tzname) STRUCT_FOR_ID(uid) diff --git a/Include/internal/pycore_intrinsics.h b/Include/internal/pycore_intrinsics.h index 3902059a04b9..39f15681b7b2 100644 --- a/Include/internal/pycore_intrinsics.h +++ b/Include/internal/pycore_intrinsics.h @@ -8,15 +8,23 @@ #define INTRINSIC_ASYNC_GEN_WRAP 4 #define INTRINSIC_UNARY_POSITIVE 5 #define INTRINSIC_LIST_TO_TUPLE 6 +#define INTRINSIC_TYPEVAR 7 +#define INTRINSIC_PARAMSPEC 8 +#define INTRINSIC_TYPEVARTUPLE 9 +#define INTRINSIC_SUBSCRIPT_GENERIC 10 +#define INTRINSIC_TYPEALIAS 11 -#define MAX_INTRINSIC_1 6 +#define MAX_INTRINSIC_1 11 /* Binary Functions: */ #define INTRINSIC_2_INVALID 0 #define INTRINSIC_PREP_RERAISE_STAR 1 +#define INTRINSIC_TYPEVAR_WITH_BOUND 2 +#define INTRINSIC_TYPEVAR_WITH_CONSTRAINTS 3 +#define INTRINSIC_SET_FUNCTION_TYPE_PARAMS 4 -#define MAX_INTRINSIC_2 1 +#define MAX_INTRINSIC_2 4 typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value); typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index e823e1bfb5d4..c2fa5692dbe4 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -167,7 +167,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_ATTR_SLOT] = LOAD_ATTR, [LOAD_ATTR_WITH_HINT] = LOAD_ATTR, [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS, - [LOAD_CLASSDEREF] = LOAD_CLASSDEREF, [LOAD_CLOSURE] = LOAD_CLOSURE, [LOAD_CONST] = LOAD_CONST, [LOAD_CONST__LOAD_FAST] = LOAD_CONST, @@ -177,9 +176,12 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_FAST_CHECK] = LOAD_FAST_CHECK, [LOAD_FAST__LOAD_CONST] = LOAD_FAST, [LOAD_FAST__LOAD_FAST] = LOAD_FAST, + [LOAD_FROM_DICT_OR_DEREF] = LOAD_FROM_DICT_OR_DEREF, + [LOAD_FROM_DICT_OR_GLOBALS] = LOAD_FROM_DICT_OR_GLOBALS, [LOAD_GLOBAL] = LOAD_GLOBAL, [LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL, [LOAD_GLOBAL_MODULE] = LOAD_GLOBAL, + [LOAD_LOCALS] = LOAD_LOCALS, [LOAD_NAME] = LOAD_NAME, [LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, [LOAD_SUPER_ATTR_ATTR] = LOAD_SUPER_ATTR, @@ -329,8 +331,8 @@ static const char *const _PyOpcode_OpName[267] = { [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [LOAD_LOCALS] = "LOAD_LOCALS", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -353,9 +355,9 @@ static const char *const _PyOpcode_OpName[267] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -390,7 +392,7 @@ static const char *const _PyOpcode_OpName[267] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [LOAD_CLASSDEREF] = "LOAD_CLASSDEREF", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", @@ -417,8 +419,8 @@ static const char *const _PyOpcode_OpName[267] = { [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", - [175] = "<175>", - [176] = "<176>", + [LOAD_FROM_DICT_OR_GLOBALS] = "LOAD_FROM_DICT_OR_GLOBALS", + [LOAD_FROM_DICT_OR_DEREF] = "LOAD_FROM_DICT_OR_DEREF", [177] = "<177>", [178] = "<178>", [179] = "<179>", @@ -515,8 +517,6 @@ static const char *const _PyOpcode_OpName[267] = { #define EXTRA_CASES \ case 169: \ case 170: \ - case 175: \ - case 176: \ case 177: \ case 178: \ case 179: \ diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 7b9c73dd1edf..ff1dee6eacfe 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -546,15 +546,19 @@ extern "C" { INIT_STR(dbl_close_br, "}}"), \ INIT_STR(dbl_open_br, "{{"), \ INIT_STR(dbl_percent, "%%"), \ + INIT_STR(defaults, ".defaults"), \ INIT_STR(dot, "."), \ INIT_STR(dot_locals, ".<locals>"), \ INIT_STR(empty, ""), \ + INIT_STR(generic_base, ".generic_base"), \ INIT_STR(json_decoder, "json.decoder"), \ + INIT_STR(kwdefaults, ".kwdefaults"), \ INIT_STR(list_err, "list index out of range"), \ INIT_STR(newline, "\n"), \ INIT_STR(open_br, "{"), \ INIT_STR(percent, "%"), \ INIT_STR(shim_name, "<shim>"), \ + INIT_STR(type_params, ".type_params"), \ INIT_STR(utf_8, "utf-8"), \ } @@ -596,6 +600,8 @@ extern "C" { INIT_ID(__class__), \ INIT_ID(__class_getitem__), \ INIT_ID(__classcell__), \ + INIT_ID(__classdict__), \ + INIT_ID(__classdictcell__), \ INIT_ID(__complex__), \ INIT_ID(__contains__), \ INIT_ID(__copy__), \ @@ -718,6 +724,7 @@ extern "C" { INIT_ID(__subclasshook__), \ INIT_ID(__truediv__), \ INIT_ID(__trunc__), \ + INIT_ID(__type_params__), \ INIT_ID(__typing_is_unpacked_typevartuple__), \ INIT_ID(__typing_prepare_subst__), \ INIT_ID(__typing_subst__), \ @@ -773,8 +780,11 @@ extern "C" { INIT_ID(after_in_child), \ INIT_ID(after_in_parent), \ INIT_ID(aggregate_class), \ + INIT_ID(alias), \ INIT_ID(append), \ + INIT_ID(arg), \ INIT_ID(argdefs), \ + INIT_ID(args), \ INIT_ID(arguments), \ INIT_ID(argv), \ INIT_ID(as_integer_ratio), \ @@ -789,6 +799,7 @@ extern "C" { INIT_ID(big), \ INIT_ID(binary_form), \ INIT_ID(block), \ + INIT_ID(bound), \ INIT_ID(buffer), \ INIT_ID(buffer_callback), \ INIT_ID(buffer_size), \ @@ -844,11 +855,13 @@ extern "C" { INIT_ID(compile_mode), \ INIT_ID(consts), \ INIT_ID(context), \ + INIT_ID(contravariant), \ INIT_ID(cookie), \ INIT_ID(copy), \ INIT_ID(copyreg), \ INIT_ID(coro), \ INIT_ID(count), \ + INIT_ID(covariant), \ INIT_ID(cwd), \ INIT_ID(d), \ INIT_ID(data), \ @@ -958,6 +971,7 @@ extern "C" { INIT_ID(incoming), \ INIT_ID(indexgroup), \ INIT_ID(inf), \ + INIT_ID(infer_variance), \ INIT_ID(inheritable), \ INIT_ID(initial), \ INIT_ID(initial_bytes), \ @@ -1074,6 +1088,7 @@ extern "C" { INIT_ID(optimize), \ INIT_ID(options), \ INIT_ID(order), \ + INIT_ID(origin), \ INIT_ID(out_fd), \ INIT_ID(outgoing), \ INIT_ID(overlapped), \ @@ -1207,6 +1222,7 @@ extern "C" { INIT_ID(twice), \ INIT_ID(txt), \ INIT_ID(type), \ + INIT_ID(type_params), \ INIT_ID(tz), \ INIT_ID(tzname), \ INIT_ID(uid), \ diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 9a005be5402c..3fa825d0a837 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -10,8 +10,17 @@ extern "C" { struct _mod; // Type defined in pycore_ast.h -typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock, AnnotationBlock } - _Py_block_ty; +typedef enum _block_type { + FunctionBlock, ClassBlock, ModuleBlock, + // Used for annotations if 'from __future__ import annotations' is active. + // Annotation blocks cannot bind names and are not evaluated. + AnnotationBlock, + // Used for generics and type aliases. These work mostly like functions + // (see PEP 695 for details). The three different blocks function identically; + // they are different enum entries only so that error messages can be more + // precise. + TypeVarBoundBlock, TypeAliasBlock, TypeParamBlock +} _Py_block_ty; typedef enum _comprehension_type { NoComprehension = 0, @@ -49,7 +58,7 @@ typedef struct _symtable_entry { PyObject *ste_varnames; /* list of function parameters */ PyObject *ste_children; /* list of child blocks */ PyObject *ste_directives;/* locations of global and nonlocal statements */ - _Py_block_ty ste_type; /* module, class, function or annotation */ + _Py_block_ty ste_type; int ste_nested; /* true if block is nested */ unsigned ste_free : 1; /* true if block has free variables */ unsigned ste_child_free : 1; /* true if a child block has free vars, @@ -64,8 +73,12 @@ typedef struct _symtable_entry { unsigned ste_needs_class_closure : 1; /* for class scopes, true if a closure over __class__ should be created */ + unsigned ste_needs_classdict : 1; /* for class scopes, true if a closure + over the class dict should be created */ unsigned ste_comp_inlined : 1; /* true if this comprehension is inlined */ unsigned ste_comp_iter_target : 1; /* true if visiting comprehension target */ + unsigned ste_can_see_class_scope : 1; /* true if this block can see names bound in an + enclosing class scope */ int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */ int ste_lineno; /* first line of block */ int ste_col_offset; /* offset of first line of block */ @@ -82,6 +95,7 @@ extern PyTypeObject PySTEntry_Type; extern long _PyST_GetSymbol(PySTEntryObject *, PyObject *); extern int _PyST_GetScope(PySTEntryObject *, PyObject *); +extern int _PyST_IsFunctionLike(PySTEntryObject *); extern struct symtable* _PySymtable_Build( struct _mod *mod, @@ -105,6 +119,7 @@ extern PyObject* _Py_Mangle(PyObject *p, PyObject *name); #define DEF_IMPORT 2<<6 /* assignment occurred via import */ #define DEF_ANNOT 2<<7 /* this name is annotated */ #define DEF_COMP_ITER 2<<8 /* this name is a comprehension iteration variable */ +#define DEF_TYPE_PARAM 2<<9 /* this name is a type parameter */ #define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT) diff --git a/Include/internal/pycore_typevarobject.h b/Include/internal/pycore_typevarobject.h new file mode 100644 index 000000000000..2035e47e9230 --- /dev/null +++ b/Include/internal/pycore_typevarobject.h @@ -0,0 +1,22 @@ +#ifndef Py_INTERNAL_TYPEVAROBJECT_H +#define Py_INTERNAL_TYPEVAROBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +extern PyObject *_Py_make_typevar(PyObject *, PyObject *, PyObject *); +extern PyObject *_Py_make_paramspec(PyThreadState *, PyObject *); +extern PyObject *_Py_make_typevartuple(PyThreadState *, PyObject *); +extern PyObject *_Py_make_typealias(PyThreadState *, PyObject *); +extern PyObject *_Py_subscript_generic(PyThreadState *, PyObject *); +extern int _Py_initialize_generic(PyInterpreterState *); +extern void _Py_clear_generic_types(PyInterpreterState *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_TYPEVAROBJECT_H */ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 8e086edbdf81..ba6b37f1bf55 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -123,6 +123,12 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(__classcell__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(__classdict__); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(__classdictcell__); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__complex__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -489,6 +495,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(__trunc__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(__type_params__); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__typing_is_unpacked_typevartuple__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -654,12 +663,21 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(aggregate_class); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(alias); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(append); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(arg); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(argdefs); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(args); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(arguments); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -702,6 +720,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(block); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(bound); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(buffer); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -867,6 +888,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(context); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(contravariant); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cookie); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -882,6 +906,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(count); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(covariant); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cwd); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1209,6 +1236,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(inf); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(infer_variance); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(inheritable); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1557,6 +1587,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(order); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(origin); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(out_fd); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); @@ -1956,6 +1989,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(type); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(type_params); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tz); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Include/opcode.h b/Include/opcode.h index c3b6e5dce49a..dea7687c39da 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -45,6 +45,7 @@ extern "C" { #define RETURN_GENERATOR 75 #define RETURN_VALUE 83 #define SETUP_ANNOTATIONS 85 +#define LOAD_LOCALS 87 #define POP_EXCEPT 89 #define HAVE_ARGUMENT 90 #define STORE_NAME 90 @@ -102,7 +103,6 @@ extern "C" { #define LIST_APPEND 145 #define SET_ADD 146 #define MAP_ADD 147 -#define LOAD_CLASSDEREF 148 #define COPY_FREE_VARS 149 #define YIELD_VALUE 150 #define RESUME 151 @@ -118,6 +118,8 @@ extern "C" { #define KW_NAMES 172 #define CALL_INTRINSIC_1 173 #define CALL_INTRINSIC_2 174 +#define LOAD_FROM_DICT_OR_GLOBALS 175 +#define LOAD_FROM_DICT_OR_DEREF 176 #define MIN_INSTRUMENTED_OPCODE 238 #define INSTRUMENTED_POP_JUMP_IF_NONE 238 #define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239 @@ -199,11 +201,11 @@ extern "C" { #define LOAD_ATTR_METHOD_WITH_VALUES 82 #define LOAD_CONST__LOAD_FAST 84 #define LOAD_FAST__LOAD_CONST 86 -#define LOAD_FAST__LOAD_FAST 87 -#define LOAD_GLOBAL_BUILTIN 88 -#define LOAD_GLOBAL_MODULE 111 -#define STORE_ATTR_INSTANCE_VALUE 112 -#define STORE_ATTR_SLOT 113 +#define LOAD_FAST__LOAD_FAST 88 +#define LOAD_GLOBAL_BUILTIN 111 +#define LOAD_GLOBAL_MODULE 112 +#define STORE_ATTR_INSTANCE_VALUE 113 +#define STORE_ATTR_SLOT 148 #define STORE_ATTR_WITH_HINT 153 #define STORE_FAST__LOAD_FAST 154 #define STORE_FAST__STORE_FAST 158 diff --git a/Lib/ast.py b/Lib/ast.py index 65152047a223..08904afb2031 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1051,6 +1051,7 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) + self._typeparams_helper(node.typeparams) with self.delimit_if("(", ")", condition = node.bases or node.keywords): comma = False for e in node.bases: @@ -1082,6 +1083,7 @@ def _function_helper(self, node, fill_suffix): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) + self._typeparams_helper(node.typeparams) with self.delimit("(", ")"): self.traverse(node.args) if node.returns: @@ -1090,6 +1092,30 @@ def _function_helper(self, node, fill_suffix): with self.block(extra=self.get_type_comment(node)): self._write_docstring_and_traverse_body(node) + def _typeparams_helper(self, typeparams): + if typeparams is not None and len(typeparams) > 0: + with self.delimit("[", "]"): + self.interleave(lambda: self.write(", "), self.traverse, typeparams) + + def visit_TypeVar(self, node): + self.write(node.name) + if node.bound: + self.write(": ") + self.traverse(node.bound) + + def visit_TypeVarTuple(self, node): + self.write("*" + node.name) + + def visit_ParamSpec(self, node): + self.write("**" + node.name) + + def visit_TypeAlias(self, node): + self.fill("type ") + self.traverse(node.name) + self._typeparams_helper(node.typeparams) + self.write(" = ") + self.traverse(node.value) + def visit_For(self, node): self._for_helper("for ", node) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 3ca5a1aea28a..73ac4405cb54 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -444,6 +444,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization) # Python 3.12b1 3529 (Inline list/dict/set comprehensions) # Python 3.12b1 3530 (Shrink the LOAD_SUPER_ATTR caches) +# Python 3.12b1 3531 (Add PEP 695 changes) # Python 3.13 will start with 3550 @@ -460,7 +461,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 = (3530).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3531).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/keyword.py b/Lib/keyword.py index cc2b46b7229d..e22c837835e7 100644 --- a/Lib/keyword.py +++ b/Lib/keyword.py @@ -56,7 +56,8 @@ softkwlist = [ '_', 'case', - 'match' + 'match', + 'type' ] iskeyword = frozenset(kwlist).__contains__ diff --git a/Lib/opcode.py b/Lib/opcode.py index 155466b1ab85..97d0a654a03a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -131,6 +131,7 @@ def pseudo_op(name, op, real_ops): def_op('RETURN_VALUE', 83) def_op('SETUP_ANNOTATIONS', 85) +def_op('LOAD_LOCALS', 87) def_op('POP_EXCEPT', 89) @@ -206,7 +207,6 @@ def pseudo_op(name, op, real_ops): def_op('LIST_APPEND', 145) def_op('SET_ADD', 146) def_op('MAP_ADD', 147) -def_op('LOAD_CLASSDEREF', 148) hasfree.append(148) def_op('COPY_FREE_VARS', 149) def_op('YIELD_VALUE', 150) @@ -228,6 +228,10 @@ def pseudo_op(name, op, real_ops): def_op('CALL_INTRINSIC_1', 173) def_op('CALL_INTRINSIC_2', 174) +name_op('LOAD_FROM_DICT_OR_GLOBALS', 175) +def_op('LOAD_FROM_DICT_OR_DEREF', 176) +hasfree.append(176) + # Instrumented instructions MIN_INSTRUMENTED_OPCODE = 238 @@ -318,12 +322,20 @@ def pseudo_op(name, op, real_ops): "INTRINSIC_ASYNC_GEN_WRAP", "INTRINSIC_UNARY_POSITIVE", "INTRINSIC_LIST_TO_TUPLE", + "INTRINSIC_TYPEVAR", + "INTRINSIC_PARAMSPEC", + "INTRINSIC_TYPEVARTUPLE", + "INTRINSIC_SUBSCRIPT_GENERIC", + "INTRINSIC_TYPEALIAS", ] _intrinsic_2_descs = [ - 'INTRINSIC_2_INVALID', - 'INTRINSIC_PREP_RERAISE_STAR', - ] + "INTRINSIC_2_INVALID", + "INTRINSIC_PREP_RERAISE_STAR", + "INTRINSIC_TYPEVAR_WITH_BOUND", + "INTRINSIC_TYPEVAR_WITH_CONSTRAINTS", + "INTRINSIC_SET_FUNCTION_TYPE_PARAMS", +] _specializations = { "BINARY_OP": [ diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d063837baee2..d555c53fee50 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -12,6 +12,7 @@ import stat import sys import sysconfig +import textwrap import time import types import unittest @@ -619,6 +620,14 @@ def sortdict(dict): withcommas = ", ".join(reprpairs) return "{%s}" % withcommas + +def run_code(code: str) -> dict[str, object]: + """Run a piece of code after dedenting it, and return its global namespace.""" + ns = {} + exec(textwrap.dedent(code), ns) + return ns + + def check_syntax_error(testcase, statement, errtext='', *, lineno=None, offset=None): with testcase.assertRaisesRegex(SyntaxError, errtext) as cm: compile(statement, '<test string>', 'exec') diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 34808ed8562e..cf128e1e8cd0 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -181,7 +181,22 @@ def to_tuple(t): "def f(a=1, /, b=2, *, c): pass", "def f(a=1, /, b=2, *, c=4, **kwargs): pass", "def f(a=1, /, b=2, *, c, **kwargs): pass", - + # Type aliases + "type X = int", + "type X[T] = int", + "type X[T, *Ts, **P] = (T, Ts, P)", + "type X[T: int, *Ts, **P] = (T, Ts, P)", + "type X[T: (int, str), *Ts, **P] = (T, Ts, P)", + # Generic classes + "class X[T]: pass", + "class X[T, *Ts, **P]: pass", + "class X[T: int, *Ts, **P]: pass", + "class X[T: (int, str), *Ts, **P]: pass", + # Generic functions + "def f[T](): pass", + "def f[T, *Ts, **P](): pass", + "def f[T: int, *Ts, **P](): pass", + "def f[T: (int, str), *Ts, **P](): pass", ] # These are compiled through "single" @@ -262,7 +277,6 @@ def to_tuple(t): "()", # Combination "a.b.c.d(a.b[1:2])", - ] # TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension @@ -1013,6 +1027,18 @@ def test_exception_groups_feature_version(self): with self.assertRaises(SyntaxError): ast.parse(code, feature_version=(3, 10)) + def test_type_params_feature_version(self): + samples = [ + "type X = int", + "class X[T]: pass", + "def f[T](): pass", + ] + for sample in samples: + with self.subTest(sample): + ast.parse(sample) + with self.assertRaises(SyntaxError): + ast.parse(sample, feature_version=(3, 11)) + def test_invalid_major_feature_version(self): with self.assertRaises(ValueError): ast.parse('pass', feature_version=(2, 7)) @@ -1557,16 +1583,16 @@ def arguments(args=None, posonlyargs=None, vararg=None, def test_funcdef(self): a = ast.arguments([], [], None, [], [], None, []) - f = ast.FunctionDef("x", a, [], [], None) + f = ast.FunctionDef("x", [], a, [], [], None) self.stmt(f, "empty body on FunctionDef") - f = ast.FunctionDef("x", a, [ast.Pass()], [ast.Name("x", ast.Store())], + f = ast.FunctionDef("x", [], a, [ast.Pass()], [ast.Name("x", ast.Store())], None) self.stmt(f, "must have Load context") - f = ast.FunctionDef("x", a, [ast.Pass()], [], + f = ast.FunctionDef("x", [], a, [ast.Pass()], [], ast.Name("x", ast.Store())) self.stmt(f, "must have Load context") def fac(args): - return ast.FunctionDef("x", args, [ast.Pass()], [], None) + return ast.FunctionDef("x", [], args, [ast.Pass()], [], None) self._check_arguments(fac, self.stmt) def test_classdef(self): @@ -1579,7 +1605,7 @@ def cls(bases=None, keywords=None, body=None, decorator_list=None): body = [ast.Pass()] if decorator_list is None: decorator_list = [] - return ast.ClassDef("myclass", bases, keywords, + return ast.ClassDef("myclass", [], bases, keywords, body, decorator_list) self.stmt(cls(bases=[ast.Name("x", ast.Store())]), "must have Load context") @@ -2869,23 +2895,23 @@ def main(): exec_results = [ ('Module', [('Expr', (1, 0, 1, 4), ('Constant', (1, 0, 1, 4), None, None))], []), ('Module', [('Expr', (1, 0, 1, 18), ('Constant', (1, 0, 1, 18), 'module docstring', None))], []), -('Module', [('FunctionDef', (1, 0, 1, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 14), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 23), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 36), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 21), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 71), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 27), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('FunctionDef', (1, 0, 1, 45), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), -('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [('Pass', (1, 8, 1, 12))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [])], []), -('Module', [('ClassDef', (1, 0, 1, 21), 'C', [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [])], []), -('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 14), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 23), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 16), 'args', ('Starred', (1, 13, 1, 16), ('Name', (1, 14, 1, 16), 'Ts', ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 19, 1, 23))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Constant', (1, 25, 1, 28), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 36), 'f', [], ('arguments', [], [], ('arg', (1, 7, 1, 29), 'args', ('Starred', (1, 13, 1, 29), ('Subscript', (1, 14, 1, 29), ('Name', (1, 14, 1, 19), 'tuple', ('Load',)), ('Tuple', (1, 20, 1, 28), [('Name', (1, 20, 1, 23), 'int', ('Load',)), ('Starred', (1, 25, 1, 28), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), ('Load',)), None), [], [], None, []), [('Pass', (1, 32, 1, 36))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 21), 'f', [], ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 71), 'f', [], ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 27), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 23, 1, 27))], [], ('Subscript', (1, 11, 1, 21), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 20), [('Starred', (1, 17, 1, 20), ('Name', (1, 18, 1, 20), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 28, 1, 32))], [], ('Subscript', (1, 11, 1, 26), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 25), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 25), ('Name', (1, 23, 1, 25), 'Ts', ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), +('Module', [('FunctionDef', (1, 0, 1, 45), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 41, 1, 45))], [], ('Subscript', (1, 11, 1, 39), ('Name', (1, 11, 1, 16), 'tuple', ('Load',)), ('Tuple', (1, 17, 1, 38), [('Name', (1, 17, 1, 20), 'int', ('Load',)), ('Starred', (1, 22, 1, 38), ('Subscript', (1, 23, 1, 38), ('Name', (1, 23, 1, 28), 'tuple', ('Load',)), ('Tuple', (1, 29, 1, 37), [('Name', (1, 29, 1, 32), 'int', ('Load',)), ('Constant', (1, 34, 1, 37), Ellipsis, None)], ('Load',)), ('Load',)), ('Load',))], ('Load',)), ('Load',)), None)], []), +('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [], [('Pass', (1, 8, 1, 12))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 21), 'C', [], [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None)], []), ('Module', [('Delete', (1, 0, 1, 5), [('Name', (1, 4, 1, 5), 'v', ('Del',))])], []), ('Module', [('Assign', (1, 0, 1, 5), [('Name', (1, 0, 1, 1), 'v', ('Store',))], ('Constant', (1, 4, 1, 5), 1, None), None)], []), ('Module', [('Assign', (1, 0, 1, 7), [('Tuple', (1, 0, 1, 3), [('Name', (1, 0, 1, 1), 'a', ('Store',)), ('Name', (1, 2, 1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 6, 1, 7), 'c', ('Load',)), None)], []), @@ -2922,28 +2948,41 @@ def main(): ('Module', [('Expr', (1, 0, 1, 20), ('DictComp', (1, 0, 1, 20), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'v', ('Store',)), ('Name', (1, 13, 1, 14), 'w', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'x', ('Load',)), [], 0)]))], []), ('Module', [('Expr', (1, 0, 1, 19), ('SetComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 12, 1, 13), 'x', ('Load',)), [('Name', (1, 17, 1, 18), 'g', ('Load',))], 0)]))], []), ('Module', [('Expr', (1, 0, 1, 16), ('SetComp', (1, 0, 1, 16), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7, 1, 10), [('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 9, 1, 10), 'm', ('Store',))], ('Store',)), ('Name', (1, 14, 1, 15), 'x', ('Load',)), [], 0)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', [], ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', [], ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None)], []), ('Module', [('Expr', (1, 0, 1, 14), ('Dict', (1, 0, 1, 14), [None, ('Constant', (1, 10, 1, 11), 2, None)], [('Dict', (1, 3, 1, 8), [('Constant', (1, 4, 1, 5), 1, None)], [('Constant', (1, 6, 1, 7), 2, None)]), ('Constant', (1, 12, 1, 13), 3, None)]))], []), ('Module', [('Expr', (1, 0, 1, 12), ('Set', (1, 0, 1, 12), [('Starred', (1, 1, 1, 8), ('Set', (1, 2, 1, 8), [('Constant', (1, 3, 1, 4), 1, None), ('Constant', (1, 6, 1, 7), 2, None)]), ('Load',)), ('Constant', (1, 10, 1, 11), 3, None)]))], []), -('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None)], []), -('Module', [('FunctionDef', (4, 0, 4, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), -('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), -('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])])], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None)], []), -('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None)], []), +('Module', [('FunctionDef', (4, 0, 4, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), +('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), +('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None)], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', [], ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), ('Module', [('Expr', (1, 0, 1, 8), ('NamedExpr', (1, 1, 1, 7), ('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Constant', (1, 6, 1, 7), 1, None)))], []), -('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 39), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 20), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 30), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 39), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 20), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 30), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 42), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 40), 'f', [], ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None)], []), +('Module', [('TypeAlias', (1, 0, 1, 12), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [], ('Name', (1, 9, 1, 12), 'int', ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 15), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None)], ('Name', (1, 12, 1, 15), 'int', ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 32), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 8), 'T', None), ('TypeVarTuple', (1, 10, 1, 13), 'Ts'), ('ParamSpec', (1, 15, 1, 18), 'P')], ('Tuple', (1, 22, 1, 32), [('Name', (1, 23, 1, 24), 'T', ('Load',)), ('Name', (1, 26, 1, 28), 'Ts', ('Load',)), ('Name', (1, 30, 1, 31), 'P', ('Load',))], ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 37), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 13), 'T', ('Name', (1, 10, 1, 13), 'int', ('Load',))), ('TypeVarTuple', (1, 15, 1, 18), 'Ts'), ('ParamSpec', (1, 20, 1, 23), 'P')], ('Tuple', (1, 27, 1, 37), [('Name', (1, 28, 1, 29), 'T', ('Load',)), ('Name', (1, 31, 1, 33), 'Ts', ('Load',)), ('Name', (1, 35, 1, 36), 'P', ('Load',))], ('Load',)))], []), +('Module', [('TypeAlias', (1, 0, 1, 44), ('Name', (1, 5, 1, 6), 'X', ('Store',)), [('TypeVar', (1, 7, 1, 20), 'T', ('Tuple', (1, 10, 1, 20), [('Name', (1, 11, 1, 14), 'int', ('Load',)), ('Name', (1, 16, 1, 19), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 22, 1, 25), 'Ts'), ('ParamSpec', (1, 27, 1, 30), 'P')], ('Tuple', (1, 34, 1, 44), [('Name', (1, 35, 1, 36), 'T', ('Load',)), ('Name', (1, 38, 1, 40), 'Ts', ('Load',)), ('Name', (1, 42, 1, 43), 'P', ('Load',))], ('Load',)))], []), +('Module', [('ClassDef', (1, 0, 1, 16), 'X', [('TypeVar', (1, 8, 1, 9), 'T', None)], [], [], [('Pass', (1, 12, 1, 16))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 26), 'X', [('TypeVar', (1, 8, 1, 9), 'T', None), ('TypeVarTuple', (1, 11, 1, 14), 'Ts'), ('ParamSpec', (1, 16, 1, 19), 'P')], [], [], [('Pass', (1, 22, 1, 26))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 31), 'X', [('TypeVar', (1, 8, 1, 14), 'T', ('Name', (1, 11, 1, 14), 'int', ('Load',))), ('TypeVarTuple', (1, 16, 1, 19), 'Ts'), ('ParamSpec', (1, 21, 1, 24), 'P')], [], [], [('Pass', (1, 27, 1, 31))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 38), 'X', [('TypeVar', (1, 8, 1, 21), 'T', ('Tuple', (1, 11, 1, 21), [('Name', (1, 12, 1, 15), 'int', ('Load',)), ('Name', (1, 17, 1, 20), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 23, 1, 26), 'Ts'), ('ParamSpec', (1, 28, 1, 31), 'P')], [], [], [('Pass', (1, 34, 1, 38))], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', [('TypeVar', (1, 6, 1, 7), 'T', None)], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 12, 1, 16))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', [('TypeVar', (1, 6, 1, 7), 'T', None), ('TypeVarTuple', (1, 9, 1, 12), 'Ts'), ('ParamSpec', (1, 14, 1, 17), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 31), 'f', [('TypeVar', (1, 6, 1, 12), 'T', ('Name', (1, 9, 1, 12), 'int', ('Load',))), ('TypeVarTuple', (1, 14, 1, 17), 'Ts'), ('ParamSpec', (1, 19, 1, 22), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 27, 1, 31))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 38), 'f', [('TypeVar', (1, 6, 1, 19), 'T', ('Tuple', (1, 9, 1, 19), [('Name', (1, 10, 1, 13), 'int', ('Load',)), ('Name', (1, 15, 1, 18), 'str', ('Load',))], ('Load',))), ('TypeVarTuple', (1, 21, 1, 24), 'Ts'), ('ParamSpec', (1, 26, 1, 29), 'P')], ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 34, 1, 38))], [], None, None)], []), ] single_results = [ ('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]), diff --git a/Lib/test/test_keyword.py b/Lib/test/test_keyword.py index f329f88fa01d..858e5de3b92e 100644 --- a/Lib/test/test_keyword.py +++ b/Lib/test/test_keyword.py @@ -39,7 +39,8 @@ def test_async_and_await_are_keywords(self): self.assertIn("async", keyword.kwlist) self.assertIn("await", keyword.kwlist) - def test_match_and_case_are_soft_keywords(self): + def test_soft_keywords(self): + self.assertIn("type", keyword.softkwlist) self.assertIn("match", keyword.softkwlist) self.assertIn("case", keyword.softkwlist) self.assertIn("_", keyword.softkwlist) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index e1db450bf8a2..d81501f6f1df 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1449,7 +1449,7 @@ def func(): check(x, size('3Pi3c7P2ic??2P')) # function def func(): pass - check(func, size('14Pi')) + check(func, size('15Pi')) class c(): @staticmethod def foo(): diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py new file mode 100644 index 000000000000..d2abb932f589 --- /dev/null +++ b/Lib/test/test_type_aliases.py @@ -0,0 +1,204 @@ +import types +import unittest +from test.support import check_syntax_error, run_code + +from typing import Callable, TypeAliasType, TypeVar, get_args + + +class TypeParamsInvalidTest(unittest.TestCase): + def test_name_collision_01(self): + check_syntax_error(self, """type TA1[A, **A] = None""", "duplicate type parameter 'A'") + + def test_name_non_collision_02(self): + ns = run_code("""type TA1[A] = lambda A: A""") + self.assertIsInstance(ns["TA1"], TypeAliasType) + self.assertTrue(callable(ns["TA1"].__value__)) + self.assertEqual("arg", ns["TA1"].__value__("arg")) + + def test_name_non_collision_03(self): + ns = run_code(""" + class Outer[A]: + type TA1[A] = None + """ + ) + outer_A, = ns["Outer"].__type_params__ + inner_A, = ns["Outer"].TA1.__type_params__ + self.assertIsNot(outer_A, inner_A) + + +class TypeParamsAccessTest(unittest.TestCase): + def test_alias_access_01(self): + ns = run_code("type TA1[A, B] = dict[A, B]") + alias = ns["TA1"] + self.assertIsInstance(alias, TypeAliasType) + self.assertEqual(alias.__type_params__, get_args(alias.__value__)) + + def test_alias_access_02(self): + ns = run_code(""" + type TA1[A, B] = TA1[A, B] | int + """ + ) + alias = ns["TA1"] + self.assertIsInstance(alias, TypeAliasType) + A, B = alias.__type_params__ + self.assertEqual(alias.__value__, alias[A, B] | int) + + def test_alias_access_03(self): + ns = run_code(""" + class Outer[A]: + def inner[B](self): + type TA1[C] = TA1[A, B] | int + return TA1 + """ + ) + cls = ns["Outer"] + A, = cls.__type_params__ + B, = cls.inner.__type_params__ + alias = cls.inner(None) + self.assertIsInstance(alias, TypeAliasType) + alias2 = cls.inner(None) + self.assertIsNot(alias, alias2) + self.assertEqual(len(alias.__type_params__), 1) + + self.assertEqual(alias.__value__, alias[A, B] | int) + + +class TypeParamsAliasValueTest(unittest.TestCase): + def test_alias_value_01(self): + type TA1 = int + + self.assertIsInstance(TA1, TypeAliasType) + self.assertEqual(TA1.__value__, int) + self.assertEqual(TA1.__parameters__, ()) + self.assertEqual(TA1.__type_params__, ()) + + type TA2 = TA1 | str + + self.assertIsInstance(TA2, TypeAliasType) + a, b = TA2.__value__.__args__ + self.assertEqual(a, TA1) + self.assertEqual(b, str) + self.assertEqual(TA2.__parameters__, ()) + self.assertEqual(TA2.__type_params__, ()) + + def test_alias_value_02(self): + class Parent[A]: + type TA1[B] = dict[A, B] + + self.assertIsInstance(Parent.TA1, TypeAliasType) + self.assertEqual(len(Parent.TA1.__parameters__), 1) + self.assertEqual(len(Parent.__parameters__), 1) + a, = Parent.__parameters__ + b, = Parent.TA1.__parameters__ + self.assertEqual(Parent.__type_params__, (a,)) + self.assertEqual(Parent.TA1.__type_params__, (b,)) + self.assertEqual(Parent.TA1.__value__, dict[a, b]) + + def test_alias_value_03(self): + def outer[A](): + type TA1[B] = dict[A, B] + return TA1 + + o = outer() + self.assertIsInstance(o, TypeAliasType) + self.assertEqual(len(o.__parameters__), 1) + self.assertEqual(len(outer.__type_params__), 1) + b = o.__parameters__[0] + self.assertEqual(o.__type_params__, (b,)) + + def test_alias_value_04(self): + def more_generic[T, *Ts, **P](): + type TA[T2, *Ts2, **P2] = tuple[Callable[P, tuple[T, *Ts]], Callable[P2, tuple[T2, *Ts2]]] + return TA + + alias = more_generic() + self.assertIsInstance(alias, TypeAliasType) + T2, Ts2, P2 = alias.__type_params__ + self.assertEqual(alias.__parameters__, (T2, *Ts2, P2)) + T, Ts, P = more_generic.__type_params__ + self.assertEqual(alias.__value__, tuple[Callable[P, tuple[T, *Ts]], Callable[P2, tuple[T2, *Ts2]]]) + + def test_subscripting(self): + type NonGeneric = int + type Generic[A] = dict[A, A] + type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] + + with self.assertRaises(TypeError): + NonGeneric[int] + + specialized = Generic[int] + self.assertIsInstance(specialized, types.GenericAlias) + self.assertIs(specialized.__origin__, Generic) + self.assertEqual(specialized.__args__, (int,)) + + specialized2 = VeryGeneric[int, str, float, [bool, range]] + self.assertIsInstance(specialized2, types.GenericAlias) + self.assertIs(specialized2.__origin__, VeryGeneric) + self.assertEqual(specialized2.__args__, (int, str, float, [bool, range])) + + def test_repr(self): + type Simple = int + self.assertEqual(repr(Simple), "Simple") + + def test_recursive_repr(self): + type Recursive = Recursive + self.assertEqual(repr(Recursive), "Recursive") + + type X = list[Y] + type Y = list[X] + self.assertEqual(repr(X), "X") + + +class TypeAliasConstructorTest(unittest.TestCase): + def test_basic(self): + TA = TypeAliasType("TA", int) + self.assertEqual(TA.__name__, "TA") + self.assertIs(TA.__value__, int) + self.assertEqual(TA.__type_params__, ()) + + def test_generic(self): + T = TypeVar("T") + TA = TypeAliasType("TA", list[T], type_params=(T,)) + self.assertEqual(TA.__name__, "TA") + self.assertEqual(TA.__value__, list[T]) + self.assertEqual(TA.__type_params__, (T,)) + + def test_keywords(self): + TA = TypeAliasType(name="TA", value=int) + self.assertEqual(TA.__name__, "TA") + self.assertIs(TA.__value__, int) + self.assertEqual(TA.__type_params__, ()) + + def test_errors(self): + with self.assertRaises(TypeError): + TypeAliasType() + with self.assertRaises(TypeError): + TypeAliasType("TA") + with self.assertRaises(TypeError): + TypeAliasType("TA", list, ()) + with self.assertRaises(TypeError): + TypeAliasType("TA", list, type_params=42) + + +class TypeAliasTypeTest(unittest.TestCase): + def test_immutable(self): + with self.assertRaises(TypeError): + TypeAliasType.whatever = "not allowed" + + def test_no_subclassing(self): + with self.assertRaisesRegex(TypeError, "not an acceptable base type"): + class MyAlias(TypeAliasType): + pass + + def test_union(self): + type Alias1 = int + type Alias2 = str + union = Alias1 | Alias2 + self.assertIsInstance(union, types.UnionType) + self.assertEqual(get_args(union), (Alias1, Alias2)) + union2 = Alias1 | list[float] + self.assertIsInstance(union2, types.UnionType) + self.assertEqual(get_args(union2), (Alias1, list[float])) + union3 = list[range] | Alias1 + self.assertIsInstance(union3, types.UnionType) + self.assertEqual(get_args(union3), (list[range], Alias1)) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py new file mode 100644 index 000000000000..3ca13c21c61a --- /dev/null +++ b/Lib/test/test_type_params.py @@ -0,0 +1,847 @@ +import asyncio +import textwrap +import types +import unittest +from test.support import requires_working_socket, check_syntax_error, run_code + +from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args + + +class TypeParamsInvalidTest(unittest.TestCase): + def test_name_collision_01(self): + check_syntax_error(self, """def func[**A, A](): ...""") + + def test_name_non_collision_02(self): + ns = run_code("""def func[A](A): return A""") + func = ns["func"] + self.assertEqual(func(1), 1) + A, = func.__type_params__ + self.assertEqual(A.__name__, "A") + + def test_name_non_collision_03(self): + ns = run_code("""def func[A](*A): return A""") + func = ns["func"] + self.assertEqual(func(1), (1,)) + A, = func.__type_params__ + self.assertEqual(A.__name__, "A") + + def test_name_non_collision_04(self): + # Mangled names should not cause a conflict. + ns = run_code(""" + class ClassA: + def func[__A](self, __A): return __A + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(1), 1) + A, = cls.func.__type_params__ + self.assertEqual(A.__name__, "__A") + + def test_name_non_collision_05(self): + ns = run_code(""" + class ClassA: + def func[_ClassA__A](self, __A): return __A + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(1), 1) + A, = cls.func.__type_params__ + self.assertEqual(A.__name__, "_ClassA__A") + + def test_name_non_collision_06(self): + ns = run_code(""" + class ClassA[X]: + def func(self, X): return X + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(1), 1) + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + + def test_name_non_collision_07(self): + ns = run_code(""" + class ClassA[X]: + def func(self): + X = 1 + return X + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(), 1) + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + + def test_name_non_collision_08(self): + ns = run_code(""" + class ClassA[X]: + def func(self): + return [X for X in [1, 2]] + """ + ) + cls = ns["ClassA"] + self.assertEqual(cls().func(), [1, 2]) + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + + def test_name_non_collision_9(self): + ns = run_code(""" + class ClassA[X]: + def func[X](self): + ... + """ + ) + cls = ns["ClassA"] + outer_X, = cls.__type_params__ + inner_X, = cls.func.__type_params__ + self.assertEqual(outer_X.__name__, "X") + self.assertEqual(inner_X.__name__, "X") + self.assertIsNot(outer_X, inner_X) + + def test_name_non_collision_10(self): + ns = run_code(""" + class ClassA[X]: + X: int + """ + ) + cls = ns["ClassA"] + X, = cls.__type_params__ + self.assertEqual(X.__name__, "X") + self.assertIs(cls.__annotations__["X"], int) + + def test_name_non_collision_13(self): + ns = run_code(""" + X = 1 + def outer(): + def inner[X](): + global X + X = 2 + return inner + """ + ) + self.assertEqual(ns["X"], 1) + outer = ns["outer"] + outer()() + self.assertEqual(ns["X"], 2) + + def test_disallowed_expressions(self): + check_syntax_error(self, "type X = (yield)") + check_syntax_error(self, "type X = (yield from x)") + check_syntax_error(self, "type X = (await 42)") + check_syntax_error(self, "async def f(): type X = (yield)") + check_syntax_error(self, "type X = (y := 3)") + check_syntax_error(self, "class X[T: (yield)]: pass") + check_syntax_error(self, "class X[T: (yield from x)]: pass") + check_syntax_error(self, "class X[T: (await 42)]: pass") + check_syntax_error(self, "class X[T: (y := 3)]: pass") + check_syntax_error(self, "class X[T](y := Sequence[T]): pass") + check_syntax_error(self, "def f[T](y: (x := Sequence[T])): pass") + + +class TypeParamsNonlocalTest(unittest.TestCase): + def test_nonlocal_disallowed_01(self): + code = """ + def outer(): + X = 1 + def inner[X](): + nonlocal X + return X + """ + check_syntax_error(self, code) + + def test_nonlocal_disallowed_02(self): + code = """ + def outer2[T](): + def inner1(): + nonlocal T + """ + check_syntax_error(self, textwrap.dedent(code)) + + def test_nonlocal_disallowed_03(self): + code = """ + class Cls[T]: + nonlocal T + """ + check_syntax_error(self, textwrap.dedent(code)) + + def test_nonlocal_allowed(self): + code = """ + def func[T](): + T = "func" + def inner(): + nonlocal T + T = "inner" + inner() + assert T == "inner" + """ + ns = run_code(code) + func = ns["func"] + T, = func.__type_params__ + self.assertEqual(T.__name__, "T") + + +class TypeParamsAccessTest(unittest.TestCase): + def test_class_access_01(self): + ns = run_code(""" + class ClassA[A, B](dict[A, B]): + ... + """ + ) + cls = ns["ClassA"] + A, B = cls.__type_params__ + self.assertEqual(types.get_original_bases(cls), (dict[A, B], Generic[A, B])) + + def test_class_access_02(self): + ns = run_code(""" + class MyMeta[A, B](type): ... + class ClassA[A, B](metaclass=MyMeta[A, B]): + ... + """ + ) + meta = ns["MyMeta"] + cls = ns["ClassA"] + A1, B1 = meta.__type_params__ + A2, B2 = cls.__type_params__ + self.assertIsNot(A1, A2) + self.assertIsNot(B1, B2) + self.assertIs(type(cls), meta) + + def test_class_access_03(self): + code = """ + def my_decorator(a): + ... + @my_decorator(A) + class ClassA[A, B](): + ... + """ + + with self.assertRaisesRegex(NameError, "name 'A' is not defined"): + run_code(code) + + def test_function_access_01(self): + ns = run_code(""" + def func[A, B](a: dict[A, B]): + ... + """ + ) + func = ns["func"] + A, B = func.__type_params__ + self.assertEqual(func.__annotations__["a"], dict[A, B]) + + def test_function_access_02(self): + code = """ + def func[A](a = list[A]()): + ... + """ + + with self.assertRaisesRegex(NameError, "name 'A' is not defined"): + run_code(code) + + def test_function_access_03(self): + code = """ + def my_decorator(a): + ... + @my_decorator(A) + def func[A](): + ... + """ + + with self.assertRaisesRegex(NameError, "name 'A' is not defined"): + run_code(code) + + def test_method_access_01(self): + ns = run_code(""" + class ClassA: + x = int + def func[T](self, a: x, b: T): + ... + """ + ) + cls = ns["ClassA"] + self.assertIs(cls.func.__annotations__["a"], int) + T, = cls.func.__type_params__ + self.assertIs(cls.func.__annotations__["b"], T) + + def test_nested_access_01(self): + ns = run_code(""" + class ClassA[A]: + def funcB[B](self): + class ClassC[C]: + def funcD[D](self): + return lambda: (A, B, C, D) + return ClassC + """ + ) + cls = ns["ClassA"] + A, = cls.__type_params__ + B, = cls.funcB.__type_params__ + classC = cls().funcB() + C, = classC.__type_params__ + D, = classC.funcD.__type_params__ + self.assertEqual(classC().funcD()(), (A, B, C, D)) + + def test_out_of_scope_01(self): + code = """ + class ClassA[T]: ... + x = T + """ + + with self.assertRaisesRegex(NameError, "name 'T' is not defined"): + run_code(code) + + def test_out_of_scope_02(self): + code = """ + class ClassA[A]: + def funcB[B](self): ... + + x = B + """ + + with self.assertRaisesRegex(NameError, "name 'B' is not defined"): + run_code(code) + + def test_class_scope_interaction_01(self): + ns = run_code(""" + class C: + x = 1 + def method[T](self, arg: x): pass + """) + cls = ns["C"] + self.assertEqual(cls.method.__annotations__["arg"], 1) + + def test_class_scope_interaction_02(self): + ns = run_code(""" + class C: + class Base: pass + class Child[T](Base): pass + """) + cls = ns["C"] + self.assertEqual(cls.Child.__bases__, (cls.Base, Generic)) + T, = cls.Child.__type_params__ + self.assertEqual(types.get_original_bases(cls.Child), (cls.Base, Generic[T])) + + def test_class_deref(self): + ns = run_code(""" + class C[T]: + T = "class" + type Alias = T + """) + cls = ns["C"] + self.assertEqual(cls.Alias.__value__, "class") + + def test_shadowing_nonlocal(self): + ns = run_code(""" + def outer[T](): + T = "outer" + def inner(): + nonlocal T + T = "inner" + return T + return lambda: T, inner + """) + outer = ns["outer"] + T, = outer.__type_params__ + self.assertEqual(T.__name__, "T") + getter, inner = outer() + self.assertEqual(getter(), "outer") + self.assertEqual(inner(), "inner") + self.assertEqual(getter(), "inner") + + def test_reference_previous_typevar(self): + def func[S, T: Sequence[S]](): + pass + + S, T = func.__type_params__ + self.assertEqual(T.__bound__, Sequence[S]) + + def test_super(self): + class Base: + def meth(self): + return "base" + + class Child(Base): + # Having int in the annotation ensures the class gets cells for both + # __class__ and __classdict__ + def meth[T](self, arg: int) -> T: + return super().meth() + "child" + + c = Child() + self.assertEqual(c.meth(1), "basechild") + + def test_type_alias_containing_lambda(self): + type Alias[T] = lambda: T + T, = Alias.__type_params__ + self.assertIs(Alias.__value__(), T) + + def test_class_base_containing_lambda(self): + # Test that scopes nested inside hidden functions work correctly + outer_var = "outer" + class Base[T]: ... + class Child[T](Base[lambda: (int, outer_var, T)]): ... + base, _ = types.get_original_bases(Child) + func, = get_args(base) + T, = Child.__type_params__ + self.assertEqual(func(), (int, "outer", T)) + + def test_comprehension_01(self): + type Alias[T: ([T for T in (T, [1])[1]], T)] = [T for T in T.__name__] + self.assertEqual(Alias.__value__, ["T"]) + T, = Alias.__type_params__ + self.assertEqual(T.__constraints__, ([1], T)) + + def test_comprehension_02(self): + type Alias[T: [lambda: T for T in (T, [1])[1]]] = [lambda: T for T in T.__name__] + func, = Alias.__value__ + self.assertEqual(func(), "T") + T, = Alias.__type_params__ + func, = T.__bound__ + self.assertEqual(func(), 1) + + +def global_generic_func[T](): + pass + +class GlobalGenericClass[T]: + pass + + +class TypeParamsLazyEvaluationTest(unittest.TestCase): + def test_qualname(self): + class Foo[T]: + pass + + def func[T](): + pass + + self.assertEqual(Foo.__qualname__, "TypeParamsLazyEvaluationTest.test_qualname.<locals>.Foo") + self.assertEqual(func.__qualname__, "TypeParamsLazyEvaluationTest.test_qualname.<locals>.func") + self.assertEqual(global_generic_func.__qualname__, "global_generic_func") + self.assertEqual(GlobalGenericClass.__qualname__, "GlobalGenericClass") + + def test_recursive_class(self): + class Foo[T: Foo, U: (Foo, Foo)]: + pass + + type_params = Foo.__type_params__ + self.assertEqual(len(type_params), 2) + self.assertEqual(type_params[0].__name__, "T") + self.assertEqual(type_params[0].__bound__, Foo) + self.assertEqual(type_params[0].__constraints__, None) + + self.assertEqual(type_params[1].__name__, "U") + self.assertEqual(type_params[1].__bound__, None) + self.assertEqual(type_params[1].__constraints__, (Foo, Foo)) + + def test_evaluation_error(self): + class Foo[T: Undefined, U: (Undefined,)]: + pass + + type_params = Foo.__type_params__ + with self.assertRaises(NameError): + type_params[0].__bound__ + self.assertEqual(type_params[0].__constraints__, None) + self.assertEqual(type_params[1].__bound__, None) + with self.assertRaises(NameError): + type_params[1].__constraints__ + + Undefined = "defined" + self.assertEqual(type_params[0].__bound__, "defined") + self.assertEqual(type_params[0].__constraints__, None) + + self.assertEqual(type_params[1].__bound__, None) + self.assertEqual(type_params[1].__constraints__, ("defined",)) + + +class TypeParamsClassScopeTest(unittest.TestCase): + def test_alias(self): + class X: + T = int + type U = T + self.assertIs(X.U.__value__, int) + + ns = run_code(""" + glb = "global" + class X: + cls = "class" + type U = (glb, cls) + """) + cls = ns["X"] + self.assertEqual(cls.U.__value__, ("global", "class")) + + def test_bound(self): + class X: + T = int + def foo[U: T](self): ... + self.assertIs(X.foo.__type_params__[0].__bound__, int) + + ns = run_code(""" + glb = "global" + class X: + cls = "class" + def foo[T: glb, U: cls](self): ... + """) + cls = ns["X"] + T, U = cls.foo.__type_params__ + self.assertEqual(T.__bound__, "global") + self.assertEqual(U.__bound__, "class") + + def test_modified_later(self): + class X: + T = int + def foo[U: T](self): ... + type Alias = T + X.T = float + self.assertIs(X.foo.__type_params__[0].__bound__, float) + self.assertIs(X.Alias.__value__, float) + + def test_binding_uses_global(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + type Alias = x + val = Alias.__value__ + def meth[T: x](self, arg: x): ... + bound = meth.__type_params__[0].__bound__ + annotation = meth.__annotations__["arg"] + x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.val, "global") + self.assertEqual(cls.bound, "global") + self.assertEqual(cls.annotation, "global") + + def test_no_binding_uses_nonlocal(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + type Alias = x + val = Alias.__value__ + def meth[T: x](self, arg: x): ... + bound = meth.__type_params__[0].__bound__ + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.val, "nonlocal") + self.assertEqual(cls.bound, "nonlocal") + self.assertEqual(cls.meth.__annotations__["arg"], "nonlocal") + + def test_explicit_global(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + global x + type Alias = x + Cls.x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "global") + + def test_explicit_global_with_no_static_bound(self): + ns = run_code(""" + def outer(): + class Cls: + global x + type Alias = x + Cls.x = "class" + return Cls + """) + ns["x"] = "global" + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "global") + + def test_explicit_global_with_assignment(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + global x + type Alias = x + x = "global from class" + Cls.x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "global from class") + + def test_explicit_nonlocal(self): + ns = run_code(""" + x = "global" + def outer(): + x = "nonlocal" + class Cls: + nonlocal x + type Alias = x + x = "class" + return Cls + """) + cls = ns["outer"]() + self.assertEqual(cls.Alias.__value__, "class") + + +class TypeParamsManglingTest(unittest.TestCase): + def test_mangling(self): + class Foo[__T]: + param = __T + def meth[__U](self, arg: __T, arg2: __U): + return (__T, __U) + type Alias[__V] = (__T, __V) + + T = Foo.__type_params__[0] + self.assertEqual(T.__name__, "__T") + U = Foo.meth.__type_params__[0] + self.assertEqual(U.__name__, "__U") + V = Foo.Alias.__type_params__[0] + self.assertEqual(V.__name__, "__V") + + anno = Foo.meth.__annotations__ + self.assertIs(anno["arg"], T) + self.assertIs(anno["arg2"], U) + self.assertEqual(Foo().meth(1, 2), (T, U)) + + self.assertEqual(Foo.Alias.__value__, (T, V)) + + +class TypeParamsComplexCallsTest(unittest.TestCase): + def test_defaults(self): + # Generic functions with both defaults and kwdefaults trigger a specific code path + # in the compiler. + def func[T](a: T = "a", *, b: T = "b"): + return (a, b) + + T, = func.__type_params__ + self.assertIs(func.__annotations__["a"], T) + self.assertIs(func.__annotations__["b"], T) + self.assertEqual(func(), ("a", "b")) + self.assertEqual(func(1), (1, "b")) + self.assertEqual(func(b=2), ("a", 2)) + + def test_complex_base(self): + class Base: + def __init_subclass__(cls, **kwargs) -> None: + cls.kwargs = kwargs + + kwargs = {"c": 3} + # Base classes with **kwargs trigger a different code path in the compiler. + class C[T](Base, a=1, b=2, **kwargs): + pass + + T, = C.__type_params__ + self.assertEqual(T.__name__, "T") + self.assertEqual(C.kwargs, {"a": 1, "b": 2, "c": 3}) + + bases = (Base,) + class C2[T](*bases, **kwargs): + pass + + T, = C2.__type_params__ + self.assertEqual(T.__name__, "T") + self.assertEqual(C2.kwargs, {"c": 3}) + + +class TypeParamsTraditionalTypeVarsTest(unittest.TestCase): + def test_traditional_01(self): + code = """ + from typing import Generic + class ClassA[T](Generic[T]): ... + """ + + with self.assertRaisesRegex(TypeError, r"Cannot inherit from Generic\[...\] multiple times."): + run_code(code) + + def test_traditional_02(self): + from typing import TypeVar + S = TypeVar("S") + with self.assertRaises(TypeError): + class ClassA[T](dict[T, S]): ... + + def test_traditional_03(self): + # This does not generate a runtime error, but it should be + # flagged as an error by type checkers. + from typing import TypeVar + S = TypeVar("S") + def func[T](a: T, b: S) -> T | S: + return a + + +class TypeParamsTypeVarTest(unittest.TestCase): + def test_typevar_01(self): + def func1[A: str, B: str | int, C: (int, str)](): + return (A, B, C) + + a, b, c = func1() + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__bound__, str) + self.assertTrue(a.__infer_variance__) + self.assertFalse(a.__covariant__) + self.assertFalse(a.__contravariant__) + + self.assertIsInstance(b, TypeVar) + self.assertEqual(b.__bound__, str | int) + self.assertTrue(b.__infer_variance__) + self.assertFalse(b.__covariant__) + self.assertFalse(b.__contravariant__) + + self.assertIsInstance(c, TypeVar) + self.assertEqual(c.__bound__, None) + self.assertEqual(c.__constraints__, (int, str)) + self.assertTrue(c.__infer_variance__) + self.assertFalse(c.__covariant__) + self.assertFalse(c.__contravariant__) + + def test_typevar_generator(self): + def get_generator[A](): + def generator1[C](): + yield C + + def generator2[B](): + yield A + yield B + yield from generator1() + return generator2 + + gen = get_generator() + + a, b, c = [x for x in gen()] + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__name__, "A") + self.assertIsInstance(b, TypeVar) + self.assertEqual(b.__name__, "B") + self.assertIsInstance(c, TypeVar) + self.assertEqual(c.__name__, "C") + + @requires_working_socket() + def test_typevar_coroutine(self): + def get_coroutine[A](): + async def coroutine[B](): + return (A, B) + return coroutine + + co = get_coroutine() + + self.addCleanup(asyncio.set_event_loop_policy, None) + a, b = asyncio.run(co()) + + self.assertIsInstance(a, TypeVar) + self.assertEqual(a.__name__, "A") + self.assertIsInstance(b, TypeVar) + self.assertEqual(b.__name__, "B") + + +class TypeParamsTypeVarTupleTest(unittest.TestCase): + def test_typevartuple_01(self): + code = """def func1[*A: str](): pass""" + check_syntax_error(self, code, "cannot use bound with TypeVarTuple") + code = """def func1[*A: (int, str)](): pass""" + check_syntax_error(self, code, "cannot use constraints with TypeVarTuple") + code = """class X[*A: str]: pass""" + check_syntax_error(self, code, "cannot use bound with TypeVarTuple") + code = """class X[*A: (int, str)]: pass""" + check_syntax_error(self, code, "cannot use constraints with TypeVarTuple") + code = """type X[*A: str] = int""" + check_syntax_error(self, code, "cannot use bound with TypeVarTuple") + code = """type X[*A: (int, str)] = int""" + check_syntax_error(self, code, "cannot use constraints with TypeVarTuple") + + def test_typevartuple_02(self): + def func1[*A](): + return A + + a = func1() + self.assertIsInstance(a, TypeVarTuple) + + +class TypeParamsTypeVarParamSpecTest(unittest.TestCase): + def test_paramspec_01(self): + code = """def func1[**A: str](): pass""" + check_syntax_error(self, code, "cannot use bound with ParamSpec") + code = """def func1[**A: (int, str)](): pass""" + check_syntax_error(self, code, "cannot use constraints with ParamSpec") + code = """class X[**A: str]: pass""" + check_syntax_error(self, code, "cannot use bound with ParamSpec") + code = """class X[**A: (int, str)]: pass""" + check_syntax_error(self, code, "cannot use constraints with ParamSpec") + code = """type X[**A: str] = int""" + check_syntax_error(self, code, "cannot use bound with ParamSpec") + code = """type X[**A: (int, str)] = int""" + check_syntax_error(self, code, "cannot use constraints with ParamSpec") + + def test_paramspec_02(self): + def func1[**A](): + return A + + a = func1() + self.assertIsInstance(a, ParamSpec) + self.assertTrue(a.__infer_variance__) + self.assertFalse(a.__covariant__) + self.assertFalse(a.__contravariant__) + + +class TypeParamsTypeParamsDunder(unittest.TestCase): + def test_typeparams_dunder_class_01(self): + class Outer[A, B]: + class Inner[C, D]: + @staticmethod + def get_typeparams(): + return A, B, C, D + + a, b, c, d = Outer.Inner.get_typeparams() + self.assertEqual(Outer.__type_params__, (a, b)) + self.assertEqual(Outer.Inner.__type_params__, (c, d)) + + self.assertEqual(Outer.__parameters__, (a, b)) + self.assertEqual(Outer.Inner.__parameters__, (c, d)) + + def test_typeparams_dunder_class_02(self): + class ClassA: + pass + + self.assertEqual(ClassA.__type_params__, ()) + + def test_typeparams_dunder_class_03(self): + code = """ + class ClassA[A](): + pass + ClassA.__type_params__ = () + """ + + with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'type' objects is not writable"): + run_code(code) + + def test_typeparams_dunder_function_01(self): + def outer[A, B](): + def inner[C, D](): + return A, B, C, D + + return inner + + inner = outer() + a, b, c, d = inner() + self.assertEqual(outer.__type_params__, (a, b)) + self.assertEqual(inner.__type_params__, (c, d)) + + def test_typeparams_dunder_function_02(self): + def func1(): + pass + + self.assertEqual(func1.__type_params__, ()) + + def test_typeparams_dunder_function_03(self): + code = """ + def func[A](): + pass + func.__type_params__ = () + """ + + with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'function' objects is not writable"): + run_code(code) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index e1c6a8a7f376..71aff87dcaa3 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -48,11 +48,8 @@ from test import _typed_dict_helper -py_typing = import_helper.import_fresh_module('typing', blocked=['_typing']) -c_typing = import_helper.import_fresh_module('typing', fresh=['_typing']) - - CANNOT_SUBCLASS_TYPE = 'Cannot subclass special typing classes' +NOT_A_BASE_TYPE = "type 'typing.%s' is not an acceptable base type" CANNOT_SUBCLASS_INSTANCE = 'Cannot subclass an instance of %s' @@ -430,7 +427,7 @@ def test_no_redefinition(self): self.assertNotEqual(TypeVar('T', int, str), TypeVar('T', int, str)) def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'TypeVar'): class V(TypeVar): pass T = TypeVar("T") with self.assertRaisesRegex(TypeError, @@ -446,6 +443,9 @@ def test_bound_errors(self): TypeVar('X', bound=Union) with self.assertRaises(TypeError): TypeVar('X', str, float, bound=Employee) + with self.assertRaisesRegex(TypeError, + r"Bound must be a type\. Got \(1, 2\)\."): + TypeVar('X', bound=(1, 2)) def test_missing__name__(self): # See bpo-39942 @@ -1161,7 +1161,7 @@ class A(Generic[Unpack[Ts]]): pass self.assertEndsWith(repr(K[float, str]), 'A[float, str, typing.Unpack[typing.Tuple[str, ...]]]') def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'TypeVarTuple'): class C(TypeVarTuple): pass Ts = TypeVarTuple('Ts') with self.assertRaisesRegex(TypeError, @@ -6444,34 +6444,27 @@ def foo(a: A) -> Optional[BaseException]: class TestModules(TestCase): func_names = ['_idfunc'] - def test_py_functions(self): - for fname in self.func_names: - self.assertEqual(getattr(py_typing, fname).__module__, 'typing') - - @skipUnless(c_typing, 'requires _typing') def test_c_functions(self): for fname in self.func_names: - self.assertEqual(getattr(c_typing, fname).__module__, '_typing') + self.assertEqual(getattr(typing, fname).__module__, '_typing') -class NewTypeTests: +class NewTypeTests(BaseTestCase): def cleanup(self): - for f in self.module._cleanups: + for f in typing._cleanups: f() @classmethod def setUpClass(cls): - sys.modules['typing'] = cls.module global UserId - UserId = cls.module.NewType('UserId', int) - cls.UserName = cls.module.NewType(cls.__qualname__ + '.UserName', str) + UserId = typing.NewType('UserId', int) + cls.UserName = typing.NewType(cls.__qualname__ + '.UserName', str) @classmethod def tearDownClass(cls): global UserId del UserId del cls.UserName - sys.modules['typing'] = typing def tearDown(self): self.cleanup() @@ -6491,11 +6484,11 @@ class D(UserId): def test_or(self): for cls in (int, self.UserName): with self.subTest(cls=cls): - self.assertEqual(UserId | cls, self.module.Union[UserId, cls]) - self.assertEqual(cls | UserId, self.module.Union[cls, UserId]) + self.assertEqual(UserId | cls, typing.Union[UserId, cls]) + self.assertEqual(cls | UserId, typing.Union[cls, UserId]) - self.assertEqual(self.module.get_args(UserId | cls), (UserId, cls)) - self.assertEqual(self.module.get_args(cls | UserId), (cls, UserId)) + self.assertEqual(typing.get_args(UserId | cls), (UserId, cls)) + self.assertEqual(typing.get_args(cls | UserId), (cls, UserId)) def test_special_attrs(self): self.assertEqual(UserId.__name__, 'UserId') @@ -6516,7 +6509,7 @@ def test_repr(self): f'{__name__}.{self.__class__.__qualname__}.UserName') def test_pickle(self): - UserAge = self.module.NewType('UserAge', float) + UserAge = typing.NewType('UserAge', float) for proto in range(pickle.HIGHEST_PROTOCOL + 1): with self.subTest(proto=proto): pickled = pickle.dumps(UserId, proto) @@ -6548,15 +6541,6 @@ class ProUserId(UserId): ... -class NewTypePythonTests(NewTypeTests, BaseTestCase): - module = py_typing - - - at skipUnless(c_typing, 'requires _typing') -class NewTypeCTests(NewTypeTests, BaseTestCase): - module = c_typing - - class NamedTupleTests(BaseTestCase): class NestedEmployee(NamedTuple): name: str @@ -8170,11 +8154,11 @@ def test_paramspec_gets_copied(self): self.assertEqual(C2[Concatenate[T, P2]].__parameters__, (T, P2)) def test_cannot_subclass(self): - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpec'): class C(ParamSpec): pass - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpecArgs'): class C(ParamSpecArgs): pass - with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE): + with self.assertRaisesRegex(TypeError, NOT_A_BASE_TYPE % 'ParamSpecKwargs'): class C(ParamSpecKwargs): pass P = ParamSpec('P') with self.assertRaisesRegex(TypeError, diff --git a/Lib/typing.py b/Lib/typing.py index 61aed0980ac2..8d132e2cbf87 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -23,6 +23,7 @@ import collections from collections import defaultdict import collections.abc +import copyreg import contextlib import functools import operator @@ -32,12 +33,16 @@ import warnings from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType, GenericAlias - -try: - from _typing import _idfunc -except ImportError: - def _idfunc(_, x): - return x +from _typing import ( + _idfunc, + TypeVar, + ParamSpec, + TypeVarTuple, + ParamSpecArgs, + ParamSpecKwargs, + TypeAliasType, + Generic, +) # Please keep __all__ alphabetized within each category. __all__ = [ @@ -149,6 +154,7 @@ def _idfunc(_, x): 'TYPE_CHECKING', 'TypeAlias', 'TypeGuard', + 'TypeAliasType', 'Unpack', ] @@ -695,6 +701,15 @@ def Union(self, parameters): return _UnionGenericAlias(self, parameters, name="Optional") return _UnionGenericAlias(self, parameters) +def _make_union(left, right): + """Used from the C implementation of TypeVar. + + TypeVar.__or__ calls this instead of returning types.UnionType + because we want to allow unions between TypeVars and strings + (forward references.) + """ + return Union[left, right] + @_SpecialForm def Optional(self, parameters): """Optional type. @@ -926,333 +941,162 @@ def __reduce__(self): return self.__name__ -class _BoundVarianceMixin: - """Mixin giving __init__ bound and variance arguments. - - This is used by TypeVar and ParamSpec, which both employ the notions of - a type 'bound' (restricting type arguments to be a subtype of some - specified type) and type 'variance' (determining subtype relations between - generic types). - """ - def __init__(self, bound, covariant, contravariant): - """Used to setup TypeVars and ParamSpec's bound, covariant and - contravariant attributes. - """ - if covariant and contravariant: - raise ValueError("Bivariant types are not supported.") - self.__covariant__ = bool(covariant) - self.__contravariant__ = bool(contravariant) - if bound: - self.__bound__ = _type_check(bound, "Bound must be a type.") - else: - self.__bound__ = None - - def __or__(self, right): - return Union[self, right] - - def __ror__(self, left): - return Union[left, self] - - def __repr__(self): - if self.__covariant__: - prefix = '+' - elif self.__contravariant__: - prefix = '-' - else: - prefix = '~' - return prefix + self.__name__ - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class TypeVar(_Final, _Immutable, _BoundVarianceMixin, _PickleUsingNameMixin, - _root=True): - """Type variable. - - Usage:: - - T = TypeVar('T') # Can be anything - A = TypeVar('A', str, bytes) # Must be str or bytes - - Type variables exist primarily for the benefit of static type - checkers. They serve as the parameters for generic types as well - as for generic function definitions. See class Generic for more - information on generic types. Generic functions work as follows: - - def repeat(x: T, n: int) -> List[T]: - '''Return a list containing n references to x.''' - return [x]*n - - def longest(x: A, y: A) -> A: - '''Return the longest of two strings.''' - return x if len(x) >= len(y) else y - - The latter example's signature is essentially the overloading - of (str, str) -> str and (bytes, bytes) -> bytes. Also note - that if the arguments are instances of some subclass of str, - the return type is still plain str. - - At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError. - - Type variables defined with covariant=True or contravariant=True - can be used to declare covariant or contravariant generic types. - See PEP 484 for more details. By default generic types are invariant - in all type variables. - - Type variables can be introspected. e.g.: - - T.__name__ == 'T' - T.__constraints__ == () - T.__covariant__ == False - T.__contravariant__ = False - A.__constraints__ == (str, bytes) - - Note that only type variables defined in global scope can be pickled. - """ - - def __init__(self, name, *constraints, bound=None, - covariant=False, contravariant=False): - self.__name__ = name - super().__init__(bound, covariant, contravariant) - if constraints and bound is not None: - raise TypeError("Constraints cannot be combined with bound=...") - if constraints and len(constraints) == 1: - raise TypeError("A single constraint is not allowed") - msg = "TypeVar(name, constraint, ...): constraints must be types." - self.__constraints__ = tuple(_type_check(t, msg) for t in constraints) - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod +def _typevar_subst(self, arg): + msg = "Parameters to generic types must be types." + arg = _type_check(arg, msg, is_argument=True) + if ((isinstance(arg, _GenericAlias) and arg.__origin__ is Unpack) or + (isinstance(arg, GenericAlias) and getattr(arg, '__unpacked__', False))): + raise TypeError(f"{arg} is not valid as type argument") + return arg - def __typing_subst__(self, arg): - msg = "Parameters to generic types must be types." - arg = _type_check(arg, msg, is_argument=True) - if ((isinstance(arg, _GenericAlias) and arg.__origin__ is Unpack) or - (isinstance(arg, GenericAlias) and getattr(arg, '__unpacked__', False))): - raise TypeError(f"{arg} is not valid as type argument") - return arg +def _typevartuple_prepare_subst(self, alias, args): + params = alias.__parameters__ + typevartuple_index = params.index(self) + for param in params[typevartuple_index + 1:]: + if isinstance(param, TypeVarTuple): + raise TypeError(f"More than one TypeVarTuple parameter in {alias}") + + alen = len(args) + plen = len(params) + left = typevartuple_index + right = plen - typevartuple_index - 1 + var_tuple_index = None + fillarg = None + for k, arg in enumerate(args): + if not isinstance(arg, type): + subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) + if subargs and len(subargs) == 2 and subargs[-1] is ...: + if var_tuple_index is not None: + raise TypeError("More than one unpacked arbitrary-length tuple argument") + var_tuple_index = k + fillarg = subargs[0] + if var_tuple_index is not None: + left = min(left, var_tuple_index) + right = min(right, alen - var_tuple_index - 1) + elif left + right > alen: + raise TypeError(f"Too few arguments for {alias};" + f" actual {alen}, expected at least {plen-1}") -class TypeVarTuple(_Final, _Immutable, _PickleUsingNameMixin, _root=True): - """Type variable tuple. + return ( + *args[:left], + *([fillarg]*(typevartuple_index - left)), + tuple(args[left: alen - right]), + *([fillarg]*(plen - right - left - typevartuple_index - 1)), + *args[alen - right:], + ) - Usage: - Ts = TypeVarTuple('Ts') # Can be given any name +def _paramspec_subst(self, arg): + if isinstance(arg, (list, tuple)): + arg = tuple(_type_check(a, "Expected a type.") for a in arg) + elif not _is_param_expr(arg): + raise TypeError(f"Expected a list of types, an ellipsis, " + f"ParamSpec, or Concatenate. Got {arg}") + return arg - Just as a TypeVar (type variable) is a placeholder for a single type, - a TypeVarTuple is a placeholder for an *arbitrary* number of types. For - example, if we define a generic class using a TypeVarTuple: - class C(Generic[*Ts]): ... +def _paramspec_prepare_subst(self, alias, args): + params = alias.__parameters__ + i = params.index(self) + if i >= len(args): + raise TypeError(f"Too few arguments for {alias}") + # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. + if len(params) == 1 and not _is_param_expr(args[0]): + assert i == 0 + args = (args,) + # Convert lists to tuples to help other libraries cache the results. + elif isinstance(args[i], list): + args = (*args[:i], tuple(args[i]), *args[i+1:]) + return args - Then we can parameterize that class with an arbitrary number of type - arguments: - C[int] # Fine - C[int, str] # Also fine - C[()] # Even this is fine + at _tp_cache +def _generic_class_getitem(cls, params): + """Parameterizes a generic class. - For more details, see PEP 646. + At least, parameterizing a generic class is the *main* thing this method + does. For example, for some generic class `Foo`, this is called when we + do `Foo[int]` - there, with `cls=Foo` and `params=int`. - Note that only TypeVarTuples defined in global scope can be pickled. + However, note that this method is also called when defining generic + classes in the first place with `class Foo(Generic[T]): ...`. """ + if not isinstance(params, tuple): + params = (params,) - def __init__(self, name): - self.__name__ = name - - # Used for pickling. - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod - - def __iter__(self): - yield Unpack[self] - - def __repr__(self): - return self.__name__ + params = tuple(_type_convert(p) for p in params) + is_generic_or_protocol = cls in (Generic, Protocol) - def __typing_subst__(self, arg): - raise TypeError("Substitution of bare TypeVarTuple is not supported") + if is_generic_or_protocol: + # Generic and Protocol can only be subscripted with unique type variables. + if not params: + raise TypeError( + f"Parameter list to {cls.__qualname__}[...] cannot be empty" + ) + if not all(_is_typevar_like(p) for p in params): + raise TypeError( + f"Parameters to {cls.__name__}[...] must all be type variables " + f"or parameter specification variables.") + if len(set(params)) != len(params): + raise TypeError( + f"Parameters to {cls.__name__}[...] must all be unique") + else: + # Subscripting a regular Generic subclass. + for param in cls.__parameters__: + prepare = getattr(param, '__typing_prepare_subst__', None) + if prepare is not None: + params = prepare(cls, params) + _check_generic(cls, params, len(cls.__parameters__)) - def __typing_prepare_subst__(self, alias, args): - params = alias.__parameters__ - typevartuple_index = params.index(self) - for param in params[typevartuple_index + 1:]: + new_args = [] + for param, new_arg in zip(cls.__parameters__, params): if isinstance(param, TypeVarTuple): - raise TypeError(f"More than one TypeVarTuple parameter in {alias}") - - alen = len(args) - plen = len(params) - left = typevartuple_index - right = plen - typevartuple_index - 1 - var_tuple_index = None - fillarg = None - for k, arg in enumerate(args): - if not isinstance(arg, type): - subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) - if subargs and len(subargs) == 2 and subargs[-1] is ...: - if var_tuple_index is not None: - raise TypeError("More than one unpacked arbitrary-length tuple argument") - var_tuple_index = k - fillarg = subargs[0] - if var_tuple_index is not None: - left = min(left, var_tuple_index) - right = min(right, alen - var_tuple_index - 1) - elif left + right > alen: - raise TypeError(f"Too few arguments for {alias};" - f" actual {alen}, expected at least {plen-1}") - - return ( - *args[:left], - *([fillarg]*(typevartuple_index - left)), - tuple(args[left: alen - right]), - *([fillarg]*(plen - right - left - typevartuple_index - 1)), - *args[alen - right:], - ) - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class ParamSpecArgs(_Final, _Immutable, _root=True): - """The args for a ParamSpec object. - - Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. - - ParamSpecArgs objects have a reference back to their ParamSpec: - - P.args.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.args" - - def __eq__(self, other): - if not isinstance(other, ParamSpecArgs): - return NotImplemented - return self.__origin__ == other.__origin__ - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class ParamSpecKwargs(_Final, _Immutable, _root=True): - """The kwargs for a ParamSpec object. - - Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. - - ParamSpecKwargs objects have a reference back to their ParamSpec: - - P.kwargs.__origin__ is P - - This type is meant for runtime introspection and has no special meaning to - static type checkers. - """ - def __init__(self, origin): - self.__origin__ = origin - - def __repr__(self): - return f"{self.__origin__.__name__}.kwargs" - - def __eq__(self, other): - if not isinstance(other, ParamSpecKwargs): - return NotImplemented - return self.__origin__ == other.__origin__ - - def __mro_entries__(self, bases): - raise TypeError(f"Cannot subclass an instance of {type(self).__name__}") - - -class ParamSpec(_Final, _Immutable, _BoundVarianceMixin, _PickleUsingNameMixin, - _root=True): - """Parameter specification variable. - - Usage:: - - P = ParamSpec('P') - - Parameter specification variables exist primarily for the benefit of static - type checkers. They are used to forward the parameter types of one - callable to another callable, a pattern commonly found in higher order - functions and decorators. They are only valid when used in ``Concatenate``, - or as the first argument to ``Callable``, or as parameters for user-defined - Generics. See class Generic for more information on generic types. An - example for annotating a decorator:: - - T = TypeVar('T') - P = ParamSpec('P') - - def add_logging(f: Callable[P, T]) -> Callable[P, T]: - '''A type-safe decorator to add logging to a function.''' - def inner(*args: P.args, **kwargs: P.kwargs) -> T: - logging.info(f'{f.__name__} was called') - return f(*args, **kwargs) - return inner - - @add_logging - def add_two(x: float, y: float) -> float: - '''Add two numbers together.''' - return x + y - - Parameter specification variables defined with covariant=True or - contravariant=True can be used to declare covariant or contravariant - generic types. These keyword arguments are valid, but their actual semantics - are yet to be decided. See PEP 612 for details. - - Parameter specification variables can be introspected. e.g.: - - P.__name__ == 'P' - P.__bound__ == None - P.__covariant__ == False - P.__contravariant__ == False - - Note that only parameter specification variables defined in global scope can - be pickled. - """ + new_args.extend(new_arg) + else: + new_args.append(new_arg) + params = tuple(new_args) - @property - def args(self): - return ParamSpecArgs(self) + return _GenericAlias(cls, params) - @property - def kwargs(self): - return ParamSpecKwargs(self) - - def __init__(self, name, *, bound=None, covariant=False, contravariant=False): - self.__name__ = name - super().__init__(bound, covariant, contravariant) - def_mod = _caller() - if def_mod != 'typing': - self.__module__ = def_mod - def __typing_subst__(self, arg): - if isinstance(arg, (list, tuple)): - arg = tuple(_type_check(a, "Expected a type.") for a in arg) - elif not _is_param_expr(arg): - raise TypeError(f"Expected a list of types, an ellipsis, " - f"ParamSpec, or Concatenate. Got {arg}") - return arg +def _generic_init_subclass(cls, *args, **kwargs): + super(Generic, cls).__init_subclass__(*args, **kwargs) + tvars = [] + if '__orig_bases__' in cls.__dict__: + error = Generic in cls.__orig_bases__ + else: + error = (Generic in cls.__bases__ and + cls.__name__ != 'Protocol' and + type(cls) != _TypedDictMeta) + if error: + raise TypeError("Cannot inherit from plain Generic") + if '__orig_bases__' in cls.__dict__: + tvars = _collect_parameters(cls.__orig_bases__) + # Look for Generic[T1, ..., Tn]. + # If found, tvars must be a subset of it. + # If not found, tvars is it. + # Also check for and reject plain Generic, + # and reject multiple Generic[...]. + gvars = None + for base in cls.__orig_bases__: + if (isinstance(base, _GenericAlias) and + base.__origin__ is Generic): + if gvars is not None: + raise TypeError( + "Cannot inherit from Generic[...] multiple times.") + gvars = base.__parameters__ + if gvars is not None: + tvarset = set(tvars) + gvarset = set(gvars) + if not tvarset <= gvarset: + s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) + s_args = ', '.join(str(g) for g in gvars) + raise TypeError(f"Some type variables ({s_vars}) are" + f" not listed in Generic[{s_args}]") + tvars = gvars + cls.__parameters__ = tuple(tvars) - def __typing_prepare_subst__(self, alias, args): - params = alias.__parameters__ - i = params.index(self) - if i >= len(args): - raise TypeError(f"Too few arguments for {alias}") - # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. - if len(params) == 1 and not _is_param_expr(args[0]): - assert i == 0 - args = (args,) - # Convert lists to tuples to help other libraries cache the results. - elif isinstance(args[i], list): - args = (*args[:i], tuple(args[i]), *args[i+1:]) - return args def _is_dunder(attr): return attr.startswith('__') and attr.endswith('__') @@ -1812,113 +1656,6 @@ def __typing_is_unpacked_typevartuple__(self): return isinstance(self.__args__[0], TypeVarTuple) -class Generic: - """Abstract base class for generic types. - - A generic type is typically declared by inheriting from - this class parameterized with one or more type variables. - For example, a generic mapping type might be defined as:: - - class Mapping(Generic[KT, VT]): - def __getitem__(self, key: KT) -> VT: - ... - # Etc. - - This class can then be used as follows:: - - def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: - try: - return mapping[key] - except KeyError: - return default - """ - __slots__ = () - _is_protocol = False - - @_tp_cache - def __class_getitem__(cls, params): - """Parameterizes a generic class. - - At least, parameterizing a generic class is the *main* thing this method - does. For example, for some generic class `Foo`, this is called when we - do `Foo[int]` - there, with `cls=Foo` and `params=int`. - - However, note that this method is also called when defining generic - classes in the first place with `class Foo(Generic[T]): ...`. - """ - if not isinstance(params, tuple): - params = (params,) - - params = tuple(_type_convert(p) for p in params) - if cls in (Generic, Protocol): - # Generic and Protocol can only be subscripted with unique type variables. - if not params: - raise TypeError( - f"Parameter list to {cls.__qualname__}[...] cannot be empty" - ) - if not all(_is_typevar_like(p) for p in params): - raise TypeError( - f"Parameters to {cls.__name__}[...] must all be type variables " - f"or parameter specification variables.") - if len(set(params)) != len(params): - raise TypeError( - f"Parameters to {cls.__name__}[...] must all be unique") - else: - # Subscripting a regular Generic subclass. - for param in cls.__parameters__: - prepare = getattr(param, '__typing_prepare_subst__', None) - if prepare is not None: - params = prepare(cls, params) - _check_generic(cls, params, len(cls.__parameters__)) - - new_args = [] - for param, new_arg in zip(cls.__parameters__, params): - if isinstance(param, TypeVarTuple): - new_args.extend(new_arg) - else: - new_args.append(new_arg) - params = tuple(new_args) - - return _GenericAlias(cls, params) - - def __init_subclass__(cls, *args, **kwargs): - super().__init_subclass__(*args, **kwargs) - tvars = [] - if '__orig_bases__' in cls.__dict__: - error = Generic in cls.__orig_bases__ - else: - error = (Generic in cls.__bases__ and - cls.__name__ != 'Protocol' and - type(cls) != _TypedDictMeta) - if error: - raise TypeError("Cannot inherit from plain Generic") - if '__orig_bases__' in cls.__dict__: - tvars = _collect_parameters(cls.__orig_bases__) - # Look for Generic[T1, ..., Tn]. - # If found, tvars must be a subset of it. - # If not found, tvars is it. - # Also check for and reject plain Generic, - # and reject multiple Generic[...]. - gvars = None - for base in cls.__orig_bases__: - if (isinstance(base, _GenericAlias) and - base.__origin__ is Generic): - if gvars is not None: - raise TypeError( - "Cannot inherit from Generic[...] multiple times.") - gvars = base.__parameters__ - if gvars is not None: - tvarset = set(tvars) - gvarset = set(gvars) - if not tvarset <= gvarset: - s_vars = ', '.join(str(t) for t in tvars if t not in gvarset) - s_args = ', '.join(str(g) for g in gvars) - raise TypeError(f"Some type variables ({s_vars}) are" - f" not listed in Generic[{s_args}]") - tvars = gvars - cls.__parameters__ = tuple(tvars) - - class _TypingEllipsis: """Internal placeholder for ... (ellipsis).""" @@ -2024,6 +1761,18 @@ def _lazy_load_getattr_static(): _cleanups.append(_lazy_load_getattr_static.cache_clear) +def _pickle_psargs(psargs): + return ParamSpecArgs, (psargs.__origin__,) + +copyreg.pickle(ParamSpecArgs, _pickle_psargs) + +def _pickle_pskwargs(pskwargs): + return ParamSpecKwargs, (pskwargs.__origin__,) + +copyreg.pickle(ParamSpecKwargs, _pickle_pskwargs) + +del _pickle_psargs, _pickle_pskwargs + class _ProtocolMeta(ABCMeta): # This metaclass is really unfortunate and exists only because of @@ -2943,7 +2692,7 @@ def __new__(cls, typename, bases, ns): module=ns['__module__']) nm_tpl.__bases__ = bases if Generic in bases: - class_getitem = Generic.__class_getitem__.__func__ + class_getitem = _generic_class_getitem nm_tpl.__class_getitem__ = classmethod(class_getitem) # update from user namespace without overriding special namedtuple attributes for key in ns: diff --git a/Makefile.pre.in b/Makefile.pre.in index 7c44b7be5dbe..d66574143267 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -479,6 +479,7 @@ OBJECT_OBJS= \ Objects/structseq.o \ Objects/tupleobject.o \ Objects/typeobject.o \ + Objects/typevarobject.o \ Objects/unicodeobject.o \ Objects/unicodectype.o \ Objects/unionobject.o \ @@ -1767,6 +1768,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_tracemalloc.h \ $(srcdir)/Include/internal/pycore_tuple.h \ $(srcdir)/Include/internal/pycore_typeobject.h \ + $(srcdir)/Include/internal/pycore_typevarobject.h \ $(srcdir)/Include/internal/pycore_ucnhash.h \ $(srcdir)/Include/internal/pycore_unionobject.h \ $(srcdir)/Include/internal/pycore_unicodeobject.h \ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst new file mode 100644 index 000000000000..cefe6429ab20 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst @@ -0,0 +1,23 @@ +Implement :pep:`695`, adding syntactic support for generic classes, generic +functions, and type aliases. + +A new ``type X = ...`` syntax is added for type aliases, which resolves at +runtime to an instance of the new class ``typing.TypeAliasType``. +The value is lazily evaluated and is accessible through the ``.__value__`` +attribute. This is implemented as a new AST node ``ast.TypeAlias``. + +New syntax (``class X[T]: ...``, ``def func[T](): ...``) is added for defining +generic functions and classes. This is implemented as a new +``typeparams`` attribute on the AST nodes for classes and functions. +This node holds instances of the new AST classes ``ast.TypeVar``, +``ast.ParamSpec``, and ``ast.TypeVarTuple``. + +``typing.TypeVar``, ``typing.ParamSpec``, ``typing.ParamSpecArgs``, +``typing.ParamSpecKwargs``, ``typing.TypeVarTuple``, and +``typing.Generic`` are now implemented in C rather than Python. + +There are new bytecode instructions ``LOAD_LOCALS``, +``LOAD_CLASSDICT_OR_GLOBAL``, and ``LOAD_CLASSDICT_OR_DEREF`` +to support correct resolution of names in class namespaces. + +Patch by Eric Traut, Larry Hastings, and Jelle Zijlstra. diff --git a/Modules/Setup.bootstrap.in b/Modules/Setup.bootstrap.in index e3e9b96b0630..8ef0f203a82a 100644 --- a/Modules/Setup.bootstrap.in +++ b/Modules/Setup.bootstrap.in @@ -21,6 +21,7 @@ itertools itertoolsmodule.c _sre _sre/sre.c _thread _threadmodule.c time timemodule.c +_typing _typingmodule.c _weakref _weakref.c # commonly used core modules diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index 95409d48c0da..6db567d71309 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -41,7 +41,6 @@ @MODULE__QUEUE_TRUE at _queue _queuemodule.c @MODULE__RANDOM_TRUE at _random _randommodule.c @MODULE__STRUCT_TRUE at _struct _struct.c - at MODULE__TYPING_TRUE@_typing _typingmodule.c @MODULE__XXSUBINTERPRETERS_TRUE at _xxsubinterpreters _xxsubinterpretersmodule.c @MODULE__XXINTERPCHANNELS_TRUE at _xxinterpchannels _xxinterpchannelsmodule.c @MODULE__ZONEINFO_TRUE at _zoneinfo _zoneinfo.c diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c index 64286375636a..ed2999c0b68b 100644 --- a/Modules/_typingmodule.c +++ b/Modules/_typingmodule.c @@ -1,6 +1,11 @@ /* typing accelerator C extension: _typing module. */ +#ifndef Py_BUILD_CORE +#define Py_BUILD_CORE +#endif + #include "Python.h" +#include "internal/pycore_interp.h" #include "clinic/_typingmodule.c.h" /*[clinic input] @@ -35,7 +40,30 @@ static PyMethodDef typing_methods[] = { PyDoc_STRVAR(typing_doc, "Accelerators for the typing module.\n"); +static int +_typing_exec(PyObject *m) +{ + PyInterpreterState *interp = PyInterpreterState_Get(); + +#define EXPORT_TYPE(name, typename) \ + if (PyModule_AddObjectRef(m, name, \ + (PyObject *)interp->cached_objects.typename) < 0) { \ + return -1; \ + } + + EXPORT_TYPE("TypeVar", typevar_type); + EXPORT_TYPE("TypeVarTuple", typevartuple_type); + EXPORT_TYPE("ParamSpec", paramspec_type); + EXPORT_TYPE("ParamSpecArgs", paramspecargs_type); + EXPORT_TYPE("ParamSpecKwargs", paramspeckwargs_type); + EXPORT_TYPE("TypeAliasType", typealias_type); + EXPORT_TYPE("Generic", generic_type); +#undef EXPORT_TYPE + return 0; +} + static struct PyModuleDef_Slot _typingmodule_slots[] = { + {Py_mod_exec, _typing_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; diff --git a/Objects/clinic/typevarobject.c.h b/Objects/clinic/typevarobject.c.h new file mode 100644 index 000000000000..54189b984468 --- /dev/null +++ b/Objects/clinic/typevarobject.c.h @@ -0,0 +1,786 @@ +/*[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(typevar_new__doc__, +"typevar(name, *constraints, *, bound=None, covariant=False,\n" +" contravariant=False, infer_variance=False)\n" +"--\n" +"\n" +"Create a TypeVar."); + +static PyObject * +typevar_new_impl(PyTypeObject *type, PyObject *name, PyObject *constraints, + PyObject *bound, int covariant, int contravariant, + int infer_variance); + +static PyObject * +typevar_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 5 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), &_Py_ID(bound), &_Py_ID(covariant), &_Py_ID(contravariant), &_Py_ID(infer_variance), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"name", "bound", "covariant", "contravariant", "infer_variance", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "typevar", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[6]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = Py_MIN(nargs, 1) + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; + PyObject *name; + PyObject *constraints = NULL; + PyObject *bound = Py_None; + int covariant = 0; + int contravariant = 0; + int infer_variance = 0; + + fastargs = _PyArg_UnpackKeywordsWithVararg(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, 1, argsbuf); + if (!fastargs) { + goto exit; + } + if (!PyUnicode_Check(fastargs[0])) { + _PyArg_BadArgument("typevar", "argument 'name'", "str", fastargs[0]); + goto exit; + } + name = fastargs[0]; + constraints = fastargs[1]; + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[2]) { + bound = fastargs[2]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[3]) { + covariant = PyObject_IsTrue(fastargs[3]); + if (covariant < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[4]) { + contravariant = PyObject_IsTrue(fastargs[4]); + if (contravariant < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + infer_variance = PyObject_IsTrue(fastargs[5]); + if (infer_variance < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = typevar_new_impl(type, name, constraints, bound, covariant, contravariant, infer_variance); + +exit: + Py_XDECREF(constraints); + return return_value; +} + +PyDoc_STRVAR(typevar_typing_subst__doc__, +"__typing_subst__($self, /, arg)\n" +"--\n" +"\n"); + +#define TYPEVAR_TYPING_SUBST_METHODDEF \ + {"__typing_subst__", _PyCFunction_CAST(typevar_typing_subst), METH_FASTCALL|METH_KEYWORDS, typevar_typing_subst__doc__}, + +static PyObject * +typevar_typing_subst_impl(typevarobject *self, PyObject *arg); + +static PyObject * +typevar_typing_subst(typevarobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(arg), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"arg", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__typing_subst__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *arg; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + arg = args[0]; + return_value = typevar_typing_subst_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(typevar_reduce__doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define TYPEVAR_REDUCE_METHODDEF \ + {"__reduce__", (PyCFunction)typevar_reduce, METH_NOARGS, typevar_reduce__doc__}, + +static PyObject * +typevar_reduce_impl(typevarobject *self); + +static PyObject * +typevar_reduce(typevarobject *self, PyObject *Py_UNUSED(ignored)) +{ + return typevar_reduce_impl(self); +} + +PyDoc_STRVAR(paramspecargs_new__doc__, +"paramspecargs(origin)\n" +"--\n" +"\n" +"Create a ParamSpecArgs object."); + +static PyObject * +paramspecargs_new_impl(PyTypeObject *type, PyObject *origin); + +static PyObject * +paramspecargs_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(origin), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"origin", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "paramspecargs", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *origin; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + origin = fastargs[0]; + return_value = paramspecargs_new_impl(type, origin); + +exit: + return return_value; +} + +PyDoc_STRVAR(paramspeckwargs_new__doc__, +"paramspeckwargs(origin)\n" +"--\n" +"\n" +"Create a ParamSpecKwargs object."); + +static PyObject * +paramspeckwargs_new_impl(PyTypeObject *type, PyObject *origin); + +static PyObject * +paramspeckwargs_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(origin), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"origin", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "paramspeckwargs", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *origin; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + origin = fastargs[0]; + return_value = paramspeckwargs_new_impl(type, origin); + +exit: + return return_value; +} + +PyDoc_STRVAR(paramspec_new__doc__, +"paramspec(name, *, bound=None, covariant=False, contravariant=False,\n" +" infer_variance=False)\n" +"--\n" +"\n" +"Create a ParamSpec object."); + +static PyObject * +paramspec_new_impl(PyTypeObject *type, PyObject *name, PyObject *bound, + int covariant, int contravariant, int infer_variance); + +static PyObject * +paramspec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 5 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), &_Py_ID(bound), &_Py_ID(covariant), &_Py_ID(contravariant), &_Py_ID(infer_variance), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"name", "bound", "covariant", "contravariant", "infer_variance", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "paramspec", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[5]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; + PyObject *name; + PyObject *bound = Py_None; + int covariant = 0; + int contravariant = 0; + int infer_variance = 0; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!PyUnicode_Check(fastargs[0])) { + _PyArg_BadArgument("paramspec", "argument 'name'", "str", fastargs[0]); + goto exit; + } + name = fastargs[0]; + if (!noptargs) { + goto skip_optional_kwonly; + } + if (fastargs[1]) { + bound = fastargs[1]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[2]) { + covariant = PyObject_IsTrue(fastargs[2]); + if (covariant < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (fastargs[3]) { + contravariant = PyObject_IsTrue(fastargs[3]); + if (contravariant < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + infer_variance = PyObject_IsTrue(fastargs[4]); + if (infer_variance < 0) { + goto exit; + } +skip_optional_kwonly: + return_value = paramspec_new_impl(type, name, bound, covariant, contravariant, infer_variance); + +exit: + return return_value; +} + +PyDoc_STRVAR(paramspec_typing_subst__doc__, +"__typing_subst__($self, /, arg)\n" +"--\n" +"\n"); + +#define PARAMSPEC_TYPING_SUBST_METHODDEF \ + {"__typing_subst__", _PyCFunction_CAST(paramspec_typing_subst), METH_FASTCALL|METH_KEYWORDS, paramspec_typing_subst__doc__}, + +static PyObject * +paramspec_typing_subst_impl(paramspecobject *self, PyObject *arg); + +static PyObject * +paramspec_typing_subst(paramspecobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(arg), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"arg", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__typing_subst__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *arg; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + arg = args[0]; + return_value = paramspec_typing_subst_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(paramspec_typing_prepare_subst__doc__, +"__typing_prepare_subst__($self, /, alias, args)\n" +"--\n" +"\n"); + +#define PARAMSPEC_TYPING_PREPARE_SUBST_METHODDEF \ + {"__typing_prepare_subst__", _PyCFunction_CAST(paramspec_typing_prepare_subst), METH_FASTCALL|METH_KEYWORDS, paramspec_typing_prepare_subst__doc__}, + +static PyObject * +paramspec_typing_prepare_subst_impl(paramspecobject *self, PyObject *alias, + PyObject *args); + +static PyObject * +paramspec_typing_prepare_subst(paramspecobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(alias), &_Py_ID(args), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"alias", "args", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__typing_prepare_subst__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject *alias; + PyObject *__clinic_args; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + alias = args[0]; + __clinic_args = args[1]; + return_value = paramspec_typing_prepare_subst_impl(self, alias, __clinic_args); + +exit: + return return_value; +} + +PyDoc_STRVAR(paramspec_reduce__doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define PARAMSPEC_REDUCE_METHODDEF \ + {"__reduce__", (PyCFunction)paramspec_reduce, METH_NOARGS, paramspec_reduce__doc__}, + +static PyObject * +paramspec_reduce_impl(paramspecobject *self); + +static PyObject * +paramspec_reduce(paramspecobject *self, PyObject *Py_UNUSED(ignored)) +{ + return paramspec_reduce_impl(self); +} + +PyDoc_STRVAR(typevartuple__doc__, +"typevartuple(name)\n" +"--\n" +"\n" +"Create a new TypeVarTuple with the given name."); + +static PyObject * +typevartuple_impl(PyTypeObject *type, PyObject *name); + +static PyObject * +typevartuple(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"name", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "typevartuple", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *name; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!PyUnicode_Check(fastargs[0])) { + _PyArg_BadArgument("typevartuple", "argument 'name'", "str", fastargs[0]); + goto exit; + } + name = fastargs[0]; + return_value = typevartuple_impl(type, name); + +exit: + return return_value; +} + +PyDoc_STRVAR(typevartuple_typing_subst__doc__, +"__typing_subst__($self, /, arg)\n" +"--\n" +"\n"); + +#define TYPEVARTUPLE_TYPING_SUBST_METHODDEF \ + {"__typing_subst__", _PyCFunction_CAST(typevartuple_typing_subst), METH_FASTCALL|METH_KEYWORDS, typevartuple_typing_subst__doc__}, + +static PyObject * +typevartuple_typing_subst_impl(typevartupleobject *self, PyObject *arg); + +static PyObject * +typevartuple_typing_subst(typevartupleobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(arg), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"arg", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__typing_subst__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *arg; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + arg = args[0]; + return_value = typevartuple_typing_subst_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(typevartuple_typing_prepare_subst__doc__, +"__typing_prepare_subst__($self, /, alias, args)\n" +"--\n" +"\n"); + +#define TYPEVARTUPLE_TYPING_PREPARE_SUBST_METHODDEF \ + {"__typing_prepare_subst__", _PyCFunction_CAST(typevartuple_typing_prepare_subst), METH_FASTCALL|METH_KEYWORDS, typevartuple_typing_prepare_subst__doc__}, + +static PyObject * +typevartuple_typing_prepare_subst_impl(typevartupleobject *self, + PyObject *alias, PyObject *args); + +static PyObject * +typevartuple_typing_prepare_subst(typevartupleobject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(alias), &_Py_ID(args), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"alias", "args", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__typing_prepare_subst__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + PyObject *alias; + PyObject *__clinic_args; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { + goto exit; + } + alias = args[0]; + __clinic_args = args[1]; + return_value = typevartuple_typing_prepare_subst_impl(self, alias, __clinic_args); + +exit: + return return_value; +} + +PyDoc_STRVAR(typevartuple_reduce__doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define TYPEVARTUPLE_REDUCE_METHODDEF \ + {"__reduce__", (PyCFunction)typevartuple_reduce, METH_NOARGS, typevartuple_reduce__doc__}, + +static PyObject * +typevartuple_reduce_impl(typevartupleobject *self); + +static PyObject * +typevartuple_reduce(typevartupleobject *self, PyObject *Py_UNUSED(ignored)) +{ + return typevartuple_reduce_impl(self); +} + +PyDoc_STRVAR(typealias_reduce__doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define TYPEALIAS_REDUCE_METHODDEF \ + {"__reduce__", (PyCFunction)typealias_reduce, METH_NOARGS, typealias_reduce__doc__}, + +static PyObject * +typealias_reduce_impl(typealiasobject *self); + +static PyObject * +typealias_reduce(typealiasobject *self, PyObject *Py_UNUSED(ignored)) +{ + return typealias_reduce_impl(self); +} + +PyDoc_STRVAR(typealias_new__doc__, +"typealias(name, value, *, type_params=<unrepresentable>)\n" +"--\n" +"\n" +"Create a TypeAliasType."); + +static PyObject * +typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, + PyObject *type_params); + +static PyObject * +typealias_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 3 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), &_Py_ID(value), &_Py_ID(type_params), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"name", "value", "type_params", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "typealias", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; + PyObject *name; + PyObject *value; + PyObject *type_params = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 2, 2, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!PyUnicode_Check(fastargs[0])) { + _PyArg_BadArgument("typealias", "argument 'name'", "str", fastargs[0]); + goto exit; + } + name = fastargs[0]; + value = fastargs[1]; + if (!noptargs) { + goto skip_optional_kwonly; + } + type_params = fastargs[2]; +skip_optional_kwonly: + return_value = typealias_new_impl(type, name, value, type_params); + +exit: + return return_value; +} +/*[clinic end generated code: output=807bcd30ebd10ac3 input=a9049054013a1b77]*/ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 78c1144afca2..69898bf722d6 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -127,6 +127,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr) PyErr_Clear(); } op->func_annotations = NULL; + op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; op->func_version = 0; _PyObject_GC_TRACK(op); @@ -202,6 +203,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname op->func_weakreflist = NULL; op->func_module = module; op->func_annotations = NULL; + op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; op->func_version = 0; _PyObject_GC_TRACK(op); @@ -652,6 +654,28 @@ func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno return 0; } +static PyObject * +func_get_type_params(PyFunctionObject *op, void *Py_UNUSED(ignored)) +{ + if (op->func_typeparams == NULL) { + return PyTuple_New(0); + } + + assert(PyTuple_Check(op->func_typeparams)); + return Py_NewRef(op->func_typeparams); +} + +PyObject * +_Py_set_function_type_params(PyThreadState *Py_UNUSED(ignored), PyObject *func, + PyObject *type_params) +{ + assert(PyFunction_Check(func)); + assert(PyTuple_Check(type_params)); + PyFunctionObject *f = (PyFunctionObject *)func; + Py_XSETREF(f->func_typeparams, Py_NewRef(type_params)); + return Py_NewRef(func); +} + static PyGetSetDef func_getsetlist[] = { {"__code__", (getter)func_get_code, (setter)func_set_code}, {"__defaults__", (getter)func_get_defaults, @@ -663,6 +687,7 @@ static PyGetSetDef func_getsetlist[] = { {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, {"__name__", (getter)func_get_name, (setter)func_set_name}, {"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname}, + {"__type_params__", (getter)func_get_type_params, NULL}, {NULL} /* Sentinel */ }; @@ -783,6 +808,7 @@ func_clear(PyFunctionObject *op) Py_CLEAR(op->func_dict); Py_CLEAR(op->func_closure); Py_CLEAR(op->func_annotations); + Py_CLEAR(op->func_typeparams); // Don't Py_CLEAR(op->func_code), since code is always required // to be non-NULL. Similarly, name and qualname shouldn't be NULL. // However, name and qualname could be str subclasses, so they @@ -837,6 +863,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg) Py_VISIT(f->func_dict); Py_VISIT(f->func_closure); Py_VISIT(f->func_annotations); + Py_VISIT(f->func_typeparams); Py_VISIT(f->func_qualname); return 0; } diff --git a/Objects/object.c b/Objects/object.c index a7c79c673d5f..f3118665430d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -14,6 +14,7 @@ #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntry_Type +#include "pycore_typevarobject.h" // _PyTypeVar_Type etc., _Py_initialize_generic #include "pycore_typeobject.h" // _PyBufferWrapper_Type #include "pycore_unionobject.h" // _PyUnion_Type #include "pycore_interpreteridobject.h" // _PyInterpreterID_Type @@ -2139,6 +2140,11 @@ _PyTypes_InitTypes(PyInterpreterState *interp) } } + // Must be after static types are initialized + if (_Py_initialize_generic(interp) < 0) { + return _PyStatus_ERR("Can't initialize generic types"); + } + return _PyStatus_OK(); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c1525320a7cb..624dc63ce82c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1460,6 +1460,18 @@ type_get_annotations(PyTypeObject *type, void *context) return annotations; } +static PyObject * +type_get_type_params(PyTypeObject *type, void *context) +{ + PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__)); + + if (params) { + return Py_NewRef(params); + } + + return PyTuple_New(0); +} + static int type_set_annotations(PyTypeObject *type, PyObject *value, void *context) { @@ -1536,6 +1548,7 @@ static PyGetSetDef type_getsets[] = { {"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL}, {"__text_signature__", (getter)type_get_text_signature, NULL, NULL}, {"__annotations__", (getter)type_get_annotations, (setter)type_set_annotations, NULL}, + {"__type_params__", (getter)type_get_type_params, NULL, NULL}, {0} }; @@ -3130,11 +3143,12 @@ type_new_copy_slots(type_new_ctx *ctx, PyObject *dict) goto error; } if (r > 0) { - /* CPython inserts __qualname__ and __classcell__ (when needed) + /* CPython inserts these names (when needed) into the namespace when creating a class. They will be deleted below so won't act as class variables. */ if (!_PyUnicode_Equal(slot, &_Py_ID(__qualname__)) && - !_PyUnicode_Equal(slot, &_Py_ID(__classcell__))) + !_PyUnicode_Equal(slot, &_Py_ID(__classcell__)) && + !_PyUnicode_Equal(slot, &_Py_ID(__classdictcell__))) { PyErr_Format(PyExc_ValueError, "%R in __slots__ conflicts with class variable", @@ -3585,6 +3599,32 @@ type_new_set_classcell(PyTypeObject *type) return 0; } +static int +type_new_set_classdictcell(PyTypeObject *type) +{ + PyObject *dict = lookup_tp_dict(type); + PyObject *cell = PyDict_GetItemWithError(dict, &_Py_ID(__classdictcell__)); + if (cell == NULL) { + if (PyErr_Occurred()) { + return -1; + } + return 0; + } + + /* At least one method requires a reference to the dict of its defining class */ + if (!PyCell_Check(cell)) { + PyErr_Format(PyExc_TypeError, + "__classdictcell__ must be a nonlocal cell, not %.200R", + Py_TYPE(cell)); + return -1; + } + + (void)PyCell_Set(cell, (PyObject *)dict); + if (PyDict_DelItem(dict, &_Py_ID(__classdictcell__)) < 0) { + return -1; + } + return 0; +} static int type_new_set_attrs(const type_new_ctx *ctx, PyTypeObject *type) @@ -3629,6 +3669,9 @@ type_new_set_attrs(const type_new_ctx *ctx, PyTypeObject *type) if (type_new_set_classcell(type) < 0) { return -1; } + if (type_new_set_classdictcell(type) < 0) { + return -1; + } return 0; } diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c new file mode 100644 index 000000000000..b0578756f7df --- /dev/null +++ b/Objects/typevarobject.c @@ -0,0 +1,1620 @@ +// TypeVar, TypeVarTuple, and ParamSpec +#include "Python.h" +#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK +#include "pycore_typevarobject.h" +#include "pycore_unionobject.h" // _Py_union_type_or +#include "structmember.h" + +/*[clinic input] +class typevar "typevarobject *" "&_PyTypeVar_Type" +class paramspec "paramspecobject *" "&_PyParamSpec_Type" +class paramspecargs "paramspecattrobject *" "&_PyParamSpecArgs_Type" +class paramspeckwargs "paramspecattrobject *" "&_PyParamSpecKwargs_Type" +class typevartuple "typevartupleobject *" "&_PyTypeVarTuple_Type" +class typealias "typealiasobject *" "&_PyTypeAlias_Type" +class Generic "PyObject *" "&PyGeneric_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=aa86741931a0f55c]*/ + +typedef struct { + PyObject_HEAD + PyObject *name; + PyObject *bound; + PyObject *evaluate_bound; + PyObject *constraints; + PyObject *evaluate_constraints; + bool covariant; + bool contravariant; + bool infer_variance; +} typevarobject; + +typedef struct { + PyObject_HEAD + PyObject *name; +} typevartupleobject; + +typedef struct { + PyObject_HEAD + PyObject *name; + PyObject *bound; + bool covariant; + bool contravariant; + bool infer_variance; +} paramspecobject; + +typedef struct { + PyObject_HEAD + PyObject *name; + PyObject *type_params; + PyObject *compute_value; + PyObject *value; +} typealiasobject; + +#include "clinic/typevarobject.c.h" + +static PyObject * +call_typing_func_object(const char *name, PyObject **args, size_t nargs) +{ + PyObject *typing = PyImport_ImportModule("typing"); + if (typing == NULL) { + return NULL; + } + PyObject *func = PyObject_GetAttrString(typing, name); + if (func == NULL) { + Py_DECREF(typing); + return NULL; + } + PyObject *result = PyObject_Vectorcall(func, args, nargs, NULL); + Py_DECREF(func); + Py_DECREF(typing); + return result; +} + +static PyObject * +type_check(PyObject *arg, const char *msg) +{ + // Calling typing.py here leads to bootstrapping problems + if (Py_IsNone(arg)) { + return Py_NewRef(Py_TYPE(arg)); + } + PyObject *message_str = PyUnicode_FromString(msg); + if (message_str == NULL) { + return NULL; + } + PyObject *args[2] = {arg, message_str}; + PyObject *result = call_typing_func_object("_type_check", args, 2); + Py_DECREF(message_str); + return result; +} + +/* + * Return a typing.Union. This is used as the nb_or (|) operator for + * TypeVar and ParamSpec. We use this rather than _Py_union_type_or + * (which would produce a types.Union) because historically TypeVar + * supported unions with string forward references, and we want to + * preserve that behavior. _Py_union_type_or only allows a small set + * of types. + */ +static PyObject * +make_union(PyObject *self, PyObject *other) +{ + PyObject *args[2] = {self, other}; + PyObject *result = call_typing_func_object("_make_union", args, 2); + return result; +} + +static PyObject * +caller(void) +{ + _PyInterpreterFrame *f = _PyThreadState_GET()->cframe->current_frame; + if (f == NULL) { + Py_RETURN_NONE; + } + if (f == NULL || f->f_funcobj == NULL) { + Py_RETURN_NONE; + } + PyObject *r = PyFunction_GetModule(f->f_funcobj); + if (!r) { + PyErr_Clear(); + Py_RETURN_NONE; + } + return Py_NewRef(r); +} + +static PyObject * +typevartuple_unpack(PyObject *tvt) +{ + PyObject *typing = PyImport_ImportModule("typing"); + if (typing == NULL) { + return NULL; + } + PyObject *unpack = PyObject_GetAttrString(typing, "Unpack"); + if (unpack == NULL) { + Py_DECREF(typing); + return NULL; + } + PyObject *unpacked = PyObject_GetItem(unpack, tvt); + Py_DECREF(typing); + Py_DECREF(unpack); + return unpacked; +} + +static int +contains_typevartuple(PyTupleObject *params) +{ + Py_ssize_t n = PyTuple_GET_SIZE(params); + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevartuple_type; + for (Py_ssize_t i = 0; i < n; i++) { + PyObject *param = PyTuple_GET_ITEM(params, i); + if (Py_IS_TYPE(param, tp)) { + return 1; + } + } + return 0; +} + +static PyObject * +unpack_typevartuples(PyObject *params) +{ + assert(PyTuple_Check(params)); + // TypeVarTuple must be unpacked when passed to Generic, so we do that here. + if (contains_typevartuple((PyTupleObject *)params)) { + Py_ssize_t n = PyTuple_GET_SIZE(params); + PyObject *new_params = PyTuple_New(n); + if (new_params == NULL) { + return NULL; + } + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevartuple_type; + for (Py_ssize_t i = 0; i < n; i++) { + PyObject *param = PyTuple_GET_ITEM(params, i); + if (Py_IS_TYPE(param, tp)) { + PyObject *unpacked = typevartuple_unpack(param); + if (unpacked == NULL) { + Py_DECREF(new_params); + return NULL; + } + PyTuple_SET_ITEM(new_params, i, unpacked); + } + else { + PyTuple_SET_ITEM(new_params, i, Py_NewRef(param)); + } + } + return new_params; + } + else { + return Py_NewRef(params); + } +} + +static void +typevar_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + typevarobject *tv = (typevarobject *)self; + + _PyObject_GC_UNTRACK(self); + + Py_DECREF(tv->name); + Py_XDECREF(tv->bound); + Py_XDECREF(tv->evaluate_bound); + Py_XDECREF(tv->constraints); + Py_XDECREF(tv->evaluate_constraints); + _PyObject_ClearManagedDict(self); + + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); +} + +static int +typevar_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + typevarobject *tv = (typevarobject *)self; + Py_VISIT(tv->bound); + Py_VISIT(tv->evaluate_bound); + Py_VISIT(tv->constraints); + Py_VISIT(tv->evaluate_constraints); + _PyObject_VisitManagedDict(self, visit, arg); + return 0; +} + +static int +typevar_clear(typevarobject *self) +{ + Py_CLEAR(self->bound); + Py_CLEAR(self->evaluate_bound); + Py_CLEAR(self->constraints); + Py_CLEAR(self->evaluate_constraints); + _PyObject_ClearManagedDict((PyObject *)self); + return 0; +} + +static PyObject * +typevar_repr(PyObject *self) +{ + typevarobject *tv = (typevarobject *)self; + + if (tv->infer_variance) { + return Py_NewRef(tv->name); + } + + char variance = tv->covariant ? '+' : tv->contravariant ? '-' : '~'; + return PyUnicode_FromFormat("%c%U", variance, tv->name); +} + +static PyMemberDef typevar_members[] = { + {"__name__", T_OBJECT, offsetof(typevarobject, name), READONLY}, + {"__covariant__", T_BOOL, offsetof(typevarobject, covariant), READONLY}, + {"__contravariant__", T_BOOL, offsetof(typevarobject, contravariant), READONLY}, + {"__infer_variance__", T_BOOL, offsetof(typevarobject, infer_variance), READONLY}, + {0} +}; + +static PyObject * +typevar_bound(typevarobject *self, void *Py_UNUSED(ignored)) +{ + if (self->bound != NULL) { + return Py_NewRef(self->bound); + } + if (self->evaluate_bound == NULL) { + Py_RETURN_NONE; + } + PyObject *bound = PyObject_CallNoArgs(self->evaluate_bound); + self->bound = Py_XNewRef(bound); + return bound; +} + +static PyObject * +typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored)) +{ + if (self->constraints != NULL) { + return Py_NewRef(self->constraints); + } + if (self->evaluate_constraints == NULL) { + Py_RETURN_NONE; + } + PyObject *constraints = PyObject_CallNoArgs(self->evaluate_constraints); + self->constraints = Py_XNewRef(constraints); + return constraints; +} + +static PyGetSetDef typevar_getset[] = { + {"__bound__", (getter)typevar_bound, NULL, NULL, NULL}, + {"__constraints__", (getter)typevar_constraints, NULL, NULL, NULL}, + {0} +}; + +static typevarobject * +typevar_alloc(PyObject *name, PyObject *bound, PyObject *evaluate_bound, + PyObject *constraints, PyObject *evaluate_constraints, + bool covariant, bool contravariant, bool infer_variance, + PyObject *module) +{ + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevar_type; + assert(tp != NULL); + typevarobject *tv = PyObject_GC_New(typevarobject, tp); + if (tv == NULL) { + return NULL; + } + + tv->name = Py_NewRef(name); + + tv->bound = Py_XNewRef(bound); + tv->evaluate_bound = Py_XNewRef(evaluate_bound); + tv->constraints = Py_XNewRef(constraints); + tv->evaluate_constraints = Py_XNewRef(evaluate_constraints); + + tv->covariant = covariant; + tv->contravariant = contravariant; + tv->infer_variance = infer_variance; + _PyObject_GC_TRACK(tv); + + if (module != NULL) { + if (PyObject_SetAttrString((PyObject *)tv, "__module__", module) < 0) { + Py_DECREF(tv); + return NULL; + } + } + + return tv; +} + +/*[clinic input] + at classmethod +typevar.__new__ as typevar_new + + name: object(subclass_of="&PyUnicode_Type") + *constraints: object + * + bound: object = None + covariant: bool = False + contravariant: bool = False + infer_variance: bool = False + +Create a TypeVar. +[clinic start generated code]*/ + +static PyObject * +typevar_new_impl(PyTypeObject *type, PyObject *name, PyObject *constraints, + PyObject *bound, int covariant, int contravariant, + int infer_variance) +/*[clinic end generated code: output=1d200450ee99226d input=2c07ab87c94f462b]*/ +{ + if (covariant && contravariant) { + PyErr_SetString(PyExc_ValueError, + "Bivariant types are not supported."); + return NULL; + } + + if (infer_variance && (covariant || contravariant)) { + PyErr_SetString(PyExc_ValueError, + "Variance cannot be specified with infer_variance."); + return NULL; + } + + if (Py_IsNone(bound)) { + bound = NULL; + } + if (bound != NULL) { + bound = type_check(bound, "Bound must be a type."); + if (bound == NULL) { + return NULL; + } + } + + if (!PyTuple_CheckExact(constraints)) { + PyErr_SetString(PyExc_TypeError, + "constraints must be a tuple"); + return NULL; + } + Py_ssize_t n_constraints = PyTuple_GET_SIZE(constraints); + if (n_constraints == 1) { + PyErr_SetString(PyExc_TypeError, + "A single constraint is not allowed"); + Py_XDECREF(bound); + return NULL; + } else if (n_constraints == 0) { + constraints = NULL; + } else if (bound != NULL) { + PyErr_SetString(PyExc_TypeError, + "Constraints cannot be combined with bound=..."); + Py_XDECREF(bound); + return NULL; + } + PyObject *module = caller(); + if (module == NULL) { + Py_XDECREF(bound); + return NULL; + } + + PyObject *tv = (PyObject *)typevar_alloc(name, bound, NULL, + constraints, NULL, + covariant, contravariant, + infer_variance, module); + Py_XDECREF(bound); + Py_XDECREF(module); + return tv; +} + +/*[clinic input] +typevar.__typing_subst__ as typevar_typing_subst + + arg: object + +[clinic start generated code]*/ + +static PyObject * +typevar_typing_subst_impl(typevarobject *self, PyObject *arg) +/*[clinic end generated code: output=c76ced134ed8f4e1 input=6b70a4bb2da838de]*/ +{ + PyObject *args[2] = {(PyObject *)self, arg}; + PyObject *result = call_typing_func_object("_typevar_subst", args, 2); + return result; +} + +/*[clinic input] +typevar.__reduce__ as typevar_reduce + +[clinic start generated code]*/ + +static PyObject * +typevar_reduce_impl(typevarobject *self) +/*[clinic end generated code: output=02e5c55d7cf8a08f input=de76bc95f04fb9ff]*/ +{ + return Py_NewRef(self->name); +} + +static PyObject * +typevar_mro_entries(PyObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "Cannot subclass an instance of TypeVar"); + return NULL; +} + +static PyMethodDef typevar_methods[] = { + TYPEVAR_TYPING_SUBST_METHODDEF + TYPEVAR_REDUCE_METHODDEF + {"__mro_entries__", typevar_mro_entries, METH_O}, + {0} +}; + +PyDoc_STRVAR(typevar_doc, +"Type variable.\n\ +\n\ +Usage::\n\ +\n\ + T = TypeVar('T') # Can be anything\n\ + A = TypeVar('A', str, bytes) # Must be str or bytes\n\ +\n\ +Type variables exist primarily for the benefit of static type\n\ +checkers. They serve as the parameters for generic types as well\n\ +as for generic function definitions. See class Generic for more\n\ +information on generic types. Generic functions work as follows:\n\ +\n\ + def repeat(x: T, n: int) -> List[T]:\n\ + '''Return a list containing n references to x.'''\n\ + return [x]*n\n\ +\n\ + def longest(x: A, y: A) -> A:\n\ + '''Return the longest of two strings.'''\n\ + return x if len(x) >= len(y) else y\n\ +\n\ +The latter example's signature is essentially the overloading\n\ +of (str, str) -> str and (bytes, bytes) -> bytes. Also note\n\ +that if the arguments are instances of some subclass of str,\n\ +the return type is still plain str.\n\ +\n\ +At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.\n\ +\n\ +Type variables defined with covariant=True or contravariant=True\n\ +can be used to declare covariant or contravariant generic types.\n\ +See PEP 484 for more details. By default generic types are invariant\n\ +in all type variables.\n\ +\n\ +Type variables can be introspected. e.g.:\n\ +\n\ + T.__name__ == 'T'\n\ + T.__constraints__ == ()\n\ + T.__covariant__ == False\n\ + T.__contravariant__ = False\n\ + A.__constraints__ == (str, bytes)\n\ +\n\ +Note that only type variables defined in global scope can be pickled.\n\ +"); + +static PyType_Slot typevar_slots[] = { + {Py_tp_doc, (void *)typevar_doc}, + {Py_tp_methods, typevar_methods}, + {Py_nb_or, make_union}, + {Py_tp_new, typevar_new}, + {Py_tp_dealloc, typevar_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, typevar_traverse}, + {Py_tp_clear, typevar_clear}, + {Py_tp_repr, typevar_repr}, + {Py_tp_members, typevar_members}, + {Py_tp_getset, typevar_getset}, + {0, NULL}, +}; + +PyType_Spec typevar_spec = { + .name = "typing.TypeVar", + .basicsize = sizeof(typevarobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_DICT, + .slots = typevar_slots, +}; + +typedef struct { + PyObject_HEAD + PyObject *__origin__; +} paramspecattrobject; + +static void +paramspecattr_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + paramspecattrobject *psa = (paramspecattrobject *)self; + + _PyObject_GC_UNTRACK(self); + + Py_XDECREF(psa->__origin__); + + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); +} + +static int +paramspecattr_traverse(PyObject *self, visitproc visit, void *arg) +{ + paramspecattrobject *psa = (paramspecattrobject *)self; + Py_VISIT(psa->__origin__); + return 0; +} + +static int +paramspecattr_clear(paramspecattrobject *self) +{ + Py_CLEAR(self->__origin__); + return 0; +} + +static PyObject * +paramspecattr_richcompare(PyObject *a, PyObject *b, int op) +{ + if (!Py_IS_TYPE(a, Py_TYPE(b))) { + Py_RETURN_NOTIMPLEMENTED; + } + if (op != Py_EQ && op != Py_NE) { + Py_RETURN_NOTIMPLEMENTED; + } + return PyObject_RichCompare( + ((paramspecattrobject *)a)->__origin__, + ((paramspecattrobject *)b)->__origin__, + op + ); +} + +static PyMemberDef paramspecattr_members[] = { + {"__origin__", T_OBJECT, offsetof(paramspecattrobject, __origin__), READONLY}, + {0} +}; + +static paramspecattrobject * +paramspecattr_new(PyTypeObject *tp, PyObject *origin) +{ + paramspecattrobject *psa = PyObject_GC_New(paramspecattrobject, tp); + if (psa == NULL) { + return NULL; + } + psa->__origin__ = Py_NewRef(origin); + _PyObject_GC_TRACK(psa); + return psa; +} + +static PyObject * +paramspecargs_repr(PyObject *self) +{ + paramspecattrobject *psa = (paramspecattrobject *)self; + + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspec_type; + if (Py_IS_TYPE(psa->__origin__, tp)) { + return PyUnicode_FromFormat("%U.args", + ((paramspecobject *)psa->__origin__)->name); + } + return PyUnicode_FromFormat("%R.args", psa->__origin__); +} + + +/*[clinic input] + at classmethod +paramspecargs.__new__ as paramspecargs_new + + origin: object + +Create a ParamSpecArgs object. +[clinic start generated code]*/ + +static PyObject * +paramspecargs_new_impl(PyTypeObject *type, PyObject *origin) +/*[clinic end generated code: output=9a1463dc8942fe4e input=3596a0bb6183c208]*/ +{ + return (PyObject *)paramspecattr_new(type, origin); +} + +static PyObject * +paramspecargs_mro_entries(PyObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "Cannot subclass an instance of ParamSpecArgs"); + return NULL; +} + +static PyMethodDef paramspecargs_methods[] = { + {"__mro_entries__", paramspecargs_mro_entries, METH_O}, + {0} +}; + +PyDoc_STRVAR(paramspecargs_doc, +"The args for a ParamSpec object.\n\ +\n\ +Given a ParamSpec object P, P.args is an instance of ParamSpecArgs.\n\ +\n\ +ParamSpecArgs objects have a reference back to their ParamSpec:\n\ +\n\ + P.args.__origin__ is P\n\ +\n\ +This type is meant for runtime introspection and has no special meaning to\n\ +static type checkers.\n\ +"); + +static PyType_Slot paramspecargs_slots[] = { + {Py_tp_doc, (void *)paramspecargs_doc}, + {Py_tp_methods, paramspecargs_methods}, + {Py_tp_new, paramspecargs_new}, + {Py_tp_dealloc, paramspecattr_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, paramspecattr_traverse}, + {Py_tp_clear, (inquiry)paramspecattr_clear}, + {Py_tp_repr, paramspecargs_repr}, + {Py_tp_members, paramspecattr_members}, + {Py_tp_richcompare, paramspecattr_richcompare}, + {0, NULL}, +}; + +PyType_Spec paramspecargs_spec = { + .name = "typing.ParamSpecArgs", + .basicsize = sizeof(paramspecattrobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .slots = paramspecargs_slots, +}; + +static PyObject * +paramspeckwargs_repr(PyObject *self) +{ + paramspecattrobject *psk = (paramspecattrobject *)self; + + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspec_type; + if (Py_IS_TYPE(psk->__origin__, tp)) { + return PyUnicode_FromFormat("%U.kwargs", + ((paramspecobject *)psk->__origin__)->name); + } + return PyUnicode_FromFormat("%R.kwargs", psk->__origin__); +} + +/*[clinic input] + at classmethod +paramspeckwargs.__new__ as paramspeckwargs_new + + origin: object + +Create a ParamSpecKwargs object. +[clinic start generated code]*/ + +static PyObject * +paramspeckwargs_new_impl(PyTypeObject *type, PyObject *origin) +/*[clinic end generated code: output=277b11967ebaf4ab input=981bca9b0cf9e40a]*/ +{ + return (PyObject *)paramspecattr_new(type, origin); +} + +static PyObject * +paramspeckwargs_mro_entries(PyObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "Cannot subclass an instance of ParamSpecKwargs"); + return NULL; +} + +static PyMethodDef paramspeckwargs_methods[] = { + {"__mro_entries__", paramspeckwargs_mro_entries, METH_O}, + {0} +}; + +PyDoc_STRVAR(paramspeckwargs_doc, +"The kwargs for a ParamSpec object.\n\ +\n\ +Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs.\n\ +\n\ +ParamSpecKwargs objects have a reference back to their ParamSpec:\n\ +\n\ + P.kwargs.__origin__ is P\n\ +\n\ +This type is meant for runtime introspection and has no special meaning to\n\ +static type checkers.\n\ +"); + +static PyType_Slot paramspeckwargs_slots[] = { + {Py_tp_doc, (void *)paramspeckwargs_doc}, + {Py_tp_methods, paramspeckwargs_methods}, + {Py_tp_new, paramspeckwargs_new}, + {Py_tp_dealloc, paramspecattr_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, paramspecattr_traverse}, + {Py_tp_clear, (inquiry)paramspecattr_clear}, + {Py_tp_repr, paramspeckwargs_repr}, + {Py_tp_members, paramspecattr_members}, + {Py_tp_richcompare, paramspecattr_richcompare}, + {0, NULL}, +}; + +PyType_Spec paramspeckwargs_spec = { + .name = "typing.ParamSpecKwargs", + .basicsize = sizeof(paramspecattrobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .slots = paramspeckwargs_slots, +}; + +static void +paramspec_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + paramspecobject *ps = (paramspecobject *)self; + + _PyObject_GC_UNTRACK(self); + + Py_DECREF(ps->name); + Py_XDECREF(ps->bound); + _PyObject_ClearManagedDict(self); + + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); +} + +static int +paramspec_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + paramspecobject *ps = (paramspecobject *)self; + Py_VISIT(ps->bound); + _PyObject_VisitManagedDict(self, visit, arg); + return 0; +} + +static int +paramspec_clear(paramspecobject *self) +{ + Py_CLEAR(self->bound); + _PyObject_ClearManagedDict((PyObject *)self); + return 0; +} + +static PyObject * +paramspec_repr(PyObject *self) +{ + paramspecobject *ps = (paramspecobject *)self; + + if (ps->infer_variance) { + return Py_NewRef(ps->name); + } + + char variance = ps->covariant ? '+' : ps->contravariant ? '-' : '~'; + return PyUnicode_FromFormat("%c%U", variance, ps->name); +} + +static PyMemberDef paramspec_members[] = { + {"__name__", T_OBJECT, offsetof(paramspecobject, name), READONLY}, + {"__bound__", T_OBJECT, offsetof(paramspecobject, bound), READONLY}, + {"__covariant__", T_BOOL, offsetof(paramspecobject, covariant), READONLY}, + {"__contravariant__", T_BOOL, offsetof(paramspecobject, contravariant), READONLY}, + {"__infer_variance__", T_BOOL, offsetof(paramspecobject, infer_variance), READONLY}, + {0} +}; + +static PyObject * +paramspec_args(PyObject *self, void *unused) +{ + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspecargs_type; + return (PyObject *)paramspecattr_new(tp, self); +} + +static PyObject * +paramspec_kwargs(PyObject *self, void *unused) +{ + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspeckwargs_type; + return (PyObject *)paramspecattr_new(tp, self); +} + +static PyGetSetDef paramspec_getset[] = { + {"args", (getter)paramspec_args, NULL, "Represents positional arguments.", NULL}, + {"kwargs", (getter)paramspec_kwargs, NULL, "Represents keyword arguments.", NULL}, + {0}, +}; + +static paramspecobject * +paramspec_alloc(PyObject *name, PyObject *bound, bool covariant, + bool contravariant, bool infer_variance, PyObject *module) +{ + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspec_type; + paramspecobject *ps = PyObject_GC_New(paramspecobject, tp); + if (ps == NULL) { + return NULL; + } + ps->name = Py_NewRef(name); + ps->bound = Py_XNewRef(bound); + ps->covariant = covariant; + ps->contravariant = contravariant; + ps->infer_variance = infer_variance; + _PyObject_GC_TRACK(ps); + if (module != NULL) { + if (PyObject_SetAttrString((PyObject *)ps, "__module__", module) < 0) { + Py_DECREF(ps); + return NULL; + } + } + return ps; +} + +/*[clinic input] + at classmethod +paramspec.__new__ as paramspec_new + + name: object(subclass_of="&PyUnicode_Type") + * + bound: object = None + covariant: bool = False + contravariant: bool = False + infer_variance: bool = False + +Create a ParamSpec object. +[clinic start generated code]*/ + +static PyObject * +paramspec_new_impl(PyTypeObject *type, PyObject *name, PyObject *bound, + int covariant, int contravariant, int infer_variance) +/*[clinic end generated code: output=fd2daab79cba62da input=57c49c581979b952]*/ +{ + if (covariant && contravariant) { + PyErr_SetString(PyExc_ValueError, "Bivariant types are not supported."); + return NULL; + } + if (infer_variance && (covariant || contravariant)) { + PyErr_SetString(PyExc_ValueError, "Variance cannot be specified with infer_variance."); + return NULL; + } + if (bound != NULL) { + bound = type_check(bound, "Bound must be a type."); + if (bound == NULL) { + return NULL; + } + } + PyObject *module = caller(); + if (module == NULL) { + Py_XDECREF(bound); + return NULL; + } + PyObject *ps = (PyObject *)paramspec_alloc( + name, bound, covariant, contravariant, infer_variance, module); + Py_XDECREF(bound); + Py_DECREF(module); + return ps; +} + + +/*[clinic input] +paramspec.__typing_subst__ as paramspec_typing_subst + + arg: object + +[clinic start generated code]*/ + +static PyObject * +paramspec_typing_subst_impl(paramspecobject *self, PyObject *arg) +/*[clinic end generated code: output=803e1ade3f13b57d input=4e0005d24023e896]*/ +{ + PyObject *args[2] = {(PyObject *)self, arg}; + PyObject *result = call_typing_func_object("_paramspec_subst", args, 2); + return result; +} + +/*[clinic input] +paramspec.__typing_prepare_subst__ as paramspec_typing_prepare_subst + + alias: object + args: object + +[clinic start generated code]*/ + +static PyObject * +paramspec_typing_prepare_subst_impl(paramspecobject *self, PyObject *alias, + PyObject *args) +/*[clinic end generated code: output=95449d630a2adb9a input=4375e2ffcb2ad635]*/ +{ + PyObject *args_array[3] = {(PyObject *)self, alias, args}; + PyObject *result = call_typing_func_object( + "_paramspec_prepare_subst", args_array, 3); + return result; +} + +/*[clinic input] +paramspec.__reduce__ as paramspec_reduce + +[clinic start generated code]*/ + +static PyObject * +paramspec_reduce_impl(paramspecobject *self) +/*[clinic end generated code: output=b83398674416db27 input=5bf349f0d5dd426c]*/ +{ + return Py_NewRef(self->name); +} + +static PyObject * +paramspec_mro_entries(PyObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "Cannot subclass an instance of ParamSpec"); + return NULL; +} + +static PyMethodDef paramspec_methods[] = { + PARAMSPEC_TYPING_SUBST_METHODDEF + PARAMSPEC_TYPING_PREPARE_SUBST_METHODDEF + PARAMSPEC_REDUCE_METHODDEF + {"__mro_entries__", paramspec_mro_entries, METH_O}, + {0} +}; + +PyDoc_STRVAR(paramspec_doc, +"Parameter specification variable.\n\ +\n\ +Usage::\n\ +\n\ + P = ParamSpec('P')\n\ +\n\ +Parameter specification variables exist primarily for the benefit of static\n\ +type checkers. They are used to forward the parameter types of one\n\ +callable to another callable, a pattern commonly found in higher order\n\ +functions and decorators. They are only valid when used in ``Concatenate``,\n\ +or as the first argument to ``Callable``, or as parameters for user-defined\n\ +Generics. See class Generic for more information on generic types. An\n\ +example for annotating a decorator::\n\ +\n\ + T = TypeVar('T')\n\ + P = ParamSpec('P')\n\ +\n\ + def add_logging(f: Callable[P, T]) -> Callable[P, T]:\n\ + '''A type-safe decorator to add logging to a function.'''\n\ + def inner(*args: P.args, **kwargs: P.kwargs) -> T:\n\ + logging.info(f'{f.__name__} was called')\n\ + return f(*args, **kwargs)\n\ + return inner\n\ +\n\ + @add_logging\n\ + def add_two(x: float, y: float) -> float:\n\ + '''Add two numbers together.'''\n\ + return x + y\n\ +\n\ +Parameter specification variables defined with covariant=True or\n\ +contravariant=True can be used to declare covariant or contravariant\n\ +generic types. These keyword arguments are valid, but their actual semantics\n\ +are yet to be decided. See PEP 612 for details.\n\ +\n\ +Parameter specification variables can be introspected. e.g.:\n\ +\n\ + P.__name__ == 'P'\n\ + P.__bound__ == None\n\ + P.__covariant__ == False\n\ + P.__contravariant__ == False\n\ +\n\ +Note that only parameter specification variables defined in global scope can\n\ +be pickled.\n\ +"); + +static PyType_Slot paramspec_slots[] = { + {Py_tp_doc, (void *)paramspec_doc}, + {Py_tp_members, paramspec_members}, + {Py_tp_methods, paramspec_methods}, + {Py_tp_getset, paramspec_getset}, + // Unions of ParamSpecs have no defined meaning, but they were allowed + // by the Python implementation, so we allow them here too. + {Py_nb_or, make_union}, + {Py_tp_new, paramspec_new}, + {Py_tp_dealloc, paramspec_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, paramspec_traverse}, + {Py_tp_clear, paramspec_clear}, + {Py_tp_repr, paramspec_repr}, + {0, 0}, +}; + +PyType_Spec paramspec_spec = { + .name = "typing.ParamSpec", + .basicsize = sizeof(paramspecobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_DICT, + .slots = paramspec_slots, +}; + +static void +typevartuple_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + typevartupleobject *tvt = (typevartupleobject *)self; + + Py_DECREF(tvt->name); + _PyObject_ClearManagedDict(self); + + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); +} + +static PyObject * +typevartuple_iter(PyObject *self) +{ + PyObject *unpacked = typevartuple_unpack(self); + if (unpacked == NULL) { + return NULL; + } + PyObject *tuple = PyTuple_Pack(1, unpacked); + if (tuple == NULL) { + Py_DECREF(unpacked); + return NULL; + } + PyObject *result = PyObject_GetIter(tuple); + Py_DECREF(unpacked); + Py_DECREF(tuple); + return result; +} + +static PyObject * +typevartuple_repr(PyObject *self) +{ + typevartupleobject *tvt = (typevartupleobject *)self; + + return Py_NewRef(tvt->name); +} + +static PyMemberDef typevartuple_members[] = { + {"__name__", T_OBJECT, offsetof(typevartupleobject, name), READONLY}, + {0} +}; + +static typevartupleobject * +typevartuple_alloc(PyObject *name, PyObject *module) +{ + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevartuple_type; + typevartupleobject *tvt = PyObject_GC_New(typevartupleobject, tp); + if (tvt == NULL) { + return NULL; + } + tvt->name = Py_NewRef(name); + _PyObject_GC_TRACK(tvt); + if (module != NULL) { + if (PyObject_SetAttrString((PyObject *)tvt, "__module__", module) < 0) { + Py_DECREF(tvt); + return NULL; + } + } + return tvt; +} + +/*[clinic input] + at classmethod +typevartuple.__new__ + + name: object(subclass_of="&PyUnicode_Type") + +Create a new TypeVarTuple with the given name. +[clinic start generated code]*/ + +static PyObject * +typevartuple_impl(PyTypeObject *type, PyObject *name) +/*[clinic end generated code: output=09d417a28f976202 input=00d28abcf1fc96bb]*/ +{ + PyObject *module = caller(); + if (module == NULL) { + return NULL; + } + PyObject *result = (PyObject *)typevartuple_alloc(name, module); + Py_DECREF(module); + return result; +} + +/*[clinic input] +typevartuple.__typing_subst__ as typevartuple_typing_subst + + arg: object + +[clinic start generated code]*/ + +static PyObject * +typevartuple_typing_subst_impl(typevartupleobject *self, PyObject *arg) +/*[clinic end generated code: output=814316519441cd76 input=670c4e0a36e5d8c0]*/ +{ + PyErr_SetString(PyExc_TypeError, "Substitution of bare TypeVarTuple is not supported"); + return NULL; +} + +/*[clinic input] +typevartuple.__typing_prepare_subst__ as typevartuple_typing_prepare_subst + + alias: object + args: object + +[clinic start generated code]*/ + +static PyObject * +typevartuple_typing_prepare_subst_impl(typevartupleobject *self, + PyObject *alias, PyObject *args) +/*[clinic end generated code: output=ff999bc5b02036c1 input=a211b05f2eeb4306]*/ +{ + PyObject *args_array[3] = {(PyObject *)self, alias, args}; + PyObject *result = call_typing_func_object( + "_typevartuple_prepare_subst", args_array, 3); + return result; +} + +/*[clinic input] +typevartuple.__reduce__ as typevartuple_reduce + +[clinic start generated code]*/ + +static PyObject * +typevartuple_reduce_impl(typevartupleobject *self) +/*[clinic end generated code: output=3215bc0477913d20 input=3018a4d66147e807]*/ +{ + return Py_NewRef(self->name); +} + +static PyObject * +typevartuple_mro_entries(PyObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, + "Cannot subclass an instance of TypeVarTuple"); + return NULL; +} + +static int +typevartuple_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + _PyObject_VisitManagedDict(self, visit, arg); + return 0; +} + +static int +typevartuple_clear(PyObject *self) +{ + _PyObject_ClearManagedDict(self); + return 0; +} + +static PyMethodDef typevartuple_methods[] = { + TYPEVARTUPLE_TYPING_SUBST_METHODDEF + TYPEVARTUPLE_TYPING_PREPARE_SUBST_METHODDEF + TYPEVARTUPLE_REDUCE_METHODDEF + {"__mro_entries__", typevartuple_mro_entries, METH_O}, + {0} +}; + +PyDoc_STRVAR(typevartuple_doc, +"Type variable tuple.\n\ +\n\ +Usage:\n\ +\n\ + Ts = TypeVarTuple('Ts') # Can be given any name\n\ +\n\ +Just as a TypeVar (type variable) is a placeholder for a single type,\n\ +a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\ +example, if we define a generic class using a TypeVarTuple:\n\ +\n\ + class C(Generic[*Ts]): ...\n\ +\n\ +Then we can parameterize that class with an arbitrary number of type\n\ +arguments:\n\ +\n\ + C[int] # Fine\n\ + C[int, str] # Also fine\n\ + C[()] # Even this is fine\n\ +\n\ +For more details, see PEP 646.\n\ +\n\ +Note that only TypeVarTuples defined in global scope can be pickled.\n\ +"); + +PyType_Slot typevartuple_slots[] = { + {Py_tp_doc, (void *)typevartuple_doc}, + {Py_tp_members, typevartuple_members}, + {Py_tp_methods, typevartuple_methods}, + {Py_tp_new, typevartuple}, + {Py_tp_iter, typevartuple_iter}, + {Py_tp_repr, typevartuple_repr}, + {Py_tp_dealloc, typevartuple_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, typevartuple_traverse}, + {Py_tp_clear, typevartuple_clear}, + {0, 0}, +}; + +PyType_Spec typevartuple_spec = { + .name = "typing.TypeVarTuple", + .basicsize = sizeof(typevartupleobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT + | Py_TPFLAGS_HAVE_GC, + .slots = typevartuple_slots, +}; + +PyObject * +_Py_make_typevar(PyObject *name, PyObject *evaluate_bound, PyObject *evaluate_constraints) +{ + return (PyObject *)typevar_alloc(name, NULL, evaluate_bound, NULL, evaluate_constraints, + false, false, true, NULL); +} + +PyObject * +_Py_make_paramspec(PyThreadState *Py_UNUSED(ignored), PyObject *v) +{ + assert(PyUnicode_Check(v)); + return (PyObject *)paramspec_alloc(v, NULL, false, false, true, NULL); +} + +PyObject * +_Py_make_typevartuple(PyThreadState *Py_UNUSED(ignored), PyObject *v) +{ + assert(PyUnicode_Check(v)); + return (PyObject *)typevartuple_alloc(v, NULL); +} + +static void +typealias_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + typealiasobject *ta = (typealiasobject *)self; + Py_DECREF(ta->name); + Py_XDECREF(ta->type_params); + Py_XDECREF(ta->compute_value); + Py_XDECREF(ta->value); + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); +} + +static PyObject * +typealias_get_value(typealiasobject *ta) +{ + if (ta->value != NULL) { + return Py_NewRef(ta->value); + } + PyObject *result = PyObject_CallNoArgs(ta->compute_value); + if (result == NULL) { + return NULL; + } + ta->value = Py_NewRef(result); + return result; +} + +static PyObject * +typealias_repr(PyObject *self) +{ + typealiasobject *ta = (typealiasobject *)self; + return Py_NewRef(ta->name); +} + +static PyMemberDef typealias_members[] = { + {"__name__", T_OBJECT, offsetof(typealiasobject, name), READONLY}, + {0} +}; + +static PyObject * +typealias_value(PyObject *self, void *unused) +{ + typealiasobject *ta = (typealiasobject *)self; + return typealias_get_value(ta); +} + +static PyObject * +typealias_parameters(PyObject *self, void *unused) +{ + typealiasobject *ta = (typealiasobject *)self; + if (ta->type_params == NULL) { + return PyTuple_New(0); + } + return unpack_typevartuples(ta->type_params); +} + +static PyObject * +typealias_type_params(PyObject *self, void *unused) +{ + typealiasobject *ta = (typealiasobject *)self; + if (ta->type_params == NULL) { + return PyTuple_New(0); + } + return Py_NewRef(ta->type_params); +} + +static PyGetSetDef typealias_getset[] = { + {"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL}, + {"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL}, + {"__value__", typealias_value, (setter)NULL, NULL, NULL}, + {0} +}; + +static typealiasobject * +typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, + PyObject *value) +{ + PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typealias_type; + typealiasobject *ta = PyObject_GC_New(typealiasobject, tp); + if (ta == NULL) { + return NULL; + } + ta->name = Py_NewRef(name); + ta->type_params = Py_IsNone(type_params) ? NULL : Py_XNewRef(type_params); + ta->compute_value = Py_XNewRef(compute_value); + ta->value = Py_XNewRef(value); + _PyObject_GC_TRACK(ta); + return ta; +} + +static int +typealias_traverse(typealiasobject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->type_params); + Py_VISIT(self->compute_value); + Py_VISIT(self->value); + return 0; +} + +static int +typealias_clear(typealiasobject *self) +{ + Py_CLEAR(self->type_params); + Py_CLEAR(self->compute_value); + Py_CLEAR(self->value); + return 0; +} + +/*[clinic input] +typealias.__reduce__ as typealias_reduce + +[clinic start generated code]*/ + +static PyObject * +typealias_reduce_impl(typealiasobject *self) +/*[clinic end generated code: output=913724f92ad3b39b input=4f06fbd9472ec0f1]*/ +{ + return Py_NewRef(self->name); +} + +static PyObject * +typealias_subscript(PyObject *self, PyObject *args) +{ + if (((typealiasobject *)self)->type_params == NULL) { + PyErr_SetString(PyExc_TypeError, + "Only generic type aliases are subscriptable"); + return NULL; + } + return Py_GenericAlias(self, args); +} + +static PyMethodDef typealias_methods[] = { + TYPEALIAS_REDUCE_METHODDEF + {0} +}; + + +/*[clinic input] + at classmethod +typealias.__new__ as typealias_new + + name: object(subclass_of="&PyUnicode_Type") + value: object + * + type_params: object = NULL + +Create a TypeAliasType. +[clinic start generated code]*/ + +static PyObject * +typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, + PyObject *type_params) +/*[clinic end generated code: output=8920ce6bdff86f00 input=df163c34e17e1a35]*/ +{ + if (type_params != NULL && !PyTuple_Check(type_params)) { + PyErr_SetString(PyExc_TypeError, "type_params must be a tuple"); + return NULL; + } + return (PyObject *)typealias_alloc(name, type_params, NULL, value); +} + +PyDoc_STRVAR(typealias_doc, +"Type alias.\n\ +\n\ +Type aliases are created through the type statement:\n\ +\n\ + type Alias = int\n\ +"); + +static PyType_Slot typealias_slots[] = { + {Py_tp_doc, (void *)typealias_doc}, + {Py_tp_members, typealias_members}, + {Py_tp_methods, typealias_methods}, + {Py_tp_getset, typealias_getset}, + {Py_mp_subscript, typealias_subscript}, + {Py_tp_dealloc, typealias_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, typealias_new}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, (traverseproc)typealias_traverse}, + {Py_tp_clear, (inquiry)typealias_clear}, + {Py_tp_repr, typealias_repr}, + {Py_nb_or, _Py_union_type_or}, + {0, 0}, +}; + +PyType_Spec typealias_spec = { + .name = "typing.TypeAliasType", + .basicsize = sizeof(typealiasobject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC, + .slots = typealias_slots, +}; + +PyObject * +_Py_make_typealias(PyThreadState* unused, PyObject *args) +{ + assert(PyTuple_Check(args)); + assert(PyTuple_GET_SIZE(args) == 3); + PyObject *name = PyTuple_GET_ITEM(args, 0); + assert(PyUnicode_Check(name)); + PyObject *type_params = PyTuple_GET_ITEM(args, 1); + PyObject *compute_value = PyTuple_GET_ITEM(args, 2); + return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL); +} + +PyDoc_STRVAR(generic_doc, +"Abstract base class for generic types.\n\ +\n\ +A generic type is typically declared by inheriting from\n\ +this class parameterized with one or more type variables.\n\ +For example, a generic mapping type might be defined as::\n\ +\n\ + class Mapping(Generic[KT, VT]):\n\ + def __getitem__(self, key: KT) -> VT:\n\ + ...\n\ + # Etc.\n\ +\n\ +This class can then be used as follows::\n\ +\n\ + def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\ + try:\n\ + return mapping[key]\n\ + except KeyError:\n\ + return default\n\ +"); + +PyDoc_STRVAR(generic_class_getitem_doc, +"Parameterizes a generic class.\n\ +\n\ +At least, parameterizing a generic class is the *main* thing this method\n\ +does. For example, for some generic class `Foo`, this is called when we\n\ +do `Foo[int]` - there, with `cls=Foo` and `params=int`.\n\ +\n\ +However, note that this method is also called when defining generic\n\ +classes in the first place with `class Foo(Generic[T]): ...`.\n\ +"); + +static PyObject * +call_typing_args_kwargs(const char *name, PyTypeObject *cls, PyObject *args, PyObject *kwargs) +{ + PyObject *typing = NULL, *func = NULL, *new_args = NULL; + typing = PyImport_ImportModule("typing"); + if (typing == NULL) { + goto error; + } + func = PyObject_GetAttrString(typing, name); + if (func == NULL) { + goto error; + } + assert(PyTuple_Check(args)); + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + new_args = PyTuple_New(nargs + 1); + if (new_args == NULL) { + goto error; + } + PyTuple_SET_ITEM(new_args, 0, Py_NewRef((PyObject *)cls)); + for (Py_ssize_t i = 0; i < nargs; i++) { + PyObject *arg = PyTuple_GET_ITEM(args, i); + PyTuple_SET_ITEM(new_args, i + 1, Py_NewRef(arg)); + } + PyObject *result = PyObject_Call(func, new_args, kwargs); + Py_DECREF(typing); + Py_DECREF(func); + Py_DECREF(new_args); + return result; +error: + Py_XDECREF(typing); + Py_XDECREF(func); + Py_XDECREF(new_args); + return NULL; +} + +static PyObject * +generic_init_subclass(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +{ + return call_typing_args_kwargs("_generic_init_subclass", cls, args, kwargs); +} + +static PyObject * +generic_class_getitem(PyTypeObject *cls, PyObject *args, PyObject *kwargs) +{ + return call_typing_args_kwargs("_generic_class_getitem", cls, args, kwargs); +} + +PyObject * +_Py_subscript_generic(PyThreadState* unused, PyObject *params) +{ + params = unpack_typevartuples(params); + + PyInterpreterState *interp = PyInterpreterState_Get(); + if (interp->cached_objects.generic_type == NULL) { + PyErr_SetString(PyExc_SystemError, "Cannot find Generic type"); + return NULL; + } + PyObject *args[2] = {(PyObject *)interp->cached_objects.generic_type, params}; + PyObject *result = call_typing_func_object("_GenericAlias", args, 2); + Py_DECREF(params); + return result; +} + +static PyMethodDef generic_methods[] = { + {"__class_getitem__", (PyCFunction)(void (*)(void))generic_class_getitem, + METH_VARARGS | METH_KEYWORDS | METH_CLASS, + generic_class_getitem_doc}, + {"__init_subclass__", (PyCFunction)(void (*)(void))generic_init_subclass, + METH_VARARGS | METH_KEYWORDS | METH_CLASS, + PyDoc_STR("Function to initialize subclasses.")}, + {NULL} /* Sentinel */ +}; + +static void +generic_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + _PyObject_GC_UNTRACK(self); + Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); +} + +static int +generic_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static PyType_Slot generic_slots[] = { + {Py_tp_doc, (void *)generic_doc}, + {Py_tp_methods, generic_methods}, + {Py_tp_dealloc, generic_dealloc}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_free, PyObject_GC_Del}, + {Py_tp_traverse, generic_traverse}, + {0, NULL}, +}; + +PyType_Spec generic_spec = { + .name = "typing.Generic", + .basicsize = sizeof(PyObject), + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .slots = generic_slots, +}; + +int _Py_initialize_generic(PyInterpreterState *interp) +{ +#define MAKE_TYPE(name) \ + do { \ + PyTypeObject *name ## _type = (PyTypeObject *)PyType_FromSpec(&name ## _spec); \ + if (name ## _type == NULL) { \ + return -1; \ + } \ + interp->cached_objects.name ## _type = name ## _type; \ + } while(0) + + MAKE_TYPE(generic); + MAKE_TYPE(typevar); + MAKE_TYPE(typevartuple); + MAKE_TYPE(paramspec); + MAKE_TYPE(paramspecargs); + MAKE_TYPE(paramspeckwargs); + MAKE_TYPE(typealias); +#undef MAKE_TYPE + return 0; +} + +void _Py_clear_generic_types(PyInterpreterState *interp) +{ + Py_CLEAR(interp->cached_objects.generic_type); + Py_CLEAR(interp->cached_objects.typevar_type); + Py_CLEAR(interp->cached_objects.typevartuple_type); + Py_CLEAR(interp->cached_objects.paramspec_type); + Py_CLEAR(interp->cached_objects.paramspecargs_type); + Py_CLEAR(interp->cached_objects.paramspeckwargs_type); + Py_CLEAR(interp->cached_objects.typealias_type); +} diff --git a/Objects/unionobject.c b/Objects/unionobject.c index f273f7d15ef2..9806678b8048 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -147,10 +147,14 @@ get_types(PyObject **obj, Py_ssize_t *size) static int is_unionable(PyObject *obj) { - return (obj == Py_None || + if (obj == Py_None || PyType_Check(obj) || _PyGenericAlias_Check(obj) || - _PyUnion_Check(obj)); + _PyUnion_Check(obj)) { + return 1; + } + PyInterpreterState *interp = PyInterpreterState_Get(); + return Py_IS_TYPE(obj, interp->cached_objects.typealias_type); } PyObject * diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index d897925f58c0..c9dbe195d932 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -159,6 +159,7 @@ <ClCompile Include="..\Objects\structseq.c" /> <ClCompile Include="..\Objects\tupleobject.c" /> <ClCompile Include="..\Objects\typeobject.c" /> + <ClCompile Include="..\Objects\typevarobject.c" /> <ClCompile Include="..\Objects\unicodectype.c" /> <ClCompile Include="..\Objects\unicodeobject.c" /> <ClCompile Include="..\Objects\unionobject.c" /> diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 28b1517c6f6b..ca43404454c4 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -269,6 +269,7 @@ <ClInclude Include="..\Include\internal\pycore_tracemalloc.h" /> <ClInclude Include="..\Include\internal\pycore_tuple.h" /> <ClInclude Include="..\Include\internal\pycore_typeobject.h" /> + <ClInclude Include="..\Include\internal\pycore_typevarobject.h" /> <ClInclude Include="..\Include\internal\pycore_ucnhash.h" /> <ClInclude Include="..\Include\internal\pycore_unionobject.h" /> <ClInclude Include="..\Include\internal\pycore_unicodeobject.h" /> @@ -481,6 +482,7 @@ <ClCompile Include="..\Objects\structseq.c" /> <ClCompile Include="..\Objects\tupleobject.c" /> <ClCompile Include="..\Objects\typeobject.c" /> + <ClCompile Include="..\Objects\typevarobject.c" /> <ClCompile Include="..\Objects\unicodectype.c" /> <ClCompile Include="..\Objects\unicodeobject.c" /> <ClCompile Include="..\Objects\unionobject.c" /> diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 75e6fbb13f98..a3c2e2476dd6 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -705,6 +705,9 @@ <ClInclude Include="..\Include\internal\pycore_typeobject.h"> <Filter>Include\internal</Filter> </ClInclude> + <ClInclude Include="..\Include\internal\pycore_typevarobject.h"> + <Filter>Include\internal</Filter> + </ClInclude> <ClInclude Include="..\Include\internal\pycore_ucnhash.h"> <Filter>Include\internal</Filter> </ClInclude> @@ -1364,6 +1367,9 @@ <ClCompile Include="..\Objects\genericaliasobject.c"> <Filter>Objects</Filter> </ClCompile> + <ClCompile Include="..\Objects\typevarobject.c"> + <Filter>Objects</Filter> + </ClCompile> <ClCompile Include="..\Objects\unionobject.c"> <Filter>Objects</Filter> </ClCompile> diff --git a/Parser/Python.asdl b/Parser/Python.asdl index e9423a7c984f..cfc41ef45b56 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -8,14 +8,15 @@ module Python | Expression(expr body) | FunctionType(expr* argtypes, expr returns) - stmt = FunctionDef(identifier name, arguments args, + stmt = FunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment) - | AsyncFunctionDef(identifier name, arguments args, + | AsyncFunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, + typeparam* typeparams, expr* bases, keyword* keywords, stmt* body, @@ -24,6 +25,7 @@ module Python | Delete(expr* targets) | Assign(expr* targets, expr value, string? type_comment) + | TypeAlias(expr name, typeparam* typeparams, expr value) | AugAssign(expr target, operator op, expr value) -- 'simple' indicates that we annotate simple name without parens | AnnAssign(expr target, expr annotation, expr? value, int simple) @@ -142,4 +144,9 @@ module Python attributes (int lineno, int col_offset, int end_lineno, int end_col_offset) type_ignore = TypeIgnore(int lineno, string tag) + + typeparam = TypeVar(identifier name, expr? bound) + | ParamSpec(identifier name) + | TypeVarTuple(identifier name) + attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) } diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 0aaaed64c403..0134e6f16ba8 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -752,7 +752,8 @@ _PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty f assert(function_def != NULL); if (function_def->kind == AsyncFunctionDef_kind) { return _PyAST_AsyncFunctionDef( - function_def->v.FunctionDef.name, function_def->v.FunctionDef.args, + function_def->v.FunctionDef.name, function_def->v.FunctionDef.typeparams, + function_def->v.FunctionDef.args, function_def->v.FunctionDef.body, decorators, function_def->v.FunctionDef.returns, function_def->v.FunctionDef.type_comment, function_def->lineno, function_def->col_offset, function_def->end_lineno, function_def->end_col_offset, @@ -760,7 +761,8 @@ _PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty f } return _PyAST_FunctionDef( - function_def->v.FunctionDef.name, function_def->v.FunctionDef.args, + function_def->v.FunctionDef.name, function_def->v.FunctionDef.typeparams, + function_def->v.FunctionDef.args, function_def->v.FunctionDef.body, decorators, function_def->v.FunctionDef.returns, function_def->v.FunctionDef.type_comment, function_def->lineno, @@ -774,8 +776,9 @@ _PyPegen_class_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty clas { assert(class_def != NULL); return _PyAST_ClassDef( - class_def->v.ClassDef.name, class_def->v.ClassDef.bases, - class_def->v.ClassDef.keywords, class_def->v.ClassDef.body, decorators, + class_def->v.ClassDef.name, class_def->v.ClassDef.typeparams, + class_def->v.ClassDef.bases, class_def->v.ClassDef.keywords, + class_def->v.ClassDef.body, decorators, class_def->lineno, class_def->col_offset, class_def->end_lineno, class_def->end_col_offset, p->arena); } diff --git a/Parser/parser.c b/Parser/parser.c index 6eb985a7d3e1..894846714eff 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -75,6 +75,7 @@ static char *soft_keywords[] = { "_", "case", "match", + "type", NULL, }; #define file_type 1000 @@ -175,419 +176,426 @@ static char *soft_keywords[] = { #define positional_patterns_type 1095 #define keyword_patterns_type 1096 #define keyword_pattern_type 1097 -#define expressions_type 1098 -#define expression_type 1099 -#define yield_expr_type 1100 -#define star_expressions_type 1101 -#define star_expression_type 1102 -#define star_named_expressions_type 1103 -#define star_named_expression_type 1104 -#define assignment_expression_type 1105 -#define named_expression_type 1106 -#define disjunction_type 1107 -#define conjunction_type 1108 -#define inversion_type 1109 -#define comparison_type 1110 -#define compare_op_bitwise_or_pair_type 1111 -#define eq_bitwise_or_type 1112 -#define noteq_bitwise_or_type 1113 -#define lte_bitwise_or_type 1114 -#define lt_bitwise_or_type 1115 -#define gte_bitwise_or_type 1116 -#define gt_bitwise_or_type 1117 -#define notin_bitwise_or_type 1118 -#define in_bitwise_or_type 1119 -#define isnot_bitwise_or_type 1120 -#define is_bitwise_or_type 1121 -#define bitwise_or_type 1122 // Left-recursive -#define bitwise_xor_type 1123 // Left-recursive -#define bitwise_and_type 1124 // Left-recursive -#define shift_expr_type 1125 // Left-recursive -#define sum_type 1126 // Left-recursive -#define term_type 1127 // Left-recursive -#define factor_type 1128 -#define power_type 1129 -#define await_primary_type 1130 -#define primary_type 1131 // Left-recursive -#define slices_type 1132 -#define slice_type 1133 -#define atom_type 1134 -#define group_type 1135 -#define lambdef_type 1136 -#define lambda_params_type 1137 -#define lambda_parameters_type 1138 -#define lambda_slash_no_default_type 1139 -#define lambda_slash_with_default_type 1140 -#define lambda_star_etc_type 1141 -#define lambda_kwds_type 1142 -#define lambda_param_no_default_type 1143 -#define lambda_param_with_default_type 1144 -#define lambda_param_maybe_default_type 1145 -#define lambda_param_type 1146 -#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 +#define type_alias_type 1098 +#define type_params_type 1099 +#define type_param_seq_type 1100 +#define type_param_type 1101 +#define type_param_bound_type 1102 +#define expressions_type 1103 +#define expression_type 1104 +#define yield_expr_type 1105 +#define star_expressions_type 1106 +#define star_expression_type 1107 +#define star_named_expressions_type 1108 +#define star_named_expression_type 1109 +#define assignment_expression_type 1110 +#define named_expression_type 1111 +#define disjunction_type 1112 +#define conjunction_type 1113 +#define inversion_type 1114 +#define comparison_type 1115 +#define compare_op_bitwise_or_pair_type 1116 +#define eq_bitwise_or_type 1117 +#define noteq_bitwise_or_type 1118 +#define lte_bitwise_or_type 1119 +#define lt_bitwise_or_type 1120 +#define gte_bitwise_or_type 1121 +#define gt_bitwise_or_type 1122 +#define notin_bitwise_or_type 1123 +#define in_bitwise_or_type 1124 +#define isnot_bitwise_or_type 1125 +#define is_bitwise_or_type 1126 +#define bitwise_or_type 1127 // Left-recursive +#define bitwise_xor_type 1128 // Left-recursive +#define bitwise_and_type 1129 // Left-recursive +#define shift_expr_type 1130 // Left-recursive +#define sum_type 1131 // Left-recursive +#define term_type 1132 // Left-recursive +#define factor_type 1133 +#define power_type 1134 +#define await_primary_type 1135 +#define primary_type 1136 // Left-recursive +#define slices_type 1137 +#define slice_type 1138 +#define atom_type 1139 +#define group_type 1140 +#define lambdef_type 1141 +#define lambda_params_type 1142 +#define lambda_parameters_type 1143 +#define lambda_slash_no_default_type 1144 +#define lambda_slash_with_default_type 1145 +#define lambda_star_etc_type 1146 +#define lambda_kwds_type 1147 +#define lambda_param_no_default_type 1148 +#define lambda_param_with_default_type 1149 +#define lambda_param_maybe_default_type 1150 +#define lambda_param_type 1151 +#define fstring_middle_type 1152 +#define fstring_replacement_field_type 1153 +#define fstring_conversion_type 1154 +#define fstring_full_format_spec_type 1155 +#define fstring_format_spec_type 1156 +#define string_type 1157 +#define strings_type 1158 +#define list_type 1159 +#define tuple_type 1160 +#define set_type 1161 +#define dict_type 1162 +#define double_starred_kvpairs_type 1163 +#define double_starred_kvpair_type 1164 +#define kvpair_type 1165 +#define for_if_clauses_type 1166 +#define for_if_clause_type 1167 +#define listcomp_type 1168 +#define setcomp_type 1169 +#define genexp_type 1170 +#define dictcomp_type 1171 +#define arguments_type 1172 +#define args_type 1173 +#define kwargs_type 1174 +#define starred_expression_type 1175 +#define kwarg_or_starred_type 1176 +#define kwarg_or_double_starred_type 1177 +#define star_targets_type 1178 +#define star_targets_list_seq_type 1179 +#define star_targets_tuple_seq_type 1180 +#define star_target_type 1181 +#define target_with_star_atom_type 1182 +#define star_atom_type 1183 +#define single_target_type 1184 +#define single_subscript_attribute_target_type 1185 +#define t_primary_type 1186 // Left-recursive +#define t_lookahead_type 1187 +#define del_targets_type 1188 +#define del_target_type 1189 +#define del_t_atom_type 1190 +#define type_expressions_type 1191 +#define func_type_comment_type 1192 +#define invalid_arguments_type 1193 +#define invalid_kwarg_type 1194 +#define expression_without_invalid_type 1195 +#define invalid_legacy_expression_type 1196 +#define invalid_expression_type 1197 +#define invalid_named_expression_type 1198 +#define invalid_assignment_type 1199 +#define invalid_ann_assign_target_type 1200 +#define invalid_del_stmt_type 1201 +#define invalid_block_type 1202 +#define invalid_comprehension_type 1203 +#define invalid_dict_comprehension_type 1204 +#define invalid_parameters_type 1205 +#define invalid_default_type 1206 +#define invalid_star_etc_type 1207 +#define invalid_kwds_type 1208 +#define invalid_parameters_helper_type 1209 +#define invalid_lambda_parameters_type 1210 +#define invalid_lambda_parameters_helper_type 1211 +#define invalid_lambda_star_etc_type 1212 +#define invalid_lambda_kwds_type 1213 +#define invalid_double_type_comments_type 1214 +#define invalid_with_item_type 1215 +#define invalid_for_target_type 1216 +#define invalid_group_type 1217 +#define invalid_import_type 1218 +#define invalid_import_from_targets_type 1219 +#define invalid_with_stmt_type 1220 +#define invalid_with_stmt_indent_type 1221 +#define invalid_try_stmt_type 1222 +#define invalid_except_stmt_type 1223 +#define invalid_finally_stmt_type 1224 +#define invalid_except_stmt_indent_type 1225 +#define invalid_except_star_stmt_indent_type 1226 +#define invalid_match_stmt_type 1227 +#define invalid_case_block_type 1228 +#define invalid_as_pattern_type 1229 +#define invalid_class_pattern_type 1230 +#define invalid_class_argument_pattern_type 1231 +#define invalid_if_stmt_type 1232 +#define invalid_elif_stmt_type 1233 +#define invalid_else_stmt_type 1234 +#define invalid_while_stmt_type 1235 +#define invalid_for_stmt_type 1236 +#define invalid_def_raw_type 1237 +#define invalid_class_def_raw_type 1238 +#define invalid_double_starred_kvpairs_type 1239 +#define invalid_kvpair_type 1240 +#define invalid_starred_expression_type 1241 +#define invalid_replacement_field_type 1242 +#define invalid_conversion_character_type 1243 +#define _loop0_1_type 1244 +#define _loop0_2_type 1245 +#define _loop0_3_type 1246 +#define _loop1_4_type 1247 +#define _loop0_6_type 1248 +#define _gather_5_type 1249 +#define _tmp_7_type 1250 +#define _tmp_8_type 1251 +#define _tmp_9_type 1252 +#define _tmp_10_type 1253 +#define _tmp_11_type 1254 +#define _tmp_12_type 1255 +#define _tmp_13_type 1256 +#define _tmp_14_type 1257 +#define _loop1_15_type 1258 +#define _tmp_16_type 1259 +#define _tmp_17_type 1260 +#define _tmp_18_type 1261 +#define _loop0_20_type 1262 +#define _gather_19_type 1263 +#define _loop0_22_type 1264 +#define _gather_21_type 1265 +#define _tmp_23_type 1266 +#define _tmp_24_type 1267 +#define _loop0_25_type 1268 +#define _loop1_26_type 1269 +#define _loop0_28_type 1270 +#define _gather_27_type 1271 +#define _tmp_29_type 1272 +#define _loop0_31_type 1273 +#define _gather_30_type 1274 +#define _tmp_32_type 1275 +#define _loop1_33_type 1276 +#define _tmp_34_type 1277 +#define _tmp_35_type 1278 +#define _tmp_36_type 1279 +#define _loop0_37_type 1280 +#define _loop0_38_type 1281 +#define _loop0_39_type 1282 +#define _loop1_40_type 1283 +#define _loop0_41_type 1284 +#define _loop1_42_type 1285 +#define _loop1_43_type 1286 +#define _loop1_44_type 1287 +#define _loop0_45_type 1288 +#define _loop1_46_type 1289 +#define _loop0_47_type 1290 +#define _loop1_48_type 1291 +#define _loop0_49_type 1292 +#define _loop0_50_type 1293 +#define _loop1_51_type 1294 +#define _loop0_53_type 1295 +#define _gather_52_type 1296 +#define _loop0_55_type 1297 +#define _gather_54_type 1298 +#define _loop0_57_type 1299 +#define _gather_56_type 1300 +#define _loop0_59_type 1301 +#define _gather_58_type 1302 +#define _tmp_60_type 1303 +#define _loop1_61_type 1304 +#define _loop1_62_type 1305 +#define _tmp_63_type 1306 +#define _tmp_64_type 1307 +#define _loop1_65_type 1308 +#define _loop0_67_type 1309 +#define _gather_66_type 1310 +#define _tmp_68_type 1311 +#define _tmp_69_type 1312 +#define _tmp_70_type 1313 +#define _tmp_71_type 1314 +#define _loop0_73_type 1315 +#define _gather_72_type 1316 +#define _loop0_75_type 1317 +#define _gather_74_type 1318 +#define _tmp_76_type 1319 +#define _loop0_78_type 1320 +#define _gather_77_type 1321 +#define _loop0_80_type 1322 +#define _gather_79_type 1323 +#define _loop0_82_type 1324 +#define _gather_81_type 1325 +#define _loop1_83_type 1326 +#define _loop1_84_type 1327 +#define _loop0_86_type 1328 +#define _gather_85_type 1329 +#define _loop1_87_type 1330 +#define _loop1_88_type 1331 +#define _loop1_89_type 1332 +#define _tmp_90_type 1333 +#define _loop0_92_type 1334 +#define _gather_91_type 1335 +#define _tmp_93_type 1336 +#define _tmp_94_type 1337 +#define _tmp_95_type 1338 +#define _tmp_96_type 1339 +#define _tmp_97_type 1340 +#define _tmp_98_type 1341 +#define _loop0_99_type 1342 +#define _loop0_100_type 1343 +#define _loop0_101_type 1344 +#define _loop1_102_type 1345 +#define _loop0_103_type 1346 +#define _loop1_104_type 1347 +#define _loop1_105_type 1348 +#define _loop1_106_type 1349 +#define _loop0_107_type 1350 +#define _loop1_108_type 1351 +#define _loop0_109_type 1352 +#define _loop1_110_type 1353 +#define _loop0_111_type 1354 +#define _loop1_112_type 1355 +#define _tmp_113_type 1356 +#define _loop0_114_type 1357 +#define _loop1_115_type 1358 +#define _tmp_116_type 1359 +#define _loop0_118_type 1360 +#define _gather_117_type 1361 +#define _loop1_119_type 1362 +#define _loop0_120_type 1363 +#define _loop0_121_type 1364 +#define _tmp_122_type 1365 +#define _loop0_124_type 1366 +#define _gather_123_type 1367 +#define _tmp_125_type 1368 +#define _loop0_127_type 1369 +#define _gather_126_type 1370 +#define _loop0_129_type 1371 +#define _gather_128_type 1372 +#define _loop0_131_type 1373 +#define _gather_130_type 1374 +#define _loop0_133_type 1375 +#define _gather_132_type 1376 +#define _loop0_134_type 1377 +#define _loop0_136_type 1378 +#define _gather_135_type 1379 +#define _loop1_137_type 1380 +#define _tmp_138_type 1381 +#define _loop0_140_type 1382 +#define _gather_139_type 1383 +#define _loop0_142_type 1384 +#define _gather_141_type 1385 +#define _loop0_144_type 1386 +#define _gather_143_type 1387 +#define _loop0_146_type 1388 +#define _gather_145_type 1389 +#define _loop0_148_type 1390 +#define _gather_147_type 1391 +#define _tmp_149_type 1392 +#define _tmp_150_type 1393 +#define _tmp_151_type 1394 +#define _tmp_152_type 1395 +#define _tmp_153_type 1396 +#define _tmp_154_type 1397 +#define _tmp_155_type 1398 +#define _tmp_156_type 1399 +#define _tmp_157_type 1400 +#define _tmp_158_type 1401 +#define _tmp_159_type 1402 +#define _tmp_160_type 1403 +#define _loop0_161_type 1404 +#define _loop0_162_type 1405 +#define _loop0_163_type 1406 +#define _tmp_164_type 1407 +#define _tmp_165_type 1408 +#define _tmp_166_type 1409 +#define _tmp_167_type 1410 +#define _tmp_168_type 1411 +#define _loop0_169_type 1412 +#define _loop0_170_type 1413 +#define _loop0_171_type 1414 +#define _loop1_172_type 1415 +#define _tmp_173_type 1416 +#define _loop0_174_type 1417 +#define _tmp_175_type 1418 +#define _loop0_176_type 1419 +#define _loop1_177_type 1420 +#define _tmp_178_type 1421 +#define _tmp_179_type 1422 +#define _tmp_180_type 1423 +#define _loop0_181_type 1424 +#define _tmp_182_type 1425 +#define _tmp_183_type 1426 +#define _loop1_184_type 1427 +#define _tmp_185_type 1428 +#define _loop0_186_type 1429 +#define _loop0_187_type 1430 +#define _loop0_188_type 1431 +#define _loop0_190_type 1432 +#define _gather_189_type 1433 +#define _tmp_191_type 1434 +#define _loop0_192_type 1435 +#define _tmp_193_type 1436 +#define _loop0_194_type 1437 +#define _loop1_195_type 1438 +#define _loop1_196_type 1439 +#define _tmp_197_type 1440 +#define _tmp_198_type 1441 +#define _loop0_199_type 1442 +#define _tmp_200_type 1443 +#define _tmp_201_type 1444 +#define _tmp_202_type 1445 +#define _loop0_204_type 1446 +#define _gather_203_type 1447 +#define _loop0_206_type 1448 +#define _gather_205_type 1449 +#define _loop0_208_type 1450 +#define _gather_207_type 1451 +#define _loop0_210_type 1452 +#define _gather_209_type 1453 +#define _tmp_211_type 1454 +#define _loop0_212_type 1455 +#define _loop1_213_type 1456 +#define _tmp_214_type 1457 +#define _loop0_215_type 1458 +#define _loop1_216_type 1459 +#define _tmp_217_type 1460 +#define _tmp_218_type 1461 +#define _tmp_219_type 1462 +#define _tmp_220_type 1463 +#define _tmp_221_type 1464 +#define _tmp_222_type 1465 +#define _tmp_223_type 1466 +#define _tmp_224_type 1467 +#define _tmp_225_type 1468 +#define _tmp_226_type 1469 +#define _loop0_228_type 1470 +#define _gather_227_type 1471 +#define _tmp_229_type 1472 +#define _tmp_230_type 1473 +#define _tmp_231_type 1474 +#define _tmp_232_type 1475 +#define _tmp_233_type 1476 +#define _tmp_234_type 1477 +#define _tmp_235_type 1478 +#define _tmp_236_type 1479 +#define _tmp_237_type 1480 +#define _tmp_238_type 1481 +#define _tmp_239_type 1482 +#define _tmp_240_type 1483 +#define _tmp_241_type 1484 +#define _loop0_242_type 1485 +#define _tmp_243_type 1486 +#define _tmp_244_type 1487 +#define _tmp_245_type 1488 +#define _tmp_246_type 1489 +#define _tmp_247_type 1490 +#define _tmp_248_type 1491 +#define _tmp_249_type 1492 +#define _tmp_250_type 1493 +#define _tmp_251_type 1494 +#define _tmp_252_type 1495 +#define _tmp_253_type 1496 +#define _tmp_254_type 1497 +#define _tmp_255_type 1498 +#define _tmp_256_type 1499 +#define _tmp_257_type 1500 +#define _tmp_258_type 1501 +#define _tmp_259_type 1502 +#define _tmp_260_type 1503 +#define _tmp_261_type 1504 +#define _tmp_262_type 1505 +#define _tmp_263_type 1506 +#define _tmp_264_type 1507 +#define _tmp_265_type 1508 +#define _tmp_266_type 1509 +#define _tmp_267_type 1510 +#define _tmp_268_type 1511 +#define _tmp_269_type 1512 +#define _tmp_270_type 1513 +#define _tmp_271_type 1514 +#define _tmp_272_type 1515 +#define _tmp_273_type 1516 +#define _tmp_274_type 1517 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -687,6 +695,11 @@ static pattern_ty class_pattern_rule(Parser *p); static asdl_pattern_seq* positional_patterns_rule(Parser *p); static asdl_seq* keyword_patterns_rule(Parser *p); static KeyPatternPair* keyword_pattern_rule(Parser *p); +static stmt_ty type_alias_rule(Parser *p); +static asdl_typeparam_seq* type_params_rule(Parser *p); +static asdl_typeparam_seq* type_param_seq_rule(Parser *p); +static typeparam_ty type_param_rule(Parser *p); +static expr_ty type_param_bound_rule(Parser *p); static expr_ty expressions_rule(Parser *p); static expr_ty expression_rule(Parser *p); static expr_ty yield_expr_rule(Parser *p); @@ -908,64 +921,64 @@ 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 *_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 asdl_seq *_loop0_82_rule(Parser *p); +static asdl_seq *_gather_81_rule(Parser *p); +static asdl_seq *_loop1_83_rule(Parser *p); +static asdl_seq *_loop1_84_rule(Parser *p); +static asdl_seq *_loop0_86_rule(Parser *p); +static asdl_seq *_gather_85_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 asdl_seq *_loop1_88_rule(Parser *p); +static asdl_seq *_loop1_89_rule(Parser *p); +static void *_tmp_90_rule(Parser *p); +static asdl_seq *_loop0_92_rule(Parser *p); +static asdl_seq *_gather_91_rule(Parser *p); static void *_tmp_93_rule(Parser *p); static void *_tmp_94_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 *_loop0_98_rule(Parser *p); +static void *_tmp_97_rule(Parser *p); +static void *_tmp_98_rule(Parser *p); static asdl_seq *_loop0_99_rule(Parser *p); -static asdl_seq *_loop1_100_rule(Parser *p); +static asdl_seq *_loop0_100_rule(Parser *p); static asdl_seq *_loop0_101_rule(Parser *p); static asdl_seq *_loop1_102_rule(Parser *p); -static asdl_seq *_loop1_103_rule(Parser *p); +static asdl_seq *_loop0_103_rule(Parser *p); static asdl_seq *_loop1_104_rule(Parser *p); -static asdl_seq *_loop0_105_rule(Parser *p); +static asdl_seq *_loop1_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 *_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 *_loop1_113_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_111_rule(Parser *p); +static asdl_seq *_loop1_112_rule(Parser *p); +static void *_tmp_113_rule(Parser *p); +static asdl_seq *_loop0_114_rule(Parser *p); +static asdl_seq *_loop1_115_rule(Parser *p); +static void *_tmp_116_rule(Parser *p); static asdl_seq *_loop0_118_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 *_gather_117_rule(Parser *p); +static asdl_seq *_loop1_119_rule(Parser *p); +static asdl_seq *_loop0_120_rule(Parser *p); +static asdl_seq *_loop0_121_rule(Parser *p); +static void *_tmp_122_rule(Parser *p); +static asdl_seq *_loop0_124_rule(Parser *p); +static asdl_seq *_gather_123_rule(Parser *p); +static void *_tmp_125_rule(Parser *p); static asdl_seq *_loop0_127_rule(Parser *p); static asdl_seq *_gather_126_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_133_rule(Parser *p); +static asdl_seq *_gather_132_rule(Parser *p); static asdl_seq *_loop0_134_rule(Parser *p); -static asdl_seq *_gather_133_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_136_rule(Parser *p); +static asdl_seq *_gather_135_rule(Parser *p); +static asdl_seq *_loop1_137_rule(Parser *p); +static void *_tmp_138_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); @@ -974,8 +987,8 @@ 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 asdl_seq *_loop0_148_rule(Parser *p); +static asdl_seq *_gather_147_rule(Parser *p); static void *_tmp_149_rule(Parser *p); static void *_tmp_150_rule(Parser *p); static void *_tmp_151_rule(Parser *p); @@ -986,64 +999,64 @@ 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 asdl_seq *_loop0_159_rule(Parser *p); -static asdl_seq *_loop0_160_rule(Parser *p); +static void *_tmp_159_rule(Parser *p); +static void *_tmp_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 asdl_seq *_loop0_162_rule(Parser *p); +static asdl_seq *_loop0_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 asdl_seq *_loop0_168_rule(Parser *p); +static void *_tmp_167_rule(Parser *p); +static void *_tmp_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 asdl_seq *_loop0_172_rule(Parser *p); +static asdl_seq *_loop0_170_rule(Parser *p); +static asdl_seq *_loop0_171_rule(Parser *p); +static asdl_seq *_loop1_172_rule(Parser *p); static void *_tmp_173_rule(Parser *p); static asdl_seq *_loop0_174_rule(Parser *p); -static asdl_seq *_loop1_175_rule(Parser *p); -static void *_tmp_176_rule(Parser *p); -static void *_tmp_177_rule(Parser *p); +static void *_tmp_175_rule(Parser *p); +static asdl_seq *_loop0_176_rule(Parser *p); +static asdl_seq *_loop1_177_rule(Parser *p); static void *_tmp_178_rule(Parser *p); -static asdl_seq *_loop0_179_rule(Parser *p); +static void *_tmp_179_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 asdl_seq *_loop0_181_rule(Parser *p); +static void *_tmp_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 asdl_seq *_loop1_184_rule(Parser *p); +static void *_tmp_185_rule(Parser *p); static asdl_seq *_loop0_186_rule(Parser *p); +static asdl_seq *_loop0_187_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 asdl_seq *_gather_189_rule(Parser *p); static void *_tmp_191_rule(Parser *p); static asdl_seq *_loop0_192_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 void *_tmp_193_rule(Parser *p); +static asdl_seq *_loop0_194_rule(Parser *p); +static asdl_seq *_loop1_195_rule(Parser *p); +static asdl_seq *_loop1_196_rule(Parser *p); +static void *_tmp_197_rule(Parser *p); static void *_tmp_198_rule(Parser *p); -static void *_tmp_199_rule(Parser *p); +static asdl_seq *_loop0_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 void *_tmp_201_rule(Parser *p); +static void *_tmp_202_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 *_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 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 asdl_seq *_gather_209_rule(Parser *p); +static void *_tmp_211_rule(Parser *p); +static asdl_seq *_loop0_212_rule(Parser *p); +static asdl_seq *_loop1_213_rule(Parser *p); +static void *_tmp_214_rule(Parser *p); +static asdl_seq *_loop0_215_rule(Parser *p); +static asdl_seq *_loop1_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); @@ -1052,10 +1065,10 @@ 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 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_225_rule(Parser *p); +static void *_tmp_226_rule(Parser *p); +static asdl_seq *_loop0_228_rule(Parser *p); +static asdl_seq *_gather_227_rule(Parser *p); static void *_tmp_229_rule(Parser *p); static void *_tmp_230_rule(Parser *p); static void *_tmp_231_rule(Parser *p); @@ -1067,9 +1080,9 @@ 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 asdl_seq *_loop0_240_rule(Parser *p); +static void *_tmp_240_rule(Parser *p); static void *_tmp_241_rule(Parser *p); -static void *_tmp_242_rule(Parser *p); +static asdl_seq *_loop0_242_rule(Parser *p); static void *_tmp_243_rule(Parser *p); static void *_tmp_244_rule(Parser *p); static void *_tmp_245_rule(Parser *p); @@ -1100,6 +1113,8 @@ 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); +static void *_tmp_273_rule(Parser *p); +static void *_tmp_274_rule(Parser *p); // file: statements? $ @@ -1681,6 +1696,7 @@ simple_stmts_rule(Parser *p) // simple_stmt: // | assignment +// | &"type" type_alias // | star_expressions // | &'return' return_stmt // | &('import' | 'from') import_stmt @@ -1738,6 +1754,27 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c%s simple_stmt[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment")); } + { // &"type" type_alias + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&\"type\" type_alias")); + stmt_ty type_alias_var; + if ( + _PyPegen_lookahead_with_string(1, _PyPegen_expect_soft_keyword, p, "type") + && + (type_alias_var = type_alias_rule(p)) // type_alias + ) + { + D(fprintf(stderr, "%*c+ simple_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&\"type\" type_alias")); + _res = type_alias_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s simple_stmt[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&\"type\" type_alias")); + } { // star_expressions if (p->error_indicator) { p->level--; @@ -4308,7 +4345,9 @@ class_def_rule(Parser *p) return _res; } -// class_def_raw: invalid_class_def_raw | 'class' NAME ['(' arguments? ')'] ':' block +// class_def_raw: +// | invalid_class_def_raw +// | 'class' NAME type_params? ['(' arguments? ')'] ':' block static stmt_ty class_def_raw_rule(Parser *p) { @@ -4350,22 +4389,25 @@ class_def_raw_rule(Parser *p) D(fprintf(stderr, "%*c%s class_def_raw[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_class_def_raw")); } - { // 'class' NAME ['(' arguments? ')'] ':' block + { // 'class' NAME type_params? ['(' arguments? ')'] ':' block if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> class_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class' NAME ['(' arguments? ')'] ':' block")); + D(fprintf(stderr, "%*c> class_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] ':' block")); Token * _keyword; Token * _literal; expr_ty a; void *b; asdl_stmt_seq* c; + void *t; if ( (_keyword = _PyPegen_expect_token(p, 654)) // token='class' && (a = _PyPegen_name_token(p)) // NAME && + (t = type_params_rule(p), !p->error_indicator) // type_params? + && (b = _tmp_34_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' @@ -4373,7 +4415,7 @@ class_def_raw_rule(Parser *p) (c = block_rule(p)) // block ) { - D(fprintf(stderr, "%*c+ class_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class' NAME ['(' arguments? ')'] ':' block")); + D(fprintf(stderr, "%*c+ class_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] ':' block")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -4383,7 +4425,7 @@ class_def_raw_rule(Parser *p) 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 = _PyAST_ClassDef ( a -> v . Name . id , ( b ) ? ( ( expr_ty ) b ) -> v . Call . args : NULL , ( b ) ? ( ( expr_ty ) b ) -> v . Call . keywords : NULL , c , NULL , EXTRA ); + _res = _PyAST_ClassDef ( a -> v . Name . id , t , ( b ) ? ( ( expr_ty ) b ) -> v . Call . args : NULL , ( b ) ? ( ( expr_ty ) b ) -> v . Call . keywords : NULL , c , NULL , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -4393,7 +4435,7 @@ class_def_raw_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s class_def_raw[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class' NAME ['(' arguments? ')'] ':' block")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class' NAME type_params? ['(' arguments? ')'] ':' block")); } _res = NULL; done: @@ -4469,8 +4511,8 @@ function_def_rule(Parser *p) // function_def_raw: // | invalid_def_raw -// | 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block -// | ASYNC 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block +// | 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block +// | ASYNC 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block static stmt_ty function_def_raw_rule(Parser *p) { @@ -4512,12 +4554,12 @@ function_def_raw_rule(Parser *p) D(fprintf(stderr, "%*c%s function_def_raw[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_def_raw")); } - { // 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block + { // 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> function_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); + D(fprintf(stderr, "%*c> function_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); Token * _keyword; Token * _literal; Token * _literal_1; @@ -4526,12 +4568,15 @@ function_def_raw_rule(Parser *p) asdl_stmt_seq* b; expr_ty n; void *params; + void *t; void *tc; if ( (_keyword = _PyPegen_expect_token(p, 652)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && + (t = type_params_rule(p), !p->error_indicator) // type_params? + && (_literal = _PyPegen_expect_forced_token(p, 7, "(")) // forced_token='(' && (params = params_rule(p), !p->error_indicator) // params? @@ -4547,7 +4592,7 @@ function_def_raw_rule(Parser *p) (b = block_rule(p)) // block ) { - D(fprintf(stderr, "%*c+ function_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); + D(fprintf(stderr, "%*c+ function_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -4557,7 +4602,7 @@ function_def_raw_rule(Parser *p) 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 = _PyAST_FunctionDef ( n -> v . Name . id , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ); + _res = _PyAST_FunctionDef ( n -> v . Name . id , t , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -4567,14 +4612,14 @@ function_def_raw_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s function_def_raw[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); } - { // ASYNC 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block + { // ASYNC 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> function_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); + D(fprintf(stderr, "%*c> function_def_raw[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); Token * _keyword; Token * _literal; Token * _literal_1; @@ -4584,6 +4629,7 @@ function_def_raw_rule(Parser *p) asdl_stmt_seq* b; expr_ty n; void *params; + void *t; void *tc; if ( (async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC' @@ -4592,6 +4638,8 @@ function_def_raw_rule(Parser *p) && (n = _PyPegen_name_token(p)) // NAME && + (t = type_params_rule(p), !p->error_indicator) // type_params? + && (_literal = _PyPegen_expect_forced_token(p, 7, "(")) // forced_token='(' && (params = params_rule(p), !p->error_indicator) // params? @@ -4607,7 +4655,7 @@ function_def_raw_rule(Parser *p) (b = block_rule(p)) // block ) { - D(fprintf(stderr, "%*c+ function_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); + D(fprintf(stderr, "%*c+ function_def_raw[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -4617,7 +4665,7 @@ function_def_raw_rule(Parser *p) 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 = CHECK_VERSION ( stmt_ty , 5 , "Async functions are" , _PyAST_AsyncFunctionDef ( n -> v . Name . id , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ) ); + _res = CHECK_VERSION ( stmt_ty , 5 , "Async functions are" , _PyAST_AsyncFunctionDef ( n -> v . Name . id , t , ( params ) ? params : CHECK ( arguments_ty , _PyPegen_empty_arguments ( p ) ) , b , NULL , a , NEW_TYPE_COMMENT ( p , tc ) , EXTRA ) ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -4627,7 +4675,7 @@ function_def_raw_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s function_def_raw[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC 'def' NAME &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC 'def' NAME type_params? &&'(' params? ')' ['->' expression] &&':' func_type_comment? block")); } _res = NULL; done: @@ -10530,6 +10578,438 @@ keyword_pattern_rule(Parser *p) return _res; } +// type_alias: "type" NAME type_params? '=' expression +static stmt_ty +type_alias_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + stmt_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 + { // "type" NAME type_params? '=' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_alias[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "\"type\" NAME type_params? '=' expression")); + expr_ty _keyword; + Token * _literal; + expr_ty b; + expr_ty n; + void *t; + if ( + (_keyword = _PyPegen_expect_soft_keyword(p, "type")) // soft_keyword='"type"' + && + (n = _PyPegen_name_token(p)) // NAME + && + (t = type_params_rule(p), !p->error_indicator) // type_params? + && + (_literal = _PyPegen_expect_token(p, 22)) // token='=' + && + (b = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ type_alias[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "\"type\" NAME type_params? '=' expression")); + 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 = CHECK_VERSION ( stmt_ty , 12 , "Type statement is" , _PyAST_TypeAlias ( CHECK ( expr_ty , _PyPegen_set_expr_context ( p , n , Store ) ) , t , b , EXTRA ) ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_alias[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\"type\" NAME type_params? '=' expression")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// type_params: '[' type_param_seq ']' +static asdl_typeparam_seq* +type_params_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_typeparam_seq* _res = NULL; + int _mark = p->mark; + { // '[' type_param_seq ']' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_params[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' type_param_seq ']'")); + Token * _literal; + Token * _literal_1; + asdl_typeparam_seq* t; + if ( + (_literal = _PyPegen_expect_token(p, 9)) // token='[' + && + (t = type_param_seq_rule(p)) // type_param_seq + && + (_literal_1 = _PyPegen_expect_token(p, 10)) // token=']' + ) + { + D(fprintf(stderr, "%*c+ type_params[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' type_param_seq ']'")); + _res = CHECK_VERSION ( asdl_typeparam_seq* , 12 , "Type parameter lists are" , t ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_params[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' type_param_seq ']'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// type_param_seq: ','.type_param+ ','? +static asdl_typeparam_seq* +type_param_seq_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_typeparam_seq* _res = NULL; + int _mark = p->mark; + { // ','.type_param+ ','? + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.type_param+ ','?")); + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + asdl_typeparam_seq* a; + if ( + (a = (asdl_typeparam_seq*)_gather_81_rule(p)) // ','.type_param+ + && + (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? + ) + { + D(fprintf(stderr, "%*c+ type_param_seq[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.type_param+ ','?")); + _res = a; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param_seq[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.type_param+ ','?")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// type_param: +// | NAME type_param_bound? +// | '*' NAME ":" expression +// | '*' NAME +// | '**' NAME ":" expression +// | '**' NAME +static typeparam_ty +type_param_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + typeparam_ty _res = NULL; + if (_PyPegen_is_memoized(p, type_param_type, &_res)) { + p->level--; + return _res; + } + 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 + { // NAME type_param_bound? + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME type_param_bound?")); + expr_ty a; + void *b; + if ( + (a = _PyPegen_name_token(p)) // NAME + && + (b = type_param_bound_rule(p), !p->error_indicator) // type_param_bound? + ) + { + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME type_param_bound?")); + 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 = _PyAST_TypeVar ( a -> v . Name . id , b , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME type_param_bound?")); + } + { // '*' NAME ":" expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' NAME \":\" expression")); + Token * _literal; + expr_ty a; + Token * colon; + expr_ty e; + if ( + (_literal = _PyPegen_expect_token(p, 16)) // token='*' + && + (a = _PyPegen_name_token(p)) // NAME + && + (colon = _PyPegen_expect_token(p, 11)) // token=':' + && + (e = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' NAME \":\" expression")); + _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( colon , e -> kind == Tuple_kind ? "cannot use constraints with TypeVarTuple" : "cannot use bound with TypeVarTuple" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' NAME \":\" expression")); + } + { // '*' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' NAME")); + Token * _literal; + expr_ty a; + if ( + (_literal = _PyPegen_expect_token(p, 16)) // token='*' + && + (a = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' NAME")); + 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 = _PyAST_TypeVarTuple ( a -> v . Name . id , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' NAME")); + } + { // '**' NAME ":" expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' NAME \":\" expression")); + Token * _literal; + expr_ty a; + Token * colon; + expr_ty e; + if ( + (_literal = _PyPegen_expect_token(p, 35)) // token='**' + && + (a = _PyPegen_name_token(p)) // NAME + && + (colon = _PyPegen_expect_token(p, 11)) // token=':' + && + (e = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' NAME \":\" expression")); + _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( colon , e -> kind == Tuple_kind ? "cannot use constraints with ParamSpec" : "cannot use bound with ParamSpec" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' NAME \":\" expression")); + } + { // '**' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' NAME")); + Token * _literal; + expr_ty a; + if ( + (_literal = _PyPegen_expect_token(p, 35)) // token='**' + && + (a = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ type_param[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' NAME")); + 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 = _PyAST_ParamSpec ( a -> v . Name . id , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' NAME")); + } + _res = NULL; + done: + _PyPegen_insert_memo(p, _mark, type_param_type, _res); + p->level--; + return _res; +} + +// type_param_bound: ":" expression +static expr_ty +type_param_bound_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; + { // ":" expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> type_param_bound[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "\":\" expression")); + Token * _literal; + expr_ty e; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (e = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ type_param_bound[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "\":\" expression")); + _res = e; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s type_param_bound[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\":\" expression")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // expressions: expression ((',' expression))+ ','? | expression ',' | expression static expr_ty expressions_rule(Parser *p) @@ -10566,7 +11046,7 @@ expressions_rule(Parser *p) if ( (a = expression_rule(p)) // expression && - (b = _loop1_81_rule(p)) // ((',' expression))+ + (b = _loop1_83_rule(p)) // ((',' expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -10957,7 +11437,7 @@ star_expressions_rule(Parser *p) if ( (a = star_expression_rule(p)) // star_expression && - (b = _loop1_82_rule(p)) // ((',' star_expression))+ + (b = _loop1_84_rule(p)) // ((',' star_expression))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11158,7 +11638,7 @@ star_named_expressions_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_83_rule(p)) // ','.star_named_expression+ + (a = (asdl_expr_seq*)_gather_85_rule(p)) // ','.star_named_expression+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -11458,7 +11938,7 @@ disjunction_rule(Parser *p) if ( (a = conjunction_rule(p)) // conjunction && - (b = _loop1_85_rule(p)) // (('or' conjunction))+ + (b = _loop1_87_rule(p)) // (('or' conjunction))+ ) { D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+")); @@ -11547,7 +12027,7 @@ conjunction_rule(Parser *p) if ( (a = inversion_rule(p)) // inversion && - (b = _loop1_86_rule(p)) // (('and' inversion))+ + (b = _loop1_88_rule(p)) // (('and' inversion))+ ) { D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+")); @@ -11721,7 +12201,7 @@ comparison_rule(Parser *p) if ( (a = bitwise_or_rule(p)) // bitwise_or && - (b = _loop1_87_rule(p)) // compare_op_bitwise_or_pair+ + (b = _loop1_89_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+")); @@ -12058,10 +12538,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_88_var; + void *_tmp_90_var; expr_ty a; if ( - (_tmp_88_var = _tmp_88_rule(p)) // '!=' + (_tmp_90_var = _tmp_90_rule(p)) // '!=' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -14096,7 +14576,7 @@ slices_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_89_rule(p)) // ','.(slice | starred_expression)+ + (a = (asdl_expr_seq*)_gather_91_rule(p)) // ','.(slice | starred_expression)+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -14169,7 +14649,7 @@ slice_rule(Parser *p) && (b = expression_rule(p), !p->error_indicator) // expression? && - (c = _tmp_91_rule(p), !p->error_indicator) // [':' expression?] + (c = _tmp_93_rule(p), !p->error_indicator) // [':' expression?] ) { D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]")); @@ -14383,7 +14863,7 @@ atom_rule(Parser *p) 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, _tmp_92_rule, p) + _PyPegen_lookahead(1, _tmp_94_rule, p) && (strings_var = strings_rule(p)) // strings ) @@ -14421,15 +14901,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_93_var; + void *_tmp_95_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='(' && - (_tmp_93_var = _tmp_93_rule(p)) // tuple | group | genexp + (_tmp_95_var = _tmp_95_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_93_var; + _res = _tmp_95_var; goto done; } p->mark = _mark; @@ -14442,15 +14922,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_94_var; + void *_tmp_96_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' && - (_tmp_94_var = _tmp_94_rule(p)) // list | listcomp + (_tmp_96_var = _tmp_96_rule(p)) // list | listcomp ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - _res = _tmp_94_var; + _res = _tmp_96_var; goto done; } p->mark = _mark; @@ -14463,15 +14943,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_95_var; + void *_tmp_97_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' && - (_tmp_95_var = _tmp_95_rule(p)) // dict | set | dictcomp | setcomp + (_tmp_97_var = _tmp_97_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_95_var; + _res = _tmp_97_var; goto done; } p->mark = _mark; @@ -14543,7 +15023,7 @@ group_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_96_rule(p)) // yield_expr | named_expression + (a = _tmp_98_rule(p)) // yield_expr | named_expression && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -14747,9 +15227,9 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default && - (b = (asdl_arg_seq*)_loop0_97_rule(p)) // lambda_param_no_default* + (b = (asdl_arg_seq*)_loop0_99_rule(p)) // lambda_param_no_default* && - (c = _loop0_98_rule(p)) // lambda_param_with_default* + (c = _loop0_100_rule(p)) // lambda_param_with_default* && (d = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14779,7 +15259,7 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_with_default_rule(p)) // lambda_slash_with_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? ) @@ -14807,9 +15287,9 @@ lambda_parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_100_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_102_rule(p)) // lambda_param_no_default+ && - (b = _loop0_101_rule(p)) // lambda_param_with_default* + (b = _loop0_103_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14836,7 +15316,7 @@ lambda_parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_102_rule(p)) // lambda_param_with_default+ + (a = _loop1_104_rule(p)) // lambda_param_with_default+ && (b = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -14910,7 +15390,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_103_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_105_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -14939,7 +15419,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_104_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_106_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -14992,9 +15472,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='/' && @@ -15024,9 +15504,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_107_rule(p)) // lambda_param_no_default* + (a = _loop0_109_rule(p)) // lambda_param_no_default* && - (b = _loop1_108_rule(p)) // lambda_param_with_default+ + (b = _loop1_110_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15104,7 +15584,7 @@ lambda_star_etc_rule(Parser *p) && (a = lambda_param_no_default_rule(p)) // lambda_param_no_default && - (b = _loop0_109_rule(p)) // lambda_param_maybe_default* + (b = _loop0_111_rule(p)) // lambda_param_maybe_default* && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15137,7 +15617,7 @@ lambda_star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_110_rule(p)) // lambda_param_maybe_default+ + (b = _loop1_112_rule(p)) // lambda_param_maybe_default+ && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15647,7 +16127,7 @@ fstring_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (a = _tmp_111_rule(p)) // yield_expr | star_expressions + (a = _tmp_113_rule(p)) // yield_expr | star_expressions && (debug_expr = _PyPegen_expect_token(p, 22), !p->error_indicator) // "="? && @@ -15786,7 +16266,7 @@ fstring_full_format_spec_rule(Parser *p) if ( (colon = _PyPegen_expect_token(p, 11)) // token=':' && - (spec = _loop0_112_rule(p)) // fstring_format_spec* + (spec = _loop0_114_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*")); @@ -15959,7 +16439,7 @@ strings_rule(Parser *p) D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_113_rule(p)) // ((fstring | string))+ + (a = (asdl_expr_seq*)_loop1_115_rule(p)) // ((fstring | string))+ ) { D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); @@ -16094,7 +16574,7 @@ tuple_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_114_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] + (a = _tmp_116_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -16312,7 +16792,7 @@ double_starred_kvpairs_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_115_rule(p)) // ','.double_starred_kvpair+ + (a = _gather_117_rule(p)) // ','.double_starred_kvpair+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -16474,7 +16954,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_117_rule(p)) // for_if_clause+ + (a = (asdl_comprehension_seq*)_loop1_119_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+")); @@ -16539,7 +17019,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_118_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_120_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))*")); @@ -16582,7 +17062,7 @@ for_if_clause_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_119_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_121_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))*")); @@ -16845,7 +17325,7 @@ genexp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_120_rule(p)) // assignment_expression | expression !':=' + (a = _tmp_122_rule(p)) // assignment_expression | expression !':=' && (b = for_if_clauses_rule(p)) // for_if_clauses && @@ -17097,9 +17577,9 @@ args_rule(Parser *p) asdl_expr_seq* a; void *b; if ( - (a = (asdl_expr_seq*)_gather_121_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (a = (asdl_expr_seq*)_gather_123_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && - (b = _tmp_123_rule(p), !p->error_indicator) // [',' kwargs] + (b = _tmp_125_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]")); @@ -17190,11 +17670,11 @@ kwargs_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _gather_124_rule(p)) // ','.kwarg_or_starred+ + (a = _gather_126_rule(p)) // ','.kwarg_or_starred+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _gather_126_rule(p)) // ','.kwarg_or_double_starred+ + (b = _gather_128_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+")); @@ -17216,13 +17696,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_128_var; + asdl_seq * _gather_130_var; if ( - (_gather_128_var = _gather_128_rule(p)) // ','.kwarg_or_starred+ + (_gather_130_var = _gather_130_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_128_var; + _res = _gather_130_var; goto done; } p->mark = _mark; @@ -17235,13 +17715,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_130_var; + asdl_seq * _gather_132_var; if ( - (_gather_130_var = _gather_130_rule(p)) // ','.kwarg_or_double_starred+ + (_gather_132_var = _gather_132_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_130_var; + _res = _gather_132_var; goto done; } p->mark = _mark; @@ -17634,7 +18114,7 @@ star_targets_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop0_132_rule(p)) // ((',' star_target))* + (b = _loop0_134_rule(p)) // ((',' star_target))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17691,7 +18171,7 @@ star_targets_list_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_133_rule(p)) // ','.star_target+ + (a = (asdl_expr_seq*)_gather_135_rule(p)) // ','.star_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17742,7 +18222,7 @@ star_targets_tuple_seq_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop1_135_rule(p)) // ((',' star_target))+ + (b = _loop1_137_rule(p)) // ((',' star_target))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17831,7 +18311,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_136_rule(p)) // !'*' star_target + (a = _tmp_138_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -18762,7 +19242,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_137_rule(p)) // ','.del_target+ + (a = (asdl_expr_seq*)_gather_139_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -19123,7 +19603,7 @@ type_expressions_rule(Parser *p) expr_ty b; expr_ty c; if ( - (a = _gather_139_rule(p)) // ','.expression+ + (a = _gather_141_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19162,7 +19642,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_141_rule(p)) // ','.expression+ + (a = _gather_143_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19195,7 +19675,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_143_rule(p)) // ','.expression+ + (a = _gather_145_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -19315,7 +19795,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_145_rule(p)) // ','.expression+ + (a = (asdl_expr_seq*)_gather_147_rule(p)) // ','.expression+ ) { D(fprintf(stderr, "%*c+ type_expressions[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.expression+")); @@ -19367,7 +19847,7 @@ func_type_comment_rule(Parser *p) && (t = _PyPegen_expect_token(p, TYPE_COMMENT)) // token='TYPE_COMMENT' && - _PyPegen_lookahead(1, _tmp_147_rule, p) + _PyPegen_lookahead(1, _tmp_149_rule, p) ) { D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)")); @@ -19496,7 +19976,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_148_rule(p), !p->error_indicator) // [args | expression for_if_clauses] + (_opt_var = _tmp_150_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]")); @@ -19556,13 +20036,13 @@ invalid_arguments_rule(Parser *p) expr_ty a; Token * b; if ( - (_opt_var = _tmp_149_rule(p), !p->error_indicator) // [(args ',')] + (_opt_var = _tmp_151_rule(p), !p->error_indicator) // [(args ',')] && (a = _PyPegen_name_token(p)) // NAME && (b = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_150_rule, p) + _PyPegen_lookahead(1, _tmp_152_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')")); @@ -19701,7 +20181,7 @@ invalid_kwarg_rule(Parser *p) Token* a; Token * b; if ( - (a = (Token*)_tmp_151_rule(p)) // 'True' | 'False' | 'None' + (a = (Token*)_tmp_153_rule(p)) // 'True' | 'False' | 'None' && (b = _PyPegen_expect_token(p, 22)) // token='=' ) @@ -19761,7 +20241,7 @@ invalid_kwarg_rule(Parser *p) expr_ty a; Token * b; if ( - _PyPegen_lookahead(0, _tmp_152_rule, p) + _PyPegen_lookahead(0, _tmp_154_rule, p) && (a = expression_rule(p)) // expression && @@ -20020,7 +20500,7 @@ invalid_expression_rule(Parser *p) expr_ty a; expr_ty b; if ( - _PyPegen_lookahead(0, _tmp_153_rule, p) + _PyPegen_lookahead(0, _tmp_155_rule, p) && (a = disjunction_rule(p)) // disjunction && @@ -20056,7 +20536,7 @@ invalid_expression_rule(Parser *p) && (b = disjunction_rule(p)) // disjunction && - _PyPegen_lookahead(0, _tmp_154_rule, p) + _PyPegen_lookahead(0, _tmp_156_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); @@ -20089,7 +20569,7 @@ invalid_expression_rule(Parser *p) && (b = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_155_rule, p) + _PyPegen_lookahead(1, _tmp_157_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)")); @@ -20178,7 +20658,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_156_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, "NAME '=' bitwise_or !('=' | ':=')")); @@ -20204,7 +20684,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, _tmp_157_rule, p) + _PyPegen_lookahead(0, _tmp_159_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -20212,7 +20692,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_158_rule, p) + _PyPegen_lookahead(0, _tmp_160_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 !('=' | ':=')")); @@ -20293,7 +20773,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_159_var; + asdl_seq * _loop0_161_var; expr_ty a; expr_ty expression_var; if ( @@ -20301,7 +20781,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_159_var = _loop0_159_rule(p)) // star_named_expressions* + (_loop0_161_var = _loop0_161_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -20358,10 +20838,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_160_var; + asdl_seq * _loop0_162_var; expr_ty a; if ( - (_loop0_160_var = _loop0_160_rule(p)) // ((star_targets '='))* + (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -20388,10 +20868,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_161_var; + asdl_seq * _loop0_163_var; expr_ty a; if ( - (_loop0_161_var = _loop0_161_rule(p)) // ((star_targets '='))* + (_loop0_163_var = _loop0_163_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -20417,7 +20897,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_162_var; + void *_tmp_164_var; expr_ty a; AugOperator* augassign_var; if ( @@ -20425,7 +20905,7 @@ invalid_assignment_rule(Parser *p) && (augassign_var = augassign_rule(p)) // augassign && - (_tmp_162_var = _tmp_162_rule(p)) // yield_expr | star_expressions + (_tmp_164_var = _tmp_164_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)")); @@ -20651,11 +21131,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_163_var; + void *_tmp_165_var; expr_ty a; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_163_var = _tmp_163_rule(p)) // '[' | '(' | '{' + (_tmp_165_var = _tmp_165_rule(p)) // '[' | '(' | '{' && (a = starred_expression_rule(p)) // starred_expression && @@ -20682,12 +21162,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_164_var; + void *_tmp_166_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_164_var = _tmp_164_rule(p)) // '[' | '{' + (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20717,12 +21197,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_165_var; + void *_tmp_167_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_165_var = _tmp_165_rule(p)) // '[' | '{' + (_tmp_167_var = _tmp_167_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -20859,13 +21339,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_167_var; - void *_tmp_166_var; + asdl_seq * _loop0_169_var; + void *_tmp_168_var; Token * a; if ( - (_tmp_166_var = _tmp_166_rule(p)) // slash_no_default | slash_with_default + (_tmp_168_var = _tmp_168_rule(p)) // slash_no_default | slash_with_default && - (_loop0_167_var = _loop0_167_rule(p)) // param_maybe_default* + (_loop0_169_var = _loop0_169_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -20889,7 +21369,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_168_var; + asdl_seq * _loop0_170_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -20897,7 +21377,7 @@ invalid_parameters_rule(Parser *p) if ( (_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default? && - (_loop0_168_var = _loop0_168_rule(p)) // param_no_default* + (_loop0_170_var = _loop0_170_rule(p)) // param_no_default* && (invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper && @@ -20923,18 +21403,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_169_var; - asdl_seq * _loop1_170_var; + asdl_seq * _loop0_171_var; + asdl_seq * _loop1_172_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_169_var = _loop0_169_rule(p)) // param_no_default* + (_loop0_171_var = _loop0_171_rule(p)) // param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_loop1_170_var = _loop1_170_rule(p)) // param_no_default+ + (_loop1_172_var = _loop1_172_rule(p)) // param_no_default+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -20961,22 +21441,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_172_var; asdl_seq * _loop0_174_var; + asdl_seq * _loop0_176_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_173_var; + void *_tmp_175_var; Token * a; if ( - (_opt_var = _tmp_171_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_173_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && - (_loop0_172_var = _loop0_172_rule(p)) // param_maybe_default* + (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_173_var = _tmp_173_rule(p)) // ',' | param_no_default + (_tmp_175_var = _tmp_175_rule(p)) // ',' | param_no_default && - (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default* + (_loop0_176_var = _loop0_176_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21001,10 +21481,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_175_var; + asdl_seq * _loop1_177_var; Token * a; if ( - (_loop1_175_var = _loop1_175_rule(p)) // param_maybe_default+ + (_loop1_177_var = _loop1_177_rule(p)) // param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21054,7 +21534,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_176_rule, p) + _PyPegen_lookahead(1, _tmp_178_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -21100,12 +21580,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_177_var; + void *_tmp_179_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_177_var = _tmp_177_rule(p)) // ')' | ',' (')' | '**') + (_tmp_179_var = _tmp_179_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -21188,20 +21668,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_179_var; - void *_tmp_178_var; + asdl_seq * _loop0_181_var; void *_tmp_180_var; + void *_tmp_182_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_178_var = _tmp_178_rule(p)) // param_no_default | ',' + (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ',' && - (_loop0_179_var = _loop0_179_rule(p)) // param_maybe_default* + (_loop0_181_var = _loop0_181_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ',' + (_tmp_182_var = _tmp_182_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 | ',')")); @@ -21317,7 +21797,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_181_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_183_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -21383,13 +21863,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_182_var; + asdl_seq * _loop1_184_var; if ( - (_loop1_182_var = _loop1_182_rule(p)) // param_with_default+ + (_loop1_184_var = _loop1_184_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_182_var; + _res = _loop1_184_var; goto done; } p->mark = _mark; @@ -21455,13 +21935,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_184_var; - void *_tmp_183_var; + asdl_seq * _loop0_186_var; + void *_tmp_185_var; Token * a; if ( - (_tmp_183_var = _tmp_183_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_185_var = _tmp_185_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_184_var = _loop0_184_rule(p)) // lambda_param_maybe_default* + (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21485,7 +21965,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_185_var; + asdl_seq * _loop0_187_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -21493,7 +21973,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_185_var = _loop0_185_rule(p)) // lambda_param_no_default* + (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -21519,18 +21999,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_187_var; - asdl_seq * _loop0_186_var; + asdl_seq * _gather_189_var; + asdl_seq * _loop0_188_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_no_default* + (_loop0_188_var = _loop0_188_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_187_var = _gather_187_rule(p)) // ','.lambda_param+ + (_gather_189_var = _gather_189_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -21557,22 +22037,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_190_var; asdl_seq * _loop0_192_var; + asdl_seq * _loop0_194_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_191_var; + void *_tmp_193_var; Token * a; if ( - (_opt_var = _tmp_189_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_191_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_190_var = _loop0_190_rule(p)) // lambda_param_maybe_default* + (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_191_var = _tmp_191_rule(p)) // ',' | lambda_param_no_default + (_tmp_193_var = _tmp_193_rule(p)) // ',' | lambda_param_no_default && - (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default* + (_loop0_194_var = _loop0_194_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -21597,10 +22077,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_193_var; + asdl_seq * _loop1_195_var; Token * a; if ( - (_loop1_193_var = _loop1_193_rule(p)) // lambda_param_maybe_default+ + (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -21672,13 +22152,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_194_var; + asdl_seq * _loop1_196_var; if ( - (_loop1_194_var = _loop1_194_rule(p)) // lambda_param_with_default+ + (_loop1_196_var = _loop1_196_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_194_var; + _res = _loop1_196_var; goto done; } p->mark = _mark; @@ -21715,11 +22195,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_195_var; + void *_tmp_197_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_195_var = _tmp_195_rule(p)) // ':' | ',' (':' | '**') + (_tmp_197_var = _tmp_197_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -21772,20 +22252,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_197_var; - void *_tmp_196_var; + asdl_seq * _loop0_199_var; void *_tmp_198_var; + void *_tmp_200_var; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_196_var = _tmp_196_rule(p)) // lambda_param_no_default | ',' + (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ',' && - (_loop0_197_var = _loop0_197_rule(p)) // lambda_param_maybe_default* + (_loop0_199_var = _loop0_199_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ',' + (_tmp_200_var = _tmp_200_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 | ',')")); @@ -21904,7 +22384,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_199_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_201_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -22012,7 +22492,7 @@ invalid_with_item_rule(Parser *p) && (a = expression_rule(p)) // expression && - _PyPegen_lookahead(1, _tmp_200_rule, p) + _PyPegen_lookahead(1, _tmp_202_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')")); @@ -22293,7 +22773,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_201_var; + asdl_seq * _gather_203_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22303,7 +22783,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_201_var = _gather_201_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_203_var = _gather_203_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22327,7 +22807,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_203_var; + asdl_seq * _gather_205_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22343,7 +22823,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_203_var = _gather_203_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_205_var = _gather_205_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22393,7 +22873,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_205_var; + asdl_seq * _gather_207_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22404,7 +22884,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_207_var = _gather_207_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22432,7 +22912,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_207_var; + asdl_seq * _gather_209_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22449,7 +22929,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_209_var = _gather_209_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22547,7 +23027,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_209_rule, p) + _PyPegen_lookahead(0, _tmp_211_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -22572,8 +23052,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_210_var; - asdl_seq * _loop1_211_var; + asdl_seq * _loop0_212_var; + asdl_seq * _loop1_213_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22584,9 +23064,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_210_var = _loop0_210_rule(p)) // block* + (_loop0_212_var = _loop0_212_rule(p)) // block* && - (_loop1_211_var = _loop1_211_rule(p)) // except_block+ + (_loop1_213_var = _loop1_213_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && @@ -22594,7 +23074,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_212_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_214_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22621,8 +23101,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_213_var; - asdl_seq * _loop1_214_var; + asdl_seq * _loop0_215_var; + asdl_seq * _loop1_216_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -22631,13 +23111,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_213_var = _loop0_213_rule(p)) // block* + (_loop0_215_var = _loop0_215_rule(p)) // block* && - (_loop1_214_var = _loop1_214_rule(p)) // except_star_block+ + (_loop1_216_var = _loop1_216_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_215_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_217_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22705,7 +23185,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_218_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -22743,7 +23223,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_217_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22795,14 +23275,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_218_var; + void *_tmp_220_var; Token * a; if ( (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_218_var = _tmp_218_rule(p)) // NEWLINE | ':' + (_tmp_220_var = _tmp_220_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -22909,7 +23389,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23004,7 +23484,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_222_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23373,7 +23853,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_221_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_223_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -23867,7 +24347,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_222_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_224_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23927,7 +24407,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_225_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23962,7 +24442,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_226_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24013,11 +24493,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_225_var; + asdl_seq * _gather_227_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_225_var = _gather_225_rule(p)) // ','.double_starred_kvpair+ + (_gather_227_var = _gather_227_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24025,7 +24505,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_225_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_227_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24078,7 +24558,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_227_rule, p) + _PyPegen_lookahead(1, _tmp_229_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24189,7 +24669,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_228_rule, p) + _PyPegen_lookahead(1, _tmp_230_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24407,7 +24887,7 @@ invalid_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - _PyPegen_lookahead(0, _tmp_229_rule, p) + _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)")); @@ -24430,13 +24910,13 @@ invalid_replacement_field_rule(Parser *p) } 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; + void *_tmp_232_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_230_var = _tmp_230_rule(p)) // yield_expr | star_expressions + (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions && - _PyPegen_lookahead(0, _tmp_231_rule, p) + _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) !('=' | '!' | ':' | '}')")); @@ -24460,15 +24940,15 @@ invalid_replacement_field_rule(Parser *p) 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; + void *_tmp_234_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions + (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_233_rule, p) + _PyPegen_lookahead(0, _tmp_235_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); @@ -24493,12 +24973,12 @@ invalid_replacement_field_rule(Parser *p) Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_234_var; + void *_tmp_236_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 + (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && @@ -24506,7 +24986,7 @@ invalid_replacement_field_rule(Parser *p) ) { 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); + _res = _PyPegen_dummy_name(p, _literal, _tmp_236_var, _opt_var, invalid_conversion_character_var); goto done; } p->mark = _mark; @@ -24524,17 +25004,17 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_235_var; + void *_tmp_237_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_235_var = _tmp_235_rule(p)) // yield_expr | star_expressions + (_tmp_237_var = _tmp_237_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] + (_opt_var_1 = _tmp_238_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_237_rule, p) + _PyPegen_lookahead(0, _tmp_239_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); @@ -24558,24 +25038,24 @@ invalid_replacement_field_rule(Parser *p) 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; + asdl_seq * _loop0_242_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; + void *_tmp_240_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions + (_tmp_240_var = _tmp_240_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] + (_opt_var_1 = _tmp_241_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_240_var = _loop0_240_rule(p)) // fstring_format_spec* + (_loop0_242_var = _loop0_242_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24604,15 +25084,15 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_241_var; + void *_tmp_243_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_241_var = _tmp_241_rule(p)) // yield_expr | star_expressions + (_tmp_243_var = _tmp_243_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] + (_opt_var_1 = _tmp_244_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -24660,7 +25140,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_243_rule, p) + _PyPegen_lookahead(1, _tmp_245_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -25605,12 +26085,12 @@ _loop1_15_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_244_var; + void *_tmp_246_var; while ( - (_tmp_244_var = _tmp_244_rule(p)) // star_targets '=' + (_tmp_246_var = _tmp_246_rule(p)) // star_targets '=' ) { - _res = _tmp_244_var; + _res = _tmp_246_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26184,12 +26664,12 @@ _loop0_25_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_245_var; + void *_tmp_247_var; while ( - (_tmp_245_var = _tmp_245_rule(p)) // '.' | '...' + (_tmp_247_var = _tmp_247_rule(p)) // '.' | '...' ) { - _res = _tmp_245_var; + _res = _tmp_247_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26252,12 +26732,12 @@ _loop1_26_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_246_var; + void *_tmp_248_var; while ( - (_tmp_246_var = _tmp_246_rule(p)) // '.' | '...' + (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...' ) { - _res = _tmp_246_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26657,12 +27137,12 @@ _loop1_33_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_247_var; + void *_tmp_249_var; while ( - (_tmp_247_var = _tmp_247_rule(p)) // '@' named_expression NEWLINE + (_tmp_249_var = _tmp_249_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_247_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29511,8 +29991,127 @@ _loop0_78_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' pattern")); + 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); + 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_77: pattern _loop0_78 +static asdl_seq * +_gather_77_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; + { // pattern _loop0_78 + if (p->error_indicator) { + p->level--; + return NULL; + } + 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_78_rule(p)) // _loop0_78 + ) + { + 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_77[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_78")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_80: ',' keyword_pattern +static asdl_seq * +_loop0_80_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; + { // ',' keyword_pattern + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); + Token * _literal; + KeyPatternPair* elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = keyword_pattern_rule(p)) // keyword_pattern + ) + { + _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_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); if (!_seq) { @@ -29528,9 +30127,9 @@ _loop0_78_rule(Parser *p) return _seq; } -// _gather_77: pattern _loop0_78 +// _gather_79: keyword_pattern _loop0_80 static asdl_seq * -_gather_77_rule(Parser *p) +_gather_79_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29542,27 +30141,27 @@ _gather_77_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // pattern _loop0_78 + { // keyword_pattern _loop0_80 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78")); - pattern_ty elem; + 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 = pattern_rule(p)) // pattern + (elem = keyword_pattern_rule(p)) // keyword_pattern && - (seq = _loop0_78_rule(p)) // _loop0_78 + (seq = _loop0_80_rule(p)) // _loop0_80 ) { - D(fprintf(stderr, "%*c+ _gather_77[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78")); + 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_77[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_78")); + 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: @@ -29570,9 +30169,9 @@ _gather_77_rule(Parser *p) return _res; } -// _loop0_80: ',' keyword_pattern +// _loop0_82: ',' type_param static asdl_seq * -_loop0_80_rule(Parser *p) +_loop0_82_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29593,18 +30192,18 @@ _loop0_80_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' keyword_pattern + { // ',' type_param if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern")); + D(fprintf(stderr, "%*c> _loop0_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param")); Token * _literal; - KeyPatternPair* elem; + typeparam_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = keyword_pattern_rule(p)) // keyword_pattern + (elem = type_param_rule(p)) // type_param ) { _res = elem; @@ -29630,8 +30229,8 @@ _loop0_80_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_80[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' keyword_pattern")); + D(fprintf(stderr, "%*c%s _loop0_82[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' type_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -29647,9 +30246,9 @@ _loop0_80_rule(Parser *p) return _seq; } -// _gather_79: keyword_pattern _loop0_80 +// _gather_81: type_param _loop0_82 static asdl_seq * -_gather_79_rule(Parser *p) +_gather_81_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29661,27 +30260,27 @@ _gather_79_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // keyword_pattern _loop0_80 + { // type_param _loop0_82 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80")); - KeyPatternPair* elem; + D(fprintf(stderr, "%*c> _gather_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82")); + typeparam_ty elem; asdl_seq * seq; if ( - (elem = keyword_pattern_rule(p)) // keyword_pattern + (elem = type_param_rule(p)) // type_param && - (seq = _loop0_80_rule(p)) // _loop0_80 + (seq = _loop0_82_rule(p)) // _loop0_82 ) { - D(fprintf(stderr, "%*c+ _gather_79[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80")); + D(fprintf(stderr, "%*c+ _gather_81[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_81[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_82")); } _res = NULL; done: @@ -29689,9 +30288,9 @@ _gather_79_rule(Parser *p) return _res; } -// _loop1_81: (',' expression) +// _loop1_83: (',' expression) static asdl_seq * -_loop1_81_rule(Parser *p) +_loop1_83_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29717,13 +30316,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, "(',' expression)")); - void *_tmp_248_var; + D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); + void *_tmp_250_var; while ( - (_tmp_248_var = _tmp_248_rule(p)) // ',' expression + (_tmp_250_var = _tmp_250_rule(p)) // ',' expression ) { - _res = _tmp_248_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29740,7 +30339,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_83[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' expression)")); } if (_n == 0 || p->error_indicator) { @@ -29762,9 +30361,9 @@ _loop1_81_rule(Parser *p) return _seq; } -// _loop1_82: (',' star_expression) +// _loop1_84: (',' star_expression) static asdl_seq * -_loop1_82_rule(Parser *p) +_loop1_84_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29790,13 +30389,13 @@ _loop1_82_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_249_var; + D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); + void *_tmp_251_var; while ( - (_tmp_249_var = _tmp_249_rule(p)) // ',' star_expression + (_tmp_251_var = _tmp_251_rule(p)) // ',' star_expression ) { - _res = _tmp_249_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -29813,7 +30412,7 @@ _loop1_82_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_82[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)")); } if (_n == 0 || p->error_indicator) { @@ -29835,9 +30434,9 @@ _loop1_82_rule(Parser *p) return _seq; } -// _loop0_84: ',' star_named_expression +// _loop0_86: ',' star_named_expression static asdl_seq * -_loop0_84_rule(Parser *p) +_loop0_86_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29863,7 +30462,7 @@ _loop0_84_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); + D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression")); Token * _literal; expr_ty elem; while ( @@ -29895,7 +30494,7 @@ _loop0_84_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_84[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_86[%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); @@ -29912,9 +30511,9 @@ _loop0_84_rule(Parser *p) return _seq; } -// _gather_83: star_named_expression _loop0_84 +// _gather_85: star_named_expression _loop0_86 static asdl_seq * -_gather_83_rule(Parser *p) +_gather_85_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29926,27 +30525,27 @@ _gather_83_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_named_expression _loop0_84 + { // star_named_expression _loop0_86 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_84")); + D(fprintf(stderr, "%*c> _gather_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); expr_ty elem; asdl_seq * seq; if ( (elem = star_named_expression_rule(p)) // star_named_expression && - (seq = _loop0_84_rule(p)) // _loop0_84 + (seq = _loop0_86_rule(p)) // _loop0_86 ) { - D(fprintf(stderr, "%*c+ _gather_83[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_84")); + D(fprintf(stderr, "%*c+ _gather_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_85[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_86")); } _res = NULL; done: @@ -29954,9 +30553,9 @@ _gather_83_rule(Parser *p) return _res; } -// _loop1_85: ('or' conjunction) +// _loop1_87: ('or' conjunction) static asdl_seq * -_loop1_85_rule(Parser *p) +_loop1_87_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -29982,13 +30581,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, "('or' conjunction)")); - void *_tmp_250_var; + D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); + void *_tmp_252_var; while ( - (_tmp_250_var = _tmp_250_rule(p)) // 'or' conjunction + (_tmp_252_var = _tmp_252_rule(p)) // 'or' conjunction ) { - _res = _tmp_250_var; + _res = _tmp_252_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30005,7 +30604,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_87[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } if (_n == 0 || p->error_indicator) { @@ -30027,9 +30626,9 @@ _loop1_85_rule(Parser *p) return _seq; } -// _loop1_86: ('and' inversion) +// _loop1_88: ('and' inversion) static asdl_seq * -_loop1_86_rule(Parser *p) +_loop1_88_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30055,13 +30654,13 @@ _loop1_86_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_251_var; + D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); + void *_tmp_253_var; while ( - (_tmp_251_var = _tmp_251_rule(p)) // 'and' inversion + (_tmp_253_var = _tmp_253_rule(p)) // 'and' inversion ) { - _res = _tmp_251_var; + _res = _tmp_253_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30078,7 +30677,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_88[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)")); } if (_n == 0 || p->error_indicator) { @@ -30100,9 +30699,9 @@ _loop1_86_rule(Parser *p) return _seq; } -// _loop1_87: compare_op_bitwise_or_pair +// _loop1_89: compare_op_bitwise_or_pair static asdl_seq * -_loop1_87_rule(Parser *p) +_loop1_89_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30128,7 +30727,7 @@ _loop1_87_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); + D(fprintf(stderr, "%*c> _loop1_89[%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 @@ -30151,7 +30750,7 @@ _loop1_87_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_89[%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) { @@ -30173,9 +30772,9 @@ _loop1_87_rule(Parser *p) return _seq; } -// _tmp_88: '!=' +// _tmp_90: '!=' static void * -_tmp_88_rule(Parser *p) +_tmp_90_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30192,13 +30791,13 @@ _tmp_88_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c> _tmp_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); Token * tok; if ( (tok = _PyPegen_expect_token(p, 28)) // token='!=' ) { - D(fprintf(stderr, "%*c+ _tmp_88[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c+ _tmp_90[%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; @@ -30208,7 +30807,7 @@ _tmp_88_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_88[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_90[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='")); } _res = NULL; @@ -30217,9 +30816,9 @@ _tmp_88_rule(Parser *p) return _res; } -// _loop0_90: ',' (slice | starred_expression) +// _loop0_92: ',' (slice | starred_expression) static asdl_seq * -_loop0_90_rule(Parser *p) +_loop0_92_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30245,13 +30844,13 @@ _loop0_90_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); + D(fprintf(stderr, "%*c> _loop0_92[%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_252_rule(p)) // slice | starred_expression + (elem = _tmp_254_rule(p)) // slice | starred_expression ) { _res = elem; @@ -30277,7 +30876,7 @@ _loop0_90_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_90[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_92[%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); @@ -30294,9 +30893,9 @@ _loop0_90_rule(Parser *p) return _seq; } -// _gather_89: (slice | starred_expression) _loop0_90 +// _gather_91: (slice | starred_expression) _loop0_92 static asdl_seq * -_gather_89_rule(Parser *p) +_gather_91_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30308,27 +30907,27 @@ _gather_89_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (slice | starred_expression) _loop0_90 + { // (slice | starred_expression) _loop0_92 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_90")); + D(fprintf(stderr, "%*c> _gather_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_92")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_252_rule(p)) // slice | starred_expression + (elem = _tmp_254_rule(p)) // slice | starred_expression && - (seq = _loop0_90_rule(p)) // _loop0_90 + (seq = _loop0_92_rule(p)) // _loop0_92 ) { - D(fprintf(stderr, "%*c+ _gather_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_90")); + D(fprintf(stderr, "%*c+ _gather_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_92")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_91[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_92")); } _res = NULL; done: @@ -30336,9 +30935,9 @@ _gather_89_rule(Parser *p) return _res; } -// _tmp_91: ':' expression? +// _tmp_93: ':' expression? static void * -_tmp_91_rule(Parser *p) +_tmp_93_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30355,7 +30954,7 @@ _tmp_91_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); Token * _literal; void *d; if ( @@ -30364,7 +30963,7 @@ _tmp_91_rule(Parser *p) (d = expression_rule(p), !p->error_indicator) // expression? ) { - D(fprintf(stderr, "%*c+ _tmp_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -30374,7 +30973,7 @@ _tmp_91_rule(Parser *p) 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, "':' expression?")); } _res = NULL; @@ -30383,9 +30982,9 @@ _tmp_91_rule(Parser *p) return _res; } -// _tmp_92: STRING | FSTRING_START +// _tmp_94: STRING | FSTRING_START static void * -_tmp_92_rule(Parser *p) +_tmp_94_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30402,18 +31001,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, "STRING")); + D(fprintf(stderr, "%*c> _tmp_94[%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")); + D(fprintf(stderr, "%*c+ _tmp_94[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING")); } { // FSTRING_START @@ -30421,18 +31020,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, "FSTRING_START")); + D(fprintf(stderr, "%*c> _tmp_94[%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")); + D(fprintf(stderr, "%*c+ _tmp_94[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START")); } _res = NULL; @@ -30441,9 +31040,9 @@ _tmp_92_rule(Parser *p) return _res; } -// _tmp_93: tuple | group | genexp +// _tmp_95: tuple | group | genexp static void * -_tmp_93_rule(Parser *p) +_tmp_95_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30460,18 +31059,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, "tuple")); + D(fprintf(stderr, "%*c> _tmp_95[%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_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_95[%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_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, "tuple")); } { // group @@ -30479,18 +31078,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, "group")); + D(fprintf(stderr, "%*c> _tmp_95[%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_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); + D(fprintf(stderr, "%*c+ _tmp_95[%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_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, "group")); } { // genexp @@ -30498,18 +31097,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, "genexp")); + D(fprintf(stderr, "%*c> _tmp_95[%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_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_95[%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_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, "genexp")); } _res = NULL; @@ -30518,9 +31117,9 @@ _tmp_93_rule(Parser *p) return _res; } -// _tmp_94: list | listcomp +// _tmp_96: list | listcomp static void * -_tmp_94_rule(Parser *p) +_tmp_96_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30537,18 +31136,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, "list")); + D(fprintf(stderr, "%*c> _tmp_96[%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_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_96[%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_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, "list")); } { // listcomp @@ -30556,18 +31155,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, "listcomp")); + D(fprintf(stderr, "%*c> _tmp_96[%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_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); + D(fprintf(stderr, "%*c+ _tmp_96[%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_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, "listcomp")); } _res = NULL; @@ -30576,9 +31175,9 @@ _tmp_94_rule(Parser *p) return _res; } -// _tmp_95: dict | set | dictcomp | setcomp +// _tmp_97: dict | set | dictcomp | setcomp static void * -_tmp_95_rule(Parser *p) +_tmp_97_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30595,18 +31194,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c> _tmp_97[%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_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); + D(fprintf(stderr, "%*c+ _tmp_97[%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_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); } { // set @@ -30614,18 +31213,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c> _tmp_97[%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_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); + D(fprintf(stderr, "%*c+ _tmp_97[%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_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); } { // dictcomp @@ -30633,18 +31232,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c> _tmp_97[%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_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); + D(fprintf(stderr, "%*c+ _tmp_97[%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_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); } { // setcomp @@ -30652,18 +31251,18 @@ _tmp_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c> _tmp_97[%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_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); + D(fprintf(stderr, "%*c+ _tmp_97[%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_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); } _res = NULL; @@ -30672,9 +31271,9 @@ _tmp_95_rule(Parser *p) return _res; } -// _tmp_96: yield_expr | named_expression +// _tmp_98: yield_expr | named_expression static void * -_tmp_96_rule(Parser *p) +_tmp_98_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30691,18 +31290,18 @@ _tmp_96_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_98[%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_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_98[%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_96[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // named_expression @@ -30710,18 +31309,18 @@ _tmp_96_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c> _tmp_98[%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_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c+ _tmp_98[%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_96[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression")); } _res = NULL; @@ -30730,9 +31329,9 @@ _tmp_96_rule(Parser *p) return _res; } -// _loop0_97: lambda_param_no_default +// _loop0_99: lambda_param_no_default static asdl_seq * -_loop0_97_rule(Parser *p) +_loop0_99_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30758,7 +31357,7 @@ _loop0_97_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_99[%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 @@ -30781,7 +31380,7 @@ _loop0_97_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_97[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_99[%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); @@ -30798,9 +31397,9 @@ _loop0_97_rule(Parser *p) return _seq; } -// _loop0_98: lambda_param_with_default +// _loop0_100: lambda_param_with_default static asdl_seq * -_loop0_98_rule(Parser *p) +_loop0_100_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30826,7 +31425,7 @@ _loop0_98_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_100[%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 @@ -30849,7 +31448,7 @@ _loop0_98_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_100[%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); @@ -30866,9 +31465,9 @@ _loop0_98_rule(Parser *p) return _seq; } -// _loop0_99: lambda_param_with_default +// _loop0_101: lambda_param_with_default static asdl_seq * -_loop0_99_rule(Parser *p) +_loop0_101_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30894,7 +31493,7 @@ _loop0_99_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + 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_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -30917,7 +31516,7 @@ _loop0_99_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_99[%d-%d]: %s failed!\n", p->level, ' ', + 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); @@ -30934,9 +31533,9 @@ _loop0_99_rule(Parser *p) return _seq; } -// _loop1_100: lambda_param_no_default +// _loop1_102: lambda_param_no_default static asdl_seq * -_loop1_100_rule(Parser *p) +_loop1_102_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -30962,7 +31561,7 @@ _loop1_100_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + 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; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -30985,7 +31584,7 @@ _loop1_100_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_100[%d-%d]: %s failed!\n", p->level, ' ', + 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")); } if (_n == 0 || p->error_indicator) { @@ -31007,9 +31606,9 @@ _loop1_100_rule(Parser *p) return _seq; } -// _loop0_101: lambda_param_with_default +// _loop0_103: lambda_param_with_default static asdl_seq * -_loop0_101_rule(Parser *p) +_loop0_103_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31035,7 +31634,7 @@ _loop0_101_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_103[%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 @@ -31058,7 +31657,7 @@ _loop0_101_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_101[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_103[%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); @@ -31075,9 +31674,9 @@ _loop0_101_rule(Parser *p) return _seq; } -// _loop1_102: lambda_param_with_default +// _loop1_104: lambda_param_with_default static asdl_seq * -_loop1_102_rule(Parser *p) +_loop1_104_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31103,7 +31702,7 @@ _loop1_102_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + 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; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31126,7 +31725,7 @@ _loop1_102_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_102[%d-%d]: %s failed!\n", p->level, ' ', + 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")); } if (_n == 0 || p->error_indicator) { @@ -31148,9 +31747,9 @@ _loop1_102_rule(Parser *p) return _seq; } -// _loop1_103: lambda_param_no_default +// _loop1_105: lambda_param_no_default static asdl_seq * -_loop1_103_rule(Parser *p) +_loop1_105_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31176,7 +31775,7 @@ _loop1_103_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_105[%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 @@ -31199,7 +31798,7 @@ _loop1_103_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_103[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_105[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -31221,9 +31820,9 @@ _loop1_103_rule(Parser *p) return _seq; } -// _loop1_104: lambda_param_no_default +// _loop1_106: lambda_param_no_default static asdl_seq * -_loop1_104_rule(Parser *p) +_loop1_106_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31249,7 +31848,7 @@ _loop1_104_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_106[%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 @@ -31272,7 +31871,7 @@ _loop1_104_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_104[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_106[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -31294,9 +31893,9 @@ _loop1_104_rule(Parser *p) return _seq; } -// _loop0_105: lambda_param_no_default +// _loop0_107: lambda_param_no_default static asdl_seq * -_loop0_105_rule(Parser *p) +_loop0_107_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31322,7 +31921,7 @@ _loop0_105_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + 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_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -31345,7 +31944,7 @@ _loop0_105_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_105[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_107[%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); @@ -31362,9 +31961,9 @@ _loop0_105_rule(Parser *p) return _seq; } -// _loop1_106: lambda_param_with_default +// _loop1_108: lambda_param_with_default static asdl_seq * -_loop1_106_rule(Parser *p) +_loop1_108_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31390,7 +31989,7 @@ _loop1_106_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + 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_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -31413,7 +32012,7 @@ _loop1_106_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_106[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_108[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -31435,9 +32034,9 @@ _loop1_106_rule(Parser *p) return _seq; } -// _loop0_107: lambda_param_no_default +// _loop0_109: lambda_param_no_default static asdl_seq * -_loop0_107_rule(Parser *p) +_loop0_109_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31463,7 +32062,7 @@ _loop0_107_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_109[%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 @@ -31486,7 +32085,7 @@ _loop0_107_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_109[%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); @@ -31503,9 +32102,9 @@ _loop0_107_rule(Parser *p) return _seq; } -// _loop1_108: lambda_param_with_default +// _loop1_110: lambda_param_with_default static asdl_seq * -_loop1_108_rule(Parser *p) +_loop1_110_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31531,7 +32130,7 @@ _loop1_108_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_110[%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 @@ -31554,7 +32153,7 @@ _loop1_108_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_108[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_110[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -31576,9 +32175,9 @@ _loop1_108_rule(Parser *p) return _seq; } -// _loop0_109: lambda_param_maybe_default +// _loop0_111: lambda_param_maybe_default static asdl_seq * -_loop0_109_rule(Parser *p) +_loop0_111_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31604,7 +32203,7 @@ _loop0_109_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_111[%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 @@ -31627,7 +32226,7 @@ _loop0_109_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_109[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_111[%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); @@ -31644,9 +32243,9 @@ _loop0_109_rule(Parser *p) return _seq; } -// _loop1_110: lambda_param_maybe_default +// _loop1_112: lambda_param_maybe_default static asdl_seq * -_loop1_110_rule(Parser *p) +_loop1_112_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31672,7 +32271,7 @@ _loop1_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_112[%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 @@ -31695,7 +32294,7 @@ _loop1_110_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -31717,9 +32316,9 @@ _loop1_110_rule(Parser *p) return _seq; } -// _tmp_111: yield_expr | star_expressions +// _tmp_113: yield_expr | star_expressions static void * -_tmp_111_rule(Parser *p) +_tmp_113_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31736,18 +32335,18 @@ _tmp_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_113[%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_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_113[%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_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -31755,18 +32354,18 @@ _tmp_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_113[%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_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_113[%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_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -31775,9 +32374,9 @@ _tmp_111_rule(Parser *p) return _res; } -// _loop0_112: fstring_format_spec +// _loop0_114: fstring_format_spec static asdl_seq * -_loop0_112_rule(Parser *p) +_loop0_114_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31803,7 +32402,7 @@ _loop0_112_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_114[%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 @@ -31826,7 +32425,7 @@ _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, ' ', + D(fprintf(stderr, "%*c%s _loop0_114[%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); @@ -31843,9 +32442,9 @@ _loop0_112_rule(Parser *p) return _seq; } -// _loop1_113: (fstring | string) +// _loop1_115: (fstring | string) static asdl_seq * -_loop1_113_rule(Parser *p) +_loop1_115_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31871,13 +32470,13 @@ _loop1_113_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_253_var; + D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); + void *_tmp_255_var; while ( - (_tmp_253_var = _tmp_253_rule(p)) // fstring | string + (_tmp_255_var = _tmp_255_rule(p)) // fstring | string ) { - _res = _tmp_253_var; + _res = _tmp_255_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31894,7 +32493,7 @@ _loop1_113_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_113[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_115[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)")); } if (_n == 0 || p->error_indicator) { @@ -31916,9 +32515,9 @@ _loop1_113_rule(Parser *p) return _seq; } -// _tmp_114: star_named_expression ',' star_named_expressions? +// _tmp_116: star_named_expression ',' star_named_expressions? static void * -_tmp_114_rule(Parser *p) +_tmp_116_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31935,7 +32534,7 @@ _tmp_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); Token * _literal; expr_ty y; void *z; @@ -31947,7 +32546,7 @@ _tmp_114_rule(Parser *p) (z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? ) { - D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c+ _tmp_116[%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; @@ -31957,7 +32556,7 @@ _tmp_114_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); } _res = NULL; @@ -31966,9 +32565,9 @@ _tmp_114_rule(Parser *p) return _res; } -// _loop0_116: ',' double_starred_kvpair +// _loop0_118: ',' double_starred_kvpair static asdl_seq * -_loop0_116_rule(Parser *p) +_loop0_118_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -31994,7 +32593,7 @@ _loop0_116_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -32026,7 +32625,7 @@ _loop0_116_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_118[%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); @@ -32043,9 +32642,9 @@ _loop0_116_rule(Parser *p) return _seq; } -// _gather_115: double_starred_kvpair _loop0_116 +// _gather_117: double_starred_kvpair _loop0_118 static asdl_seq * -_gather_115_rule(Parser *p) +_gather_117_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32057,27 +32656,27 @@ _gather_115_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_116 + { // double_starred_kvpair _loop0_118 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_116")); + D(fprintf(stderr, "%*c> _gather_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_118")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_116_rule(p)) // _loop0_116 + (seq = _loop0_118_rule(p)) // _loop0_118 ) { - D(fprintf(stderr, "%*c+ _gather_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_116")); + D(fprintf(stderr, "%*c+ _gather_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_118")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_117[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_118")); } _res = NULL; done: @@ -32085,9 +32684,9 @@ _gather_115_rule(Parser *p) return _res; } -// _loop1_117: for_if_clause +// _loop1_119: for_if_clause static asdl_seq * -_loop1_117_rule(Parser *p) +_loop1_119_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32113,7 +32712,7 @@ _loop1_117_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); + D(fprintf(stderr, "%*c> _loop1_119[%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 @@ -32136,7 +32735,7 @@ _loop1_117_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_117[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); } if (_n == 0 || p->error_indicator) { @@ -32158,9 +32757,9 @@ _loop1_117_rule(Parser *p) return _seq; } -// _loop0_118: ('if' disjunction) +// _loop0_120: ('if' disjunction) static asdl_seq * -_loop0_118_rule(Parser *p) +_loop0_120_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32186,13 +32785,13 @@ _loop0_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_254_var; + D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_256_var; while ( - (_tmp_254_var = _tmp_254_rule(p)) // 'if' disjunction + (_tmp_256_var = _tmp_256_rule(p)) // 'if' disjunction ) { - _res = _tmp_254_var; + _res = _tmp_256_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32209,7 +32808,7 @@ _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, ' ', + D(fprintf(stderr, "%*c%s _loop0_120[%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); @@ -32226,9 +32825,9 @@ _loop0_118_rule(Parser *p) return _seq; } -// _loop0_119: ('if' disjunction) +// _loop0_121: ('if' disjunction) static asdl_seq * -_loop0_119_rule(Parser *p) +_loop0_121_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32254,13 +32853,13 @@ _loop0_119_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_255_var; + D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_257_var; while ( - (_tmp_255_var = _tmp_255_rule(p)) // 'if' disjunction + (_tmp_257_var = _tmp_257_rule(p)) // 'if' disjunction ) { - _res = _tmp_255_var; + _res = _tmp_257_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32277,7 +32876,7 @@ _loop0_119_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_121[%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); @@ -32294,9 +32893,9 @@ _loop0_119_rule(Parser *p) return _seq; } -// _tmp_120: assignment_expression | expression !':=' +// _tmp_122: assignment_expression | expression !':=' static void * -_tmp_120_rule(Parser *p) +_tmp_122_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32313,18 +32912,18 @@ _tmp_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_122[%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_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_122[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -32332,7 +32931,7 @@ _tmp_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -32340,12 +32939,12 @@ _tmp_120_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_122[%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_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -32354,9 +32953,9 @@ _tmp_120_rule(Parser *p) return _res; } -// _loop0_122: ',' (starred_expression | (assignment_expression | expression !':=') !'=') +// _loop0_124: ',' (starred_expression | (assignment_expression | expression !':=') !'=') static asdl_seq * -_loop0_122_rule(Parser *p) +_loop0_124_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32382,13 +32981,13 @@ _loop0_122_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + D(fprintf(stderr, "%*c> _loop0_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_256_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -32414,7 +33013,7 @@ _loop0_122_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_124[%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); @@ -32431,10 +33030,10 @@ _loop0_122_rule(Parser *p) return _seq; } -// _gather_121: -// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122 +// _gather_123: +// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124 static asdl_seq * -_gather_121_rule(Parser *p) +_gather_123_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32446,27 +33045,27 @@ _gather_121_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122 + { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + D(fprintf(stderr, "%*c> _gather_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_256_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && - (seq = _loop0_122_rule(p)) // _loop0_122 + (seq = _loop0_124_rule(p)) // _loop0_124 ) { - D(fprintf(stderr, "%*c+ _gather_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_122")); + D(fprintf(stderr, "%*c+ _gather_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_123[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124")); } _res = NULL; done: @@ -32474,9 +33073,9 @@ _gather_121_rule(Parser *p) return _res; } -// _tmp_123: ',' kwargs +// _tmp_125: ',' kwargs static void * -_tmp_123_rule(Parser *p) +_tmp_125_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32493,7 +33092,7 @@ _tmp_123_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); Token * _literal; asdl_seq* k; if ( @@ -32502,7 +33101,7 @@ _tmp_123_rule(Parser *p) (k = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); _res = k; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -32512,7 +33111,7 @@ _tmp_123_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); } _res = NULL; @@ -32521,9 +33120,9 @@ _tmp_123_rule(Parser *p) return _res; } -// _loop0_125: ',' kwarg_or_starred +// _loop0_127: ',' kwarg_or_starred static asdl_seq * -_loop0_125_rule(Parser *p) +_loop0_127_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -32549,7 +33148,7 @@ _loop0_125_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -32581,127 +33180,8 @@ _loop0_125_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_125[%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_124: kwarg_or_starred _loop0_125 -static asdl_seq * -_gather_124_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_125 - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _gather_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_125")); - KeywordOrStarred* elem; - asdl_seq * seq; - if ( - (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred - && - (seq = _loop0_125_rule(p)) // _loop0_125 - ) - { - D(fprintf(stderr, "%*c+ _gather_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_125")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_124[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_125")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_127: ',' kwarg_or_double_starred -static asdl_seq * -_loop0_127_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_127[%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_127[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); + 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) { @@ -32717,7 +33197,7 @@ _loop0_127_rule(Parser *p) return _seq; } -// _gather_126: kwarg_or_double_starred _loop0_127 +// _gather_126: kwarg_or_starred _loop0_127 static asdl_seq * _gather_126_rule(Parser *p) { @@ -32731,27 +33211,27 @@ _gather_126_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_127 + { // kwarg_or_starred _loop0_127 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_127")); + D(fprintf(stderr, "%*c> _gather_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_127")); KeywordOrStarred* elem; asdl_seq * seq; if ( - (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred && (seq = _loop0_127_rule(p)) // _loop0_127 ) { - D(fprintf(stderr, "%*c+ _gather_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_127")); + D(fprintf(stderr, "%*c+ _gather_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_127")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_126[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_127")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_127")); } _res = NULL; done: @@ -32759,7 +33239,7 @@ _gather_126_rule(Parser *p) return _res; } -// _loop0_129: ',' kwarg_or_starred +// _loop0_129: ',' kwarg_or_double_starred static asdl_seq * _loop0_129_rule(Parser *p) { @@ -32782,18 +33262,18 @@ _loop0_129_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' kwarg_or_starred + { // ',' kwarg_or_double_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")); + D(fprintf(stderr, "%*c> _loop0_129[%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_starred_rule(p)) // kwarg_or_starred + (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred ) { _res = elem; @@ -32820,7 +33300,7 @@ _loop0_129_rule(Parser *p) } 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")); + 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) { @@ -32836,7 +33316,7 @@ _loop0_129_rule(Parser *p) return _seq; } -// _gather_128: kwarg_or_starred _loop0_129 +// _gather_128: kwarg_or_double_starred _loop0_129 static asdl_seq * _gather_128_rule(Parser *p) { @@ -32850,27 +33330,27 @@ _gather_128_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_starred _loop0_129 + { // kwarg_or_double_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")); + D(fprintf(stderr, "%*c> _gather_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_129")); KeywordOrStarred* elem; asdl_seq * seq; if ( - (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred + (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_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")); + D(fprintf(stderr, "%*c+ _gather_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_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")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_129")); } _res = NULL; done: @@ -32878,7 +33358,7 @@ _gather_128_rule(Parser *p) return _res; } -// _loop0_131: ',' kwarg_or_double_starred +// _loop0_131: ',' kwarg_or_starred static asdl_seq * _loop0_131_rule(Parser *p) { @@ -32901,18 +33381,18 @@ _loop0_131_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' kwarg_or_double_starred + { // ',' kwarg_or_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")); + D(fprintf(stderr, "%*c> _loop0_131[%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_double_starred_rule(p)) // kwarg_or_double_starred + (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred ) { _res = elem; @@ -32939,7 +33419,7 @@ _loop0_131_rule(Parser *p) } 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")); + 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) { @@ -32955,7 +33435,7 @@ _loop0_131_rule(Parser *p) return _seq; } -// _gather_130: kwarg_or_double_starred _loop0_131 +// _gather_130: kwarg_or_starred _loop0_131 static asdl_seq * _gather_130_rule(Parser *p) { @@ -32969,27 +33449,27 @@ _gather_130_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_131 + { // kwarg_or_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")); + D(fprintf(stderr, "%*c> _gather_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_131")); KeywordOrStarred* elem; asdl_seq * seq; if ( - (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + (elem = kwarg_or_starred_rule(p)) // kwarg_or_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")); + D(fprintf(stderr, "%*c+ _gather_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_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")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_131")); } _res = NULL; done: @@ -32997,9 +33477,128 @@ _gather_130_rule(Parser *p) return _res; } -// _loop0_132: (',' star_target) +// _loop0_133: ',' kwarg_or_double_starred static asdl_seq * -_loop0_132_rule(Parser *p) +_loop0_133_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_133[%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_133[%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_132: kwarg_or_double_starred _loop0_133 +static asdl_seq * +_gather_132_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_133 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_133")); + KeywordOrStarred* elem; + asdl_seq * seq; + if ( + (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + && + (seq = _loop0_133_rule(p)) // _loop0_133 + ) + { + D(fprintf(stderr, "%*c+ _gather_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_133")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_132[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_133")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_134: (',' star_target) +static asdl_seq * +_loop0_134_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33025,13 +33624,13 @@ _loop0_132_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_257_var; + D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_259_var; while ( - (_tmp_257_var = _tmp_257_rule(p)) // ',' star_target + (_tmp_259_var = _tmp_259_rule(p)) // ',' star_target ) { - _res = _tmp_257_var; + _res = _tmp_259_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33048,7 +33647,7 @@ _loop0_132_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_132[%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); @@ -33065,9 +33664,9 @@ _loop0_132_rule(Parser *p) return _seq; } -// _loop0_134: ',' star_target +// _loop0_136: ',' star_target static asdl_seq * -_loop0_134_rule(Parser *p) +_loop0_136_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33093,7 +33692,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, "',' star_target")); + D(fprintf(stderr, "%*c> _loop0_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty elem; while ( @@ -33125,7 +33724,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_136[%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); @@ -33142,9 +33741,9 @@ _loop0_134_rule(Parser *p) return _seq; } -// _gather_133: star_target _loop0_134 +// _gather_135: star_target _loop0_136 static asdl_seq * -_gather_133_rule(Parser *p) +_gather_135_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33156,27 +33755,27 @@ _gather_133_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_target _loop0_134 + { // star_target _loop0_136 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_134")); + D(fprintf(stderr, "%*c> _gather_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_136")); expr_ty elem; asdl_seq * seq; if ( (elem = star_target_rule(p)) // star_target && - (seq = _loop0_134_rule(p)) // _loop0_134 + (seq = _loop0_136_rule(p)) // _loop0_136 ) { - D(fprintf(stderr, "%*c+ _gather_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_134")); + D(fprintf(stderr, "%*c+ _gather_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_136")); _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, "star_target _loop0_134")); + D(fprintf(stderr, "%*c%s _gather_135[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_136")); } _res = NULL; done: @@ -33184,9 +33783,9 @@ _gather_133_rule(Parser *p) return _res; } -// _loop1_135: (',' star_target) +// _loop1_137: (',' star_target) static asdl_seq * -_loop1_135_rule(Parser *p) +_loop1_137_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33212,13 +33811,13 @@ _loop1_135_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_258_var; + D(fprintf(stderr, "%*c> _loop1_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_260_var; while ( - (_tmp_258_var = _tmp_258_rule(p)) // ',' star_target + (_tmp_260_var = _tmp_260_rule(p)) // ',' star_target ) { - _res = _tmp_258_var; + _res = _tmp_260_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33235,7 +33834,7 @@ _loop1_135_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_137[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } if (_n == 0 || p->error_indicator) { @@ -33257,9 +33856,9 @@ _loop1_135_rule(Parser *p) return _seq; } -// _tmp_136: !'*' star_target +// _tmp_138: !'*' star_target static void * -_tmp_136_rule(Parser *p) +_tmp_138_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33276,7 +33875,7 @@ _tmp_136_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_138[%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='*' @@ -33284,12 +33883,12 @@ _tmp_136_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_138[%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_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -33298,9 +33897,9 @@ _tmp_136_rule(Parser *p) return _res; } -// _loop0_138: ',' del_target +// _loop0_140: ',' del_target static asdl_seq * -_loop0_138_rule(Parser *p) +_loop0_140_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33326,7 +33925,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, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -33358,7 +33957,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_140[%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); @@ -33375,9 +33974,9 @@ _loop0_138_rule(Parser *p) return _seq; } -// _gather_137: del_target _loop0_138 +// _gather_139: del_target _loop0_140 static asdl_seq * -_gather_137_rule(Parser *p) +_gather_139_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33389,27 +33988,27 @@ _gather_137_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // del_target _loop0_138 + { // del_target _loop0_140 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_138")); + D(fprintf(stderr, "%*c> _gather_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_140")); expr_ty elem; asdl_seq * seq; if ( (elem = del_target_rule(p)) // del_target && - (seq = _loop0_138_rule(p)) // _loop0_138 + (seq = _loop0_140_rule(p)) // _loop0_140 ) { - D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_138")); + D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_140")); _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, "del_target _loop0_138")); + D(fprintf(stderr, "%*c%s _gather_139[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_140")); } _res = NULL; done: @@ -33417,9 +34016,9 @@ _gather_137_rule(Parser *p) return _res; } -// _loop0_140: ',' expression +// _loop0_142: ',' expression static asdl_seq * -_loop0_140_rule(Parser *p) +_loop0_142_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33445,7 +34044,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_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33477,7 +34076,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_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); @@ -33494,9 +34093,9 @@ _loop0_140_rule(Parser *p) return _seq; } -// _gather_139: expression _loop0_140 +// _gather_141: expression _loop0_142 static asdl_seq * -_gather_139_rule(Parser *p) +_gather_141_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33508,27 +34107,27 @@ _gather_139_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_140 + { // expression _loop0_142 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_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_140_rule(p)) // _loop0_140 + (seq = _loop0_142_rule(p)) // _loop0_142 ) { - D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_140")); + 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_139[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_140")); + 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: @@ -33536,9 +34135,9 @@ _gather_139_rule(Parser *p) return _res; } -// _loop0_142: ',' expression +// _loop0_144: ',' expression static asdl_seq * -_loop0_142_rule(Parser *p) +_loop0_144_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33564,7 +34163,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_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33596,7 +34195,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_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); @@ -33613,9 +34212,9 @@ _loop0_142_rule(Parser *p) return _seq; } -// _gather_141: expression _loop0_142 +// _gather_143: expression _loop0_144 static asdl_seq * -_gather_141_rule(Parser *p) +_gather_143_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33627,27 +34226,27 @@ _gather_141_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_142 + { // expression _loop0_144 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_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_142_rule(p)) // _loop0_142 + (seq = _loop0_144_rule(p)) // _loop0_144 ) { - D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_142")); + 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_141[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_142")); + 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: @@ -33655,9 +34254,9 @@ _gather_141_rule(Parser *p) return _res; } -// _loop0_144: ',' expression +// _loop0_146: ',' expression static asdl_seq * -_loop0_144_rule(Parser *p) +_loop0_146_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33683,7 +34282,7 @@ _loop0_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_144[%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 ( @@ -33715,7 +34314,7 @@ _loop0_144_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_144[%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); @@ -33732,9 +34331,9 @@ _loop0_144_rule(Parser *p) return _seq; } -// _gather_143: expression _loop0_144 +// _gather_145: expression _loop0_146 static asdl_seq * -_gather_143_rule(Parser *p) +_gather_145_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33746,27 +34345,27 @@ _gather_143_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_144 + { // expression _loop0_146 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_144")); + 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_144_rule(p)) // _loop0_144 + (seq = _loop0_146_rule(p)) // _loop0_146 ) { - D(fprintf(stderr, "%*c+ _gather_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_144")); + 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_143[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_144")); + 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: @@ -33774,9 +34373,9 @@ _gather_143_rule(Parser *p) return _res; } -// _loop0_146: ',' expression +// _loop0_148: ',' expression static asdl_seq * -_loop0_146_rule(Parser *p) +_loop0_148_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33802,7 +34401,7 @@ _loop0_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _loop0_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty elem; while ( @@ -33834,7 +34433,7 @@ _loop0_146_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_148[%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); @@ -33851,9 +34450,9 @@ _loop0_146_rule(Parser *p) return _seq; } -// _gather_145: expression _loop0_146 +// _gather_147: expression _loop0_148 static asdl_seq * -_gather_145_rule(Parser *p) +_gather_147_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33865,27 +34464,27 @@ _gather_145_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_146 + { // expression _loop0_148 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_146")); + D(fprintf(stderr, "%*c> _gather_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_148")); expr_ty elem; asdl_seq * seq; if ( (elem = expression_rule(p)) // expression && - (seq = _loop0_146_rule(p)) // _loop0_146 + (seq = _loop0_148_rule(p)) // _loop0_148 ) { - D(fprintf(stderr, "%*c+ _gather_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_146")); + D(fprintf(stderr, "%*c+ _gather_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_148")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_145[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_146")); + D(fprintf(stderr, "%*c%s _gather_147[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_148")); } _res = NULL; done: @@ -33893,9 +34492,9 @@ _gather_145_rule(Parser *p) return _res; } -// _tmp_147: NEWLINE INDENT +// _tmp_149: NEWLINE INDENT static void * -_tmp_147_rule(Parser *p) +_tmp_149_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33912,7 +34511,7 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); Token * indent_var; Token * newline_var; if ( @@ -33921,12 +34520,12 @@ _tmp_147_rule(Parser *p) (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + D(fprintf(stderr, "%*c+ _tmp_149[%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_147[%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, "NEWLINE INDENT")); } _res = NULL; @@ -33935,9 +34534,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: args | expression for_if_clauses +// _tmp_150: args | expression for_if_clauses static void * -_tmp_148_rule(Parser *p) +_tmp_150_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -33954,18 +34553,18 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_150[%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_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_150[%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_148[%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, "args")); } { // expression for_if_clauses @@ -33973,7 +34572,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, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_150[%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 ( @@ -33982,12 +34581,12 @@ _tmp_148_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_150[%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_148[%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, "expression for_if_clauses")); } _res = NULL; @@ -33996,9 +34595,9 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: args ',' +// _tmp_151: args ',' static void * -_tmp_149_rule(Parser *p) +_tmp_151_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34015,7 +34614,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, "args ','")); + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); Token * _literal; expr_ty args_var; if ( @@ -34024,12 +34623,12 @@ _tmp_149_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c+ _tmp_151[%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_149[%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, "args ','")); } _res = NULL; @@ -34038,9 +34637,9 @@ _tmp_149_rule(Parser *p) return _res; } -// _tmp_150: ',' | ')' +// _tmp_152: ',' | ')' static void * -_tmp_150_rule(Parser *p) +_tmp_152_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34057,18 +34656,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_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_152[%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_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -34076,18 +34675,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_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_152[%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_152[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } _res = NULL; @@ -34096,9 +34695,9 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: 'True' | 'False' | 'None' +// _tmp_153: 'True' | 'False' | 'None' static void * -_tmp_151_rule(Parser *p) +_tmp_153_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34115,18 +34714,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, "'True'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; 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_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'False' @@ -34134,18 +34733,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, "'False'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; 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_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } { // 'None' @@ -34153,18 +34752,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, "'None'")); + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; 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_153[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } _res = NULL; @@ -34173,9 +34772,9 @@ _tmp_151_rule(Parser *p) return _res; } -// _tmp_152: NAME '=' +// _tmp_154: NAME '=' static void * -_tmp_152_rule(Parser *p) +_tmp_154_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34192,7 +34791,7 @@ _tmp_152_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); Token * _literal; expr_ty name_var; if ( @@ -34201,12 +34800,12 @@ _tmp_152_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c+ _tmp_154[%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_152[%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, "NAME '='")); } _res = NULL; @@ -34215,9 +34814,9 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: NAME STRING | SOFT_KEYWORD +// _tmp_155: NAME STRING | SOFT_KEYWORD static void * -_tmp_153_rule(Parser *p) +_tmp_155_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34234,7 +34833,7 @@ _tmp_153_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); expr_ty name_var; expr_ty string_var; if ( @@ -34243,12 +34842,12 @@ _tmp_153_rule(Parser *p) (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c+ _tmp_155[%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_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING")); } { // SOFT_KEYWORD @@ -34256,18 +34855,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, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c> _tmp_155[%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_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c+ _tmp_155[%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_153[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD")); } _res = NULL; @@ -34276,9 +34875,9 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: 'else' | ':' +// _tmp_156: 'else' | ':' static void * -_tmp_154_rule(Parser *p) +_tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34295,18 +34894,18 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 645)) // token='else' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%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, "'else'")); } { // ':' @@ -34314,18 +34913,18 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%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, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_154[%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_154[%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; @@ -34334,9 +34933,9 @@ _tmp_154_rule(Parser *p) return _res; } -// _tmp_155: FSTRING_MIDDLE | fstring_replacement_field +// _tmp_157: FSTRING_MIDDLE | fstring_replacement_field static void * -_tmp_155_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34353,18 +34952,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE")); + D(fprintf(stderr, "%*c> _tmp_157[%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")); + D(fprintf(stderr, "%*c+ _tmp_157[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE")); } { // fstring_replacement_field @@ -34372,18 +34971,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field")); + D(fprintf(stderr, "%*c> _tmp_157[%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")); + D(fprintf(stderr, "%*c+ _tmp_157[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field")); } _res = NULL; @@ -34392,9 +34991,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: '=' | ':=' +// _tmp_158: '=' | ':=' static void * -_tmp_156_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34411,18 +35010,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%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_156[%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_156[%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, "'='")); } { // ':=' @@ -34430,18 +35029,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%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_156[%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_156[%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; @@ -34450,9 +35049,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_159: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_157_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34469,18 +35068,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, "list")); + D(fprintf(stderr, "%*c> _tmp_159[%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_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_159[%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_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -34488,18 +35087,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, "tuple")); + D(fprintf(stderr, "%*c> _tmp_159[%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_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_159[%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_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -34507,18 +35106,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, "genexp")); + D(fprintf(stderr, "%*c> _tmp_159[%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_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_159[%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_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -34526,18 +35125,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, "'True'")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 601)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; 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_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -34545,18 +35144,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, "'None'")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 602)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; 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_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -34564,18 +35163,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, "'False'")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 603)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; 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_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -34584,9 +35183,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: '=' | ':=' +// _tmp_160: '=' | ':=' static void * -_tmp_158_rule(Parser *p) +_tmp_160_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34603,18 +35202,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_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_160[%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_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34622,18 +35221,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_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_160[%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_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34642,9 +35241,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _loop0_159: star_named_expressions +// _loop0_161: star_named_expressions static asdl_seq * -_loop0_159_rule(Parser *p) +_loop0_161_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34670,7 +35269,7 @@ _loop0_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_161[%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 @@ -34693,7 +35292,7 @@ _loop0_159_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_159[%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_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34710,9 +35309,9 @@ _loop0_159_rule(Parser *p) return _seq; } -// _loop0_160: (star_targets '=') +// _loop0_162: (star_targets '=') static asdl_seq * -_loop0_160_rule(Parser *p) +_loop0_162_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34738,13 +35337,13 @@ _loop0_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_259_var; + D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_261_var; while ( - (_tmp_259_var = _tmp_259_rule(p)) // star_targets '=' + (_tmp_261_var = _tmp_261_rule(p)) // star_targets '=' ) { - _res = _tmp_259_var; + _res = _tmp_261_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34761,7 +35360,7 @@ _loop0_160_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_162[%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); @@ -34778,9 +35377,9 @@ _loop0_160_rule(Parser *p) return _seq; } -// _loop0_161: (star_targets '=') +// _loop0_163: (star_targets '=') static asdl_seq * -_loop0_161_rule(Parser *p) +_loop0_163_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34806,13 +35405,13 @@ _loop0_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_260_var; + D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_262_var; while ( - (_tmp_260_var = _tmp_260_rule(p)) // star_targets '=' + (_tmp_262_var = _tmp_262_rule(p)) // star_targets '=' ) { - _res = _tmp_260_var; + _res = _tmp_262_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34829,7 +35428,7 @@ _loop0_161_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_163[%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); @@ -34846,9 +35445,9 @@ _loop0_161_rule(Parser *p) return _seq; } -// _tmp_162: yield_expr | star_expressions +// _tmp_164: yield_expr | star_expressions static void * -_tmp_162_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34865,18 +35464,18 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_164[%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_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_164[%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_162[%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, "yield_expr")); } { // star_expressions @@ -34884,18 +35483,18 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_164[%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_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_164[%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_162[%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, "star_expressions")); } _res = NULL; @@ -34904,9 +35503,9 @@ _tmp_162_rule(Parser *p) return _res; } -// _tmp_163: '[' | '(' | '{' +// _tmp_165: '[' | '(' | '{' static void * -_tmp_163_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -34923,18 +35522,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%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_163[%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_163[%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, "'['")); } { // '(' @@ -34942,18 +35541,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%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, 7)) // token='(' ) { - D(fprintf(stderr, "%*c+ _tmp_163[%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_163[%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, "'('")); } { // '{' @@ -34961,18 +35560,18 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%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_163[%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_163[%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; @@ -34981,9 +35580,9 @@ _tmp_163_rule(Parser *p) return _res; } -// _tmp_164: '[' | '{' +// _tmp_166: '[' | '{' static void * -_tmp_164_rule(Parser *p) +_tmp_166_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35000,18 +35599,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%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, "'['")); } { // '{' @@ -35019,18 +35618,18 @@ _tmp_164_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%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, "'{'")); } _res = NULL; @@ -35039,9 +35638,9 @@ _tmp_164_rule(Parser *p) return _res; } -// _tmp_165: '[' | '{' +// _tmp_167: '[' | '{' static void * -_tmp_165_rule(Parser *p) +_tmp_167_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35058,18 +35657,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); } { // '{' @@ -35077,18 +35676,18 @@ _tmp_165_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); } _res = NULL; @@ -35097,9 +35696,9 @@ _tmp_165_rule(Parser *p) return _res; } -// _tmp_166: slash_no_default | slash_with_default +// _tmp_168: slash_no_default | slash_with_default static void * -_tmp_166_rule(Parser *p) +_tmp_168_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35116,18 +35715,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_168[%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_168[%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_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35135,18 +35734,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_168[%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_168[%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_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35155,9 +35754,9 @@ _tmp_166_rule(Parser *p) return _res; } -// _loop0_167: param_maybe_default +// _loop0_169: param_maybe_default static asdl_seq * -_loop0_167_rule(Parser *p) +_loop0_169_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35183,7 +35782,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_169[%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 @@ -35206,7 +35805,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_169[%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); @@ -35223,9 +35822,9 @@ _loop0_167_rule(Parser *p) return _seq; } -// _loop0_168: param_no_default +// _loop0_170: param_no_default static asdl_seq * -_loop0_168_rule(Parser *p) +_loop0_170_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35251,7 +35850,7 @@ _loop0_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _loop0_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 @@ -35274,7 +35873,7 @@ _loop0_168_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_170[%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); @@ -35291,9 +35890,9 @@ _loop0_168_rule(Parser *p) return _seq; } -// _loop0_169: param_no_default +// _loop0_171: param_no_default static asdl_seq * -_loop0_169_rule(Parser *p) +_loop0_171_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35319,7 +35918,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_no_default")); + D(fprintf(stderr, "%*c> _loop0_171[%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 @@ -35342,7 +35941,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_171[%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); @@ -35359,9 +35958,9 @@ _loop0_169_rule(Parser *p) return _seq; } -// _loop1_170: param_no_default +// _loop1_172: param_no_default static asdl_seq * -_loop1_170_rule(Parser *p) +_loop1_172_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35387,7 +35986,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_no_default")); + D(fprintf(stderr, "%*c> _loop1_172[%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 @@ -35410,7 +36009,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_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -35432,9 +36031,9 @@ _loop1_170_rule(Parser *p) return _seq; } -// _tmp_171: slash_no_default | slash_with_default +// _tmp_173: slash_no_default | slash_with_default static void * -_tmp_171_rule(Parser *p) +_tmp_173_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35451,18 +36050,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, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_173[%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_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_173[%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_171[%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, "slash_no_default")); } { // slash_with_default @@ -35470,18 +36069,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, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_173[%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_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_173[%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_171[%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, "slash_with_default")); } _res = NULL; @@ -35490,9 +36089,9 @@ _tmp_171_rule(Parser *p) return _res; } -// _loop0_172: param_maybe_default +// _loop0_174: param_maybe_default static asdl_seq * -_loop0_172_rule(Parser *p) +_loop0_174_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35518,7 +36117,7 @@ _loop0_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_172[%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 @@ -35541,7 +36140,7 @@ _loop0_172_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_172[%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); @@ -35558,9 +36157,9 @@ _loop0_172_rule(Parser *p) return _seq; } -// _tmp_173: ',' | param_no_default +// _tmp_175: ',' | param_no_default static void * -_tmp_173_rule(Parser *p) +_tmp_175_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35577,18 +36176,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_175[%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_175[%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_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // param_no_default @@ -35596,18 +36195,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_175[%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_175[%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_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } _res = NULL; @@ -35616,9 +36215,9 @@ _tmp_173_rule(Parser *p) return _res; } -// _loop0_174: param_maybe_default +// _loop0_176: param_maybe_default static asdl_seq * -_loop0_174_rule(Parser *p) +_loop0_176_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35644,7 +36243,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_176[%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 @@ -35667,7 +36266,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_176[%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); @@ -35684,9 +36283,9 @@ _loop0_174_rule(Parser *p) return _seq; } -// _loop1_175: param_maybe_default +// _loop1_177: param_maybe_default static asdl_seq * -_loop1_175_rule(Parser *p) +_loop1_177_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35712,7 +36311,7 @@ _loop1_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_177[%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 @@ -35735,7 +36334,7 @@ _loop1_175_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -35757,9 +36356,9 @@ _loop1_175_rule(Parser *p) return _seq; } -// _tmp_176: ')' | ',' +// _tmp_178: ')' | ',' static void * -_tmp_176_rule(Parser *p) +_tmp_178_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35776,18 +36375,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_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_176[%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_176[%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, "')'")); } { // ',' @@ -35795,18 +36394,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_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_176[%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_176[%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; @@ -35815,9 +36414,9 @@ _tmp_176_rule(Parser *p) return _res; } -// _tmp_177: ')' | ',' (')' | '**') +// _tmp_179: ')' | ',' (')' | '**') static void * -_tmp_177_rule(Parser *p) +_tmp_179_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35834,18 +36433,18 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ',' (')' | '**') @@ -35853,21 +36452,21 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_261_var; + void *_tmp_263_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_261_var = _tmp_261_rule(p)) // ')' | '**' + (_tmp_263_var = _tmp_263_rule(p)) // ')' | '**' ) { - 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); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_263_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -35876,9 +36475,9 @@ _tmp_177_rule(Parser *p) return _res; } -// _tmp_178: param_no_default | ',' +// _tmp_180: param_no_default | ',' static void * -_tmp_178_rule(Parser *p) +_tmp_180_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35895,18 +36494,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, "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_178[%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_178[%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")); } { // ',' @@ -35914,18 +36513,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, "','")); + 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_178[%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_178[%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; @@ -35934,9 +36533,9 @@ _tmp_178_rule(Parser *p) return _res; } -// _loop0_179: param_maybe_default +// _loop0_181: param_maybe_default static asdl_seq * -_loop0_179_rule(Parser *p) +_loop0_181_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -35962,7 +36561,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, "param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_181[%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 @@ -35985,7 +36584,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_181[%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); @@ -36002,9 +36601,9 @@ _loop0_179_rule(Parser *p) return _seq; } -// _tmp_180: param_no_default | ',' +// _tmp_182: param_no_default | ',' static void * -_tmp_180_rule(Parser *p) +_tmp_182_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36021,18 +36620,18 @@ _tmp_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_182[%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_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_182[%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_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -36040,18 +36639,18 @@ _tmp_180_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36060,9 +36659,9 @@ _tmp_180_rule(Parser *p) return _res; } -// _tmp_181: '*' | '**' | '/' +// _tmp_183: '*' | '**' | '/' static void * -_tmp_181_rule(Parser *p) +_tmp_183_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36079,18 +36678,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%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, "'*'")); } { // '**' @@ -36098,18 +36697,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%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, "'**'")); } { // '/' @@ -36117,18 +36716,18 @@ _tmp_181_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_181[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_181[%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, "'/'")); } _res = NULL; @@ -36137,9 +36736,9 @@ _tmp_181_rule(Parser *p) return _res; } -// _loop1_182: param_with_default +// _loop1_184: param_with_default static asdl_seq * -_loop1_182_rule(Parser *p) +_loop1_184_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36165,7 +36764,7 @@ _loop1_182_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default")); + D(fprintf(stderr, "%*c> _loop1_184[%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 @@ -36188,7 +36787,7 @@ _loop1_182_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_182[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_184[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -36210,9 +36809,9 @@ _loop1_182_rule(Parser *p) return _seq; } -// _tmp_183: lambda_slash_no_default | lambda_slash_with_default +// _tmp_185: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_183_rule(Parser *p) +_tmp_185_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36229,18 +36828,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_185[%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_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_185[%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_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -36248,18 +36847,18 @@ _tmp_183_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_185[%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_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_185[%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_183[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -36268,9 +36867,9 @@ _tmp_183_rule(Parser *p) return _res; } -// _loop0_184: lambda_param_maybe_default +// _loop0_186: lambda_param_maybe_default static asdl_seq * -_loop0_184_rule(Parser *p) +_loop0_186_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36296,7 +36895,7 @@ _loop0_184_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_186[%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 @@ -36319,7 +36918,7 @@ _loop0_184_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_184[%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_maybe_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36336,9 +36935,9 @@ _loop0_184_rule(Parser *p) return _seq; } -// _loop0_185: lambda_param_no_default +// _loop0_187: lambda_param_no_default static asdl_seq * -_loop0_185_rule(Parser *p) +_loop0_187_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36364,7 +36963,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_no_default")); + D(fprintf(stderr, "%*c> _loop0_187[%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 @@ -36387,7 +36986,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_187[%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); @@ -36404,9 +37003,9 @@ _loop0_185_rule(Parser *p) return _seq; } -// _loop0_186: lambda_param_no_default +// _loop0_188: lambda_param_no_default static asdl_seq * -_loop0_186_rule(Parser *p) +_loop0_188_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36432,7 +37031,7 @@ _loop0_186_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_188[%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 @@ -36455,7 +37054,7 @@ _loop0_186_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_186[%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_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36472,9 +37071,9 @@ _loop0_186_rule(Parser *p) return _seq; } -// _loop0_188: ',' lambda_param +// _loop0_190: ',' lambda_param static asdl_seq * -_loop0_188_rule(Parser *p) +_loop0_190_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36500,7 +37099,7 @@ _loop0_188_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -36532,7 +37131,7 @@ _loop0_188_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_188[%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")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36549,9 +37148,9 @@ _loop0_188_rule(Parser *p) return _seq; } -// _gather_187: lambda_param _loop0_188 +// _gather_189: lambda_param _loop0_190 static asdl_seq * -_gather_187_rule(Parser *p) +_gather_189_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36563,27 +37162,27 @@ _gather_187_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_188 + { // lambda_param _loop0_190 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_188")); + D(fprintf(stderr, "%*c> _gather_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_188_rule(p)) // _loop0_188 + (seq = _loop0_190_rule(p)) // _loop0_190 ) { - D(fprintf(stderr, "%*c+ _gather_187[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_188")); + D(fprintf(stderr, "%*c+ _gather_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_189[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_190")); } _res = NULL; done: @@ -36591,9 +37190,9 @@ _gather_187_rule(Parser *p) return _res; } -// _tmp_189: lambda_slash_no_default | lambda_slash_with_default +// _tmp_191: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_189_rule(Parser *p) +_tmp_191_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36610,18 +37209,18 @@ _tmp_189_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_191[%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_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_191[%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_189[%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_slash_no_default")); } { // lambda_slash_with_default @@ -36629,18 +37228,18 @@ _tmp_189_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_191[%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_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_191[%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_189[%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_slash_with_default")); } _res = NULL; @@ -36649,9 +37248,9 @@ _tmp_189_rule(Parser *p) return _res; } -// _loop0_190: lambda_param_maybe_default +// _loop0_192: lambda_param_maybe_default static asdl_seq * -_loop0_190_rule(Parser *p) +_loop0_192_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36677,7 +37276,7 @@ _loop0_190_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_190[%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 @@ -36700,7 +37299,7 @@ _loop0_190_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_190[%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); @@ -36717,9 +37316,9 @@ _loop0_190_rule(Parser *p) return _seq; } -// _tmp_191: ',' | lambda_param_no_default +// _tmp_193: ',' | lambda_param_no_default static void * -_tmp_191_rule(Parser *p) +_tmp_193_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36736,18 +37335,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_193[%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_193[%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_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -36755,18 +37354,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_193[%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_193[%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_193[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -36775,9 +37374,9 @@ _tmp_191_rule(Parser *p) return _res; } -// _loop0_192: lambda_param_maybe_default +// _loop0_194: lambda_param_maybe_default static asdl_seq * -_loop0_192_rule(Parser *p) +_loop0_194_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36803,7 +37402,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_194[%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 @@ -36826,7 +37425,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_194[%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); @@ -36843,9 +37442,9 @@ _loop0_192_rule(Parser *p) return _seq; } -// _loop1_193: lambda_param_maybe_default +// _loop1_195: lambda_param_maybe_default static asdl_seq * -_loop1_193_rule(Parser *p) +_loop1_195_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36871,7 +37470,7 @@ _loop1_193_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop1_195[%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 @@ -36894,7 +37493,7 @@ _loop1_193_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_193[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -36916,9 +37515,9 @@ _loop1_193_rule(Parser *p) return _seq; } -// _loop1_194: lambda_param_with_default +// _loop1_196: lambda_param_with_default static asdl_seq * -_loop1_194_rule(Parser *p) +_loop1_196_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -36944,7 +37543,7 @@ _loop1_194_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop1_196[%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 @@ -36967,7 +37566,7 @@ _loop1_194_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_194[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_196[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } if (_n == 0 || p->error_indicator) { @@ -36989,9 +37588,9 @@ _loop1_194_rule(Parser *p) return _seq; } -// _tmp_195: ':' | ',' (':' | '**') +// _tmp_197: ':' | ',' (':' | '**') static void * -_tmp_195_rule(Parser *p) +_tmp_197_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37008,18 +37607,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_197[%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_197[%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_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -37027,21 +37626,21 @@ _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_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_262_var; + void *_tmp_264_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_262_var = _tmp_262_rule(p)) // ':' | '**' + (_tmp_264_var = _tmp_264_rule(p)) // ':' | '**' ) { - 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); + D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_264_var); 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_197[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -37050,9 +37649,9 @@ _tmp_195_rule(Parser *p) return _res; } -// _tmp_196: lambda_param_no_default | ',' +// _tmp_198: lambda_param_no_default | ',' static void * -_tmp_196_rule(Parser *p) +_tmp_198_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37069,18 +37668,18 @@ _tmp_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_196[%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_196[%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_196[%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")); } { // ',' @@ -37088,18 +37687,18 @@ _tmp_196_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_196[%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_196[%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_196[%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; @@ -37108,9 +37707,9 @@ _tmp_196_rule(Parser *p) return _res; } -// _loop0_197: lambda_param_maybe_default +// _loop0_199: lambda_param_maybe_default static asdl_seq * -_loop0_197_rule(Parser *p) +_loop0_199_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37136,7 +37735,7 @@ _loop0_197_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_199[%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 @@ -37159,7 +37758,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_199[%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); @@ -37176,9 +37775,9 @@ _loop0_197_rule(Parser *p) return _seq; } -// _tmp_198: lambda_param_no_default | ',' +// _tmp_200: lambda_param_no_default | ',' static void * -_tmp_198_rule(Parser *p) +_tmp_200_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37195,18 +37794,18 @@ _tmp_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_200[%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_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_200[%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_198[%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, "lambda_param_no_default")); } { // ',' @@ -37214,18 +37813,18 @@ _tmp_198_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_198[%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_198[%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_198[%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; @@ -37234,9 +37833,9 @@ _tmp_198_rule(Parser *p) return _res; } -// _tmp_199: '*' | '**' | '/' +// _tmp_201: '*' | '**' | '/' static void * -_tmp_199_rule(Parser *p) +_tmp_201_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37253,18 +37852,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -37272,18 +37871,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -37291,18 +37890,18 @@ _tmp_199_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_199[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_199[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -37311,9 +37910,9 @@ _tmp_199_rule(Parser *p) return _res; } -// _tmp_200: ',' | ')' | ':' +// _tmp_202: ',' | ')' | ':' static void * -_tmp_200_rule(Parser *p) +_tmp_202_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37330,18 +37929,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -37349,18 +37948,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ':' @@ -37368,18 +37967,18 @@ _tmp_200_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -37388,9 +37987,9 @@ _tmp_200_rule(Parser *p) return _res; } -// _loop0_202: ',' (expression ['as' star_target]) +// _loop0_204: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_202_rule(Parser *p) +_loop0_204_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37416,13 +38015,13 @@ _loop0_202_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_204[%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_263_rule(p)) // expression ['as' star_target] + (elem = _tmp_265_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37448,7 +38047,7 @@ _loop0_202_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_202[%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, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37465,9 +38064,9 @@ _loop0_202_rule(Parser *p) return _seq; } -// _gather_201: (expression ['as' star_target]) _loop0_202 +// _gather_203: (expression ['as' star_target]) _loop0_204 static asdl_seq * -_gather_201_rule(Parser *p) +_gather_203_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37479,27 +38078,27 @@ _gather_201_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_202 + { // (expression ['as' star_target]) _loop0_204 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); + D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_263_rule(p)) // expression ['as' star_target] + (elem = _tmp_265_rule(p)) // expression ['as' star_target] && - (seq = _loop0_202_rule(p)) // _loop0_202 + (seq = _loop0_204_rule(p)) // _loop0_204 ) { - D(fprintf(stderr, "%*c+ _gather_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); + D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['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_201[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_202")); + D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); } _res = NULL; done: @@ -37507,9 +38106,9 @@ _gather_201_rule(Parser *p) return _res; } -// _loop0_204: ',' (expressions ['as' star_target]) +// _loop0_206: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_204_rule(Parser *p) +_loop0_206_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37535,13 +38134,13 @@ _loop0_204_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_206[%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_264_rule(p)) // expressions ['as' star_target] + (elem = _tmp_266_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -37567,7 +38166,7 @@ _loop0_204_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_204[%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, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37584,9 +38183,9 @@ _loop0_204_rule(Parser *p) return _seq; } -// _gather_203: (expressions ['as' star_target]) _loop0_204 +// _gather_205: (expressions ['as' star_target]) _loop0_206 static asdl_seq * -_gather_203_rule(Parser *p) +_gather_205_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37598,27 +38197,27 @@ _gather_203_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_204 + { // (expressions ['as' star_target]) _loop0_206 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_264_rule(p)) // expressions ['as' star_target] + (elem = _tmp_266_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_204_rule(p)) // _loop0_204 + (seq = _loop0_206_rule(p)) // _loop0_206 ) { - D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['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_203[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); } _res = NULL; done: @@ -37626,9 +38225,9 @@ _gather_203_rule(Parser *p) return _res; } -// _loop0_206: ',' (expression ['as' star_target]) +// _loop0_208: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_206_rule(Parser *p) +_loop0_208_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37654,13 +38253,13 @@ _loop0_206_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_208[%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_265_rule(p)) // expression ['as' star_target] + (elem = _tmp_267_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -37686,7 +38285,7 @@ _loop0_206_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_206[%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, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -37703,9 +38302,9 @@ _loop0_206_rule(Parser *p) return _seq; } -// _gather_205: (expression ['as' star_target]) _loop0_206 +// _gather_207: (expression ['as' star_target]) _loop0_208 static asdl_seq * -_gather_205_rule(Parser *p) +_gather_207_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37717,27 +38316,27 @@ _gather_205_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_206 + { // (expression ['as' star_target]) _loop0_208 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = _tmp_267_rule(p)) // expression ['as' star_target] && - (seq = _loop0_206_rule(p)) // _loop0_206 + (seq = _loop0_208_rule(p)) // _loop0_208 ) { - D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['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_205[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); } _res = NULL; done: @@ -37745,9 +38344,9 @@ _gather_205_rule(Parser *p) return _res; } -// _loop0_208: ',' (expressions ['as' star_target]) +// _loop0_210: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_208_rule(Parser *p) +_loop0_210_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37773,13 +38372,13 @@ _loop0_208_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_210[%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_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_268_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -37805,7 +38404,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_210[%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); @@ -37822,9 +38421,9 @@ _loop0_208_rule(Parser *p) return _seq; } -// _gather_207: (expressions ['as' star_target]) _loop0_208 +// _gather_209: (expressions ['as' star_target]) _loop0_210 static asdl_seq * -_gather_207_rule(Parser *p) +_gather_209_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37836,27 +38435,27 @@ _gather_207_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_208 + { // (expressions ['as' star_target]) _loop0_210 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_268_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_208_rule(p)) // _loop0_208 + (seq = _loop0_210_rule(p)) // _loop0_210 ) { - D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_209[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); } _res = NULL; done: @@ -37864,9 +38463,9 @@ _gather_207_rule(Parser *p) return _res; } -// _tmp_209: 'except' | 'finally' +// _tmp_211: 'except' | 'finally' static void * -_tmp_209_rule(Parser *p) +_tmp_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37883,18 +38482,18 @@ _tmp_209_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -37902,18 +38501,18 @@ _tmp_209_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -37922,9 +38521,9 @@ _tmp_209_rule(Parser *p) return _res; } -// _loop0_210: block +// _loop0_212: block static asdl_seq * -_loop0_210_rule(Parser *p) +_loop0_212_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -37950,7 +38549,7 @@ _loop0_210_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -37973,7 +38572,7 @@ _loop0_210_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_212[%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); @@ -37990,9 +38589,9 @@ _loop0_210_rule(Parser *p) return _seq; } -// _loop1_211: except_block +// _loop1_213: except_block static asdl_seq * -_loop1_211_rule(Parser *p) +_loop1_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38018,7 +38617,7 @@ _loop1_211_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + D(fprintf(stderr, "%*c> _loop1_213[%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 @@ -38041,7 +38640,7 @@ _loop1_211_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_211[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_213[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { @@ -38063,9 +38662,9 @@ _loop1_211_rule(Parser *p) return _seq; } -// _tmp_212: 'as' NAME +// _tmp_214: 'as' NAME static void * -_tmp_212_rule(Parser *p) +_tmp_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38082,7 +38681,7 @@ _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_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38091,12 +38690,12 @@ _tmp_212_rule(Parser *p) (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_214[%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_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38105,9 +38704,9 @@ _tmp_212_rule(Parser *p) return _res; } -// _loop0_213: block +// _loop0_215: block static asdl_seq * -_loop0_213_rule(Parser *p) +_loop0_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38133,7 +38732,7 @@ _loop0_213_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38156,7 +38755,7 @@ _loop0_213_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_213[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_215[%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); @@ -38173,9 +38772,9 @@ _loop0_213_rule(Parser *p) return _seq; } -// _loop1_214: except_star_block +// _loop1_216: except_star_block static asdl_seq * -_loop1_214_rule(Parser *p) +_loop1_216_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38201,7 +38800,7 @@ _loop1_214_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c> _loop1_216[%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 @@ -38224,7 +38823,7 @@ _loop1_214_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_214[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_216[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); } if (_n == 0 || p->error_indicator) { @@ -38246,9 +38845,9 @@ _loop1_214_rule(Parser *p) return _seq; } -// _tmp_215: expression ['as' NAME] +// _tmp_217: expression ['as' NAME] static void * -_tmp_215_rule(Parser *p) +_tmp_217_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38265,22 +38864,22 @@ _tmp_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_217[%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_267_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_269_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_217[%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_215[%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, "expression ['as' NAME]")); } _res = NULL; @@ -38289,9 +38888,9 @@ _tmp_215_rule(Parser *p) return _res; } -// _tmp_216: 'as' NAME +// _tmp_218: 'as' NAME static void * -_tmp_216_rule(Parser *p) +_tmp_218_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38308,7 +38907,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, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38317,12 +38916,12 @@ _tmp_216_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_218[%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_216[%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, "'as' NAME")); } _res = NULL; @@ -38331,9 +38930,9 @@ _tmp_216_rule(Parser *p) return _res; } -// _tmp_217: 'as' NAME +// _tmp_219: 'as' NAME static void * -_tmp_217_rule(Parser *p) +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38350,7 +38949,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, "'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 ( @@ -38359,12 +38958,12 @@ _tmp_217_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_217[%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_217[%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; @@ -38373,9 +38972,9 @@ _tmp_217_rule(Parser *p) return _res; } -// _tmp_218: NEWLINE | ':' +// _tmp_220: NEWLINE | ':' static void * -_tmp_218_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38392,18 +38991,18 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_220[%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_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_220[%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_218[%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, "NEWLINE")); } { // ':' @@ -38411,18 +39010,18 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; 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_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -38431,9 +39030,9 @@ _tmp_218_rule(Parser *p) return _res; } -// _tmp_219: 'as' NAME +// _tmp_221: 'as' NAME static void * -_tmp_219_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38450,7 +39049,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, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38459,12 +39058,12 @@ _tmp_219_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_221[%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_219[%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, "'as' NAME")); } _res = NULL; @@ -38473,9 +39072,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _tmp_220: 'as' NAME +// _tmp_222: 'as' NAME static void * -_tmp_220_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38492,7 +39091,7 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38501,12 +39100,12 @@ _tmp_220_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_222[%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_220[%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, "'as' NAME")); } _res = NULL; @@ -38515,9 +39114,9 @@ _tmp_220_rule(Parser *p) return _res; } -// _tmp_221: positional_patterns ',' +// _tmp_223: positional_patterns ',' static void * -_tmp_221_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38534,7 +39133,7 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -38543,12 +39142,12 @@ _tmp_221_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_223[%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_221[%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, "positional_patterns ','")); } _res = NULL; @@ -38557,9 +39156,9 @@ _tmp_221_rule(Parser *p) return _res; } -// _tmp_222: '->' expression +// _tmp_224: '->' expression static void * -_tmp_222_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38576,7 +39175,7 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -38585,12 +39184,12 @@ _tmp_222_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_224[%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_222[%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, "'->' expression")); } _res = NULL; @@ -38599,9 +39198,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: '(' arguments? ')' +// _tmp_225: '(' arguments? ')' static void * -_tmp_223_rule(Parser *p) +_tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38618,7 +39217,7 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38631,12 +39230,12 @@ _tmp_223_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_225[%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_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38645,9 +39244,9 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: '(' arguments? ')' +// _tmp_226: '(' arguments? ')' static void * -_tmp_224_rule(Parser *p) +_tmp_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38664,7 +39263,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, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -38677,12 +39276,12 @@ _tmp_224_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_226[%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_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -38691,9 +39290,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _loop0_226: ',' double_starred_kvpair +// _loop0_228: ',' double_starred_kvpair static asdl_seq * -_loop0_226_rule(Parser *p) +_loop0_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38719,7 +39318,7 @@ _loop0_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -38751,7 +39350,7 @@ _loop0_226_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_228[%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); @@ -38768,9 +39367,9 @@ _loop0_226_rule(Parser *p) return _seq; } -// _gather_225: double_starred_kvpair _loop0_226 +// _gather_227: double_starred_kvpair _loop0_228 static asdl_seq * -_gather_225_rule(Parser *p) +_gather_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38782,27 +39381,27 @@ _gather_225_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_226 + { // double_starred_kvpair _loop0_228 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_226")); + D(fprintf(stderr, "%*c> _gather_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_226_rule(p)) // _loop0_226 + (seq = _loop0_228_rule(p)) // _loop0_228 ) { - D(fprintf(stderr, "%*c+ _gather_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_226")); + D(fprintf(stderr, "%*c+ _gather_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - 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")); + D(fprintf(stderr, "%*c%s _gather_227[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_228")); } _res = NULL; done: @@ -38810,9 +39409,9 @@ _gather_225_rule(Parser *p) return _res; } -// _tmp_227: '}' | ',' +// _tmp_229: '}' | ',' static void * -_tmp_227_rule(Parser *p) +_tmp_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38829,18 +39428,18 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; 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_229[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -38848,18 +39447,18 @@ _tmp_227_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; 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_229[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -38868,9 +39467,9 @@ _tmp_227_rule(Parser *p) return _res; } -// _tmp_228: '}' | ',' +// _tmp_230: '}' | ',' static void * -_tmp_228_rule(Parser *p) +_tmp_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38887,18 +39486,18 @@ _tmp_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; 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_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -38906,18 +39505,18 @@ _tmp_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; 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_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -38926,9 +39525,9 @@ _tmp_228_rule(Parser *p) return _res; } -// _tmp_229: yield_expr | star_expressions +// _tmp_231: yield_expr | star_expressions static void * -_tmp_229_rule(Parser *p) +_tmp_231_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38945,18 +39544,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_231[%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")); + D(fprintf(stderr, "%*c+ _tmp_231[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -38964,18 +39563,18 @@ _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_expressions")); + D(fprintf(stderr, "%*c> _tmp_231[%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")); + D(fprintf(stderr, "%*c+ _tmp_231[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -38984,9 +39583,9 @@ _tmp_229_rule(Parser *p) return _res; } -// _tmp_230: yield_expr | star_expressions +// _tmp_232: yield_expr | star_expressions static void * -_tmp_230_rule(Parser *p) +_tmp_232_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39003,18 +39602,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + 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_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "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_230[%d-%d]: %s failed!\n", p->level, ' ', + 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 @@ -39022,18 +39621,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + 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_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "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_230[%d-%d]: %s failed!\n", p->level, ' ', + 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; @@ -39042,9 +39641,9 @@ _tmp_230_rule(Parser *p) return _res; } -// _tmp_231: '=' | '!' | ':' | '}' +// _tmp_233: '=' | '!' | ':' | '}' static void * -_tmp_231_rule(Parser *p) +_tmp_233_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39061,18 +39660,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_233[%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, "'='")); + 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_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -39080,18 +39679,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + 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_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + 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_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39099,18 +39698,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + 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_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + 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_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39118,18 +39717,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + 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_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + 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_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39138,9 +39737,9 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: yield_expr | star_expressions +// _tmp_234: yield_expr | star_expressions static void * -_tmp_232_rule(Parser *p) +_tmp_234_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39157,18 +39756,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, "yield_expr")); + 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_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "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_232[%d-%d]: %s failed!\n", p->level, ' ', + 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 @@ -39176,18 +39775,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, "star_expressions")); + 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_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "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_232[%d-%d]: %s failed!\n", p->level, ' ', + 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; @@ -39196,9 +39795,9 @@ _tmp_232_rule(Parser *p) return _res; } -// _tmp_233: '!' | ':' | '}' +// _tmp_235: '!' | ':' | '}' static void * -_tmp_233_rule(Parser *p) +_tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39215,18 +39814,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_235[%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, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_235[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39234,18 +39833,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_235[%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, "':'")); + D(fprintf(stderr, "%*c+ _tmp_235[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39253,18 +39852,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_235[%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, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_235[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39273,9 +39872,9 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: yield_expr | star_expressions +// _tmp_236: yield_expr | star_expressions static void * -_tmp_234_rule(Parser *p) +_tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39292,18 +39891,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_236[%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")); + D(fprintf(stderr, "%*c+ _tmp_236[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39311,18 +39910,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_236[%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")); + D(fprintf(stderr, "%*c+ _tmp_236[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39331,9 +39930,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: yield_expr | star_expressions +// _tmp_237: yield_expr | star_expressions static void * -_tmp_235_rule(Parser *p) +_tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39350,18 +39949,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, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_237[%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")); + D(fprintf(stderr, "%*c+ _tmp_237[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39369,18 +39968,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, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_237[%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")); + D(fprintf(stderr, "%*c+ _tmp_237[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39389,9 +39988,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: '!' NAME +// _tmp_238: '!' NAME static void * -_tmp_236_rule(Parser *p) +_tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39408,7 +40007,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, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39417,12 +40016,12 @@ _tmp_236_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_238[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39431,9 +40030,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: ':' | '}' +// _tmp_239: ':' | '}' static void * -_tmp_237_rule(Parser *p) +_tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39450,18 +40049,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_239[%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, "':'")); + D(fprintf(stderr, "%*c+ _tmp_239[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39469,18 +40068,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_239[%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, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_239[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39489,9 +40088,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: yield_expr | star_expressions +// _tmp_240: yield_expr | star_expressions static void * -_tmp_238_rule(Parser *p) +_tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39508,18 +40107,18 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_240[%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")); + D(fprintf(stderr, "%*c+ _tmp_240[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39527,18 +40126,18 @@ _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_expressions")); + D(fprintf(stderr, "%*c> _tmp_240[%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")); + D(fprintf(stderr, "%*c+ _tmp_240[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39547,9 +40146,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: '!' NAME +// _tmp_241: '!' NAME static void * -_tmp_239_rule(Parser *p) +_tmp_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39566,7 +40165,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, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39575,12 +40174,12 @@ _tmp_239_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_241[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39589,9 +40188,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _loop0_240: fstring_format_spec +// _loop0_242: fstring_format_spec static asdl_seq * -_loop0_240_rule(Parser *p) +_loop0_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39617,7 +40216,7 @@ _loop0_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_242[%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 @@ -39640,7 +40239,7 @@ _loop0_240_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_242[%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); @@ -39657,9 +40256,9 @@ _loop0_240_rule(Parser *p) return _seq; } -// _tmp_241: yield_expr | star_expressions +// _tmp_243: yield_expr | star_expressions static void * -_tmp_241_rule(Parser *p) +_tmp_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39676,18 +40275,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, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_243[%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")); + D(fprintf(stderr, "%*c+ _tmp_243[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39695,18 +40294,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, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_243[%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")); + D(fprintf(stderr, "%*c+ _tmp_243[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39715,9 +40314,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _tmp_242: '!' NAME +// _tmp_244: '!' NAME static void * -_tmp_242_rule(Parser *p) +_tmp_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39734,7 +40333,7 @@ _tmp_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -39743,12 +40342,12 @@ _tmp_242_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_244[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -39757,9 +40356,9 @@ _tmp_242_rule(Parser *p) return _res; } -// _tmp_243: ':' | '}' +// _tmp_245: ':' | '}' static void * -_tmp_243_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39776,18 +40375,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%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, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_243[%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_243[%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, "':'")); } { // '}' @@ -39795,18 +40394,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%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, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_243[%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_243[%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; @@ -39815,9 +40414,9 @@ _tmp_243_rule(Parser *p) return _res; } -// _tmp_244: star_targets '=' +// _tmp_246: star_targets '=' static void * -_tmp_244_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39834,7 +40433,7 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -39843,7 +40442,7 @@ _tmp_244_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -39853,7 +40452,7 @@ _tmp_244_rule(Parser *p) 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_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -39862,9 +40461,9 @@ _tmp_244_rule(Parser *p) return _res; } -// _tmp_245: '.' | '...' +// _tmp_247: '.' | '...' static void * -_tmp_245_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39881,18 +40480,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; 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_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -39900,18 +40499,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; 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_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -39920,9 +40519,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: '.' | '...' +// _tmp_248: '.' | '...' static void * -_tmp_246_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39939,18 +40538,18 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; 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_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -39958,18 +40557,18 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; 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_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -39978,9 +40577,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: '@' named_expression NEWLINE +// _tmp_249: '@' named_expression NEWLINE static void * -_tmp_247_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39997,7 +40596,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, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -40009,7 +40608,7 @@ _tmp_247_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40019,7 +40618,7 @@ _tmp_247_rule(Parser *p) 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_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -40028,9 +40627,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: ',' expression +// _tmp_250: ',' expression static void * -_tmp_248_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40047,7 +40646,7 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -40056,7 +40655,7 @@ _tmp_248_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40066,7 +40665,7 @@ _tmp_248_rule(Parser *p) 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_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -40075,9 +40674,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: ',' star_expression +// _tmp_251: ',' star_expression static void * -_tmp_249_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40094,7 +40693,7 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -40103,7 +40702,7 @@ _tmp_249_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40113,7 +40712,7 @@ _tmp_249_rule(Parser *p) 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_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -40122,9 +40721,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: 'or' conjunction +// _tmp_252: 'or' conjunction static void * -_tmp_250_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40141,7 +40740,7 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -40150,7 +40749,7 @@ _tmp_250_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40160,7 +40759,7 @@ _tmp_250_rule(Parser *p) 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_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -40169,9 +40768,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: 'and' inversion +// _tmp_253: 'and' inversion static void * -_tmp_251_rule(Parser *p) +_tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40188,7 +40787,7 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -40197,7 +40796,7 @@ _tmp_251_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40207,7 +40806,7 @@ _tmp_251_rule(Parser *p) 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_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -40216,9 +40815,9 @@ _tmp_251_rule(Parser *p) return _res; } -// _tmp_252: slice | starred_expression +// _tmp_254: slice | starred_expression static void * -_tmp_252_rule(Parser *p) +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40235,18 +40834,18 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_254[%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_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_254[%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_252[%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, "slice")); } { // starred_expression @@ -40254,18 +40853,18 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_254[%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_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_254[%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_252[%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, "starred_expression")); } _res = NULL; @@ -40274,9 +40873,9 @@ _tmp_252_rule(Parser *p) return _res; } -// _tmp_253: fstring | string +// _tmp_255: fstring | string static void * -_tmp_253_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40293,18 +40892,18 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_255[%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")); + D(fprintf(stderr, "%*c+ _tmp_255[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -40312,18 +40911,18 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_255[%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")); + D(fprintf(stderr, "%*c+ _tmp_255[%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, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -40332,9 +40931,9 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: 'if' disjunction +// _tmp_256: 'if' disjunction static void * -_tmp_254_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40351,7 +40950,7 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40360,7 +40959,7 @@ _tmp_254_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40370,7 +40969,7 @@ _tmp_254_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%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, "'if' disjunction")); } _res = NULL; @@ -40379,9 +40978,9 @@ _tmp_254_rule(Parser *p) return _res; } -// _tmp_255: 'if' disjunction +// _tmp_257: 'if' disjunction static void * -_tmp_255_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40398,7 +40997,7 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40407,7 +41006,7 @@ _tmp_255_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40417,7 +41016,7 @@ _tmp_255_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%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, "'if' disjunction")); } _res = NULL; @@ -40426,9 +41025,9 @@ _tmp_255_rule(Parser *p) return _res; } -// _tmp_256: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_258: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_256_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40445,18 +41044,18 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_258[%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_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_258[%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_256[%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, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -40464,20 +41063,20 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_268_var; + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_270_var; if ( - (_tmp_268_var = _tmp_268_rule(p)) // assignment_expression | expression !':=' + (_tmp_270_var = _tmp_270_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_268_var; + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_270_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%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, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -40486,9 +41085,9 @@ _tmp_256_rule(Parser *p) return _res; } -// _tmp_257: ',' star_target +// _tmp_259: ',' star_target static void * -_tmp_257_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40505,7 +41104,7 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40514,7 +41113,7 @@ _tmp_257_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40524,7 +41123,7 @@ _tmp_257_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%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_target")); } _res = NULL; @@ -40533,9 +41132,9 @@ _tmp_257_rule(Parser *p) return _res; } -// _tmp_258: ',' star_target +// _tmp_260: ',' star_target static void * -_tmp_258_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40552,7 +41151,7 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -40561,7 +41160,7 @@ _tmp_258_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40571,7 +41170,7 @@ _tmp_258_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%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_target")); } _res = NULL; @@ -40580,9 +41179,9 @@ _tmp_258_rule(Parser *p) return _res; } -// _tmp_259: star_targets '=' +// _tmp_261: star_targets '=' static void * -_tmp_259_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40599,7 +41198,7 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40608,12 +41207,12 @@ _tmp_259_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_261[%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_259[%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, "star_targets '='")); } _res = NULL; @@ -40622,9 +41221,9 @@ _tmp_259_rule(Parser *p) return _res; } -// _tmp_260: star_targets '=' +// _tmp_262: star_targets '=' static void * -_tmp_260_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40641,7 +41240,7 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -40650,12 +41249,12 @@ _tmp_260_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_262[%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_260[%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, "star_targets '='")); } _res = NULL; @@ -40664,9 +41263,9 @@ _tmp_260_rule(Parser *p) return _res; } -// _tmp_261: ')' | '**' +// _tmp_263: ')' | '**' static void * -_tmp_261_rule(Parser *p) +_tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40683,18 +41282,18 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%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, "')'")); } { // '**' @@ -40702,18 +41301,18 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%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, "'**'")); } _res = NULL; @@ -40722,9 +41321,9 @@ _tmp_261_rule(Parser *p) return _res; } -// _tmp_262: ':' | '**' +// _tmp_264: ':' | '**' static void * -_tmp_262_rule(Parser *p) +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40741,18 +41340,18 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%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, "':'")); } { // '**' @@ -40760,18 +41359,18 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%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, "'**'")); } _res = NULL; @@ -40780,9 +41379,9 @@ _tmp_262_rule(Parser *p) return _res; } -// _tmp_263: expression ['as' star_target] +// _tmp_265: expression ['as' star_target] static void * -_tmp_263_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40799,22 +41398,22 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%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_269_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_263[%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_263[%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; @@ -40823,9 +41422,9 @@ _tmp_263_rule(Parser *p) return _res; } -// _tmp_264: expressions ['as' star_target] +// _tmp_266: expressions ['as' star_target] static void * -_tmp_264_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40842,22 +41441,22 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%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_270_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_264[%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_264[%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; @@ -40866,9 +41465,9 @@ _tmp_264_rule(Parser *p) return _res; } -// _tmp_265: expression ['as' star_target] +// _tmp_267: expression ['as' star_target] static void * -_tmp_265_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40885,22 +41484,22 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_267[%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_271_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_267[%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_265[%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, "expression ['as' star_target]")); } _res = NULL; @@ -40909,9 +41508,9 @@ _tmp_265_rule(Parser *p) return _res; } -// _tmp_266: expressions ['as' star_target] +// _tmp_268: expressions ['as' star_target] static void * -_tmp_266_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40928,22 +41527,22 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_268[%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_272_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_268[%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_266[%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, "expressions ['as' star_target]")); } _res = NULL; @@ -40952,9 +41551,9 @@ _tmp_266_rule(Parser *p) return _res; } -// _tmp_267: 'as' NAME +// _tmp_269: 'as' NAME static void * -_tmp_267_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40971,7 +41570,7 @@ _tmp_267_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -40980,12 +41579,12 @@ _tmp_267_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_269[%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_267[%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' NAME")); } _res = NULL; @@ -40994,9 +41593,9 @@ _tmp_267_rule(Parser *p) return _res; } -// _tmp_268: assignment_expression | expression !':=' +// _tmp_270: assignment_expression | expression !':=' static void * -_tmp_268_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41013,18 +41612,18 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_270[%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_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_270[%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_268[%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, "assignment_expression")); } { // expression !':=' @@ -41032,7 +41631,7 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -41040,12 +41639,12 @@ _tmp_268_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_270[%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_268[%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, "expression !':='")); } _res = NULL; @@ -41054,9 +41653,9 @@ _tmp_268_rule(Parser *p) return _res; } -// _tmp_269: 'as' star_target +// _tmp_271: 'as' star_target static void * -_tmp_269_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41073,7 +41672,7 @@ _tmp_269_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_269[%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 ( @@ -41082,12 +41681,12 @@ _tmp_269_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_269[%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_269[%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; @@ -41096,9 +41695,9 @@ _tmp_269_rule(Parser *p) return _res; } -// _tmp_270: 'as' star_target +// _tmp_272: 'as' star_target static void * -_tmp_270_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41115,7 +41714,7 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%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 ( @@ -41124,12 +41723,12 @@ _tmp_270_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_270[%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_270[%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; @@ -41138,9 +41737,9 @@ _tmp_270_rule(Parser *p) return _res; } -// _tmp_271: 'as' star_target +// _tmp_273: 'as' star_target static void * -_tmp_271_rule(Parser *p) +_tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41157,7 +41756,7 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41166,12 +41765,12 @@ _tmp_271_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_273[%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_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41180,9 +41779,9 @@ _tmp_271_rule(Parser *p) return _res; } -// _tmp_272: 'as' star_target +// _tmp_274: 'as' star_target static void * -_tmp_272_rule(Parser *p) +_tmp_274_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41199,7 +41798,7 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41208,12 +41807,12 @@ _tmp_272_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_274[%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_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 81ab71c0fc3b..d62cccbb6e24 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -131,6 +131,7 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->Not_type); Py_CLEAR(state->Or_singleton); Py_CLEAR(state->Or_type); + Py_CLEAR(state->ParamSpec_type); Py_CLEAR(state->Pass_type); Py_CLEAR(state->Pow_singleton); Py_CLEAR(state->Pow_type); @@ -150,7 +151,10 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->TryStar_type); Py_CLEAR(state->Try_type); Py_CLEAR(state->Tuple_type); + Py_CLEAR(state->TypeAlias_type); Py_CLEAR(state->TypeIgnore_type); + Py_CLEAR(state->TypeVarTuple_type); + Py_CLEAR(state->TypeVar_type); Py_CLEAR(state->UAdd_singleton); Py_CLEAR(state->UAdd_type); Py_CLEAR(state->USub_singleton); @@ -179,6 +183,7 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->bases); Py_CLEAR(state->body); Py_CLEAR(state->boolop_type); + Py_CLEAR(state->bound); Py_CLEAR(state->cases); Py_CLEAR(state->cause); Py_CLEAR(state->cls); @@ -256,6 +261,8 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->type_comment); Py_CLEAR(state->type_ignore_type); Py_CLEAR(state->type_ignores); + Py_CLEAR(state->typeparam_type); + Py_CLEAR(state->typeparams); Py_CLEAR(state->unaryop_type); Py_CLEAR(state->upper); Py_CLEAR(state->value); @@ -289,6 +296,7 @@ static int init_identifiers(struct ast_state *state) if ((state->attr = PyUnicode_InternFromString("attr")) == NULL) return 0; if ((state->bases = PyUnicode_InternFromString("bases")) == NULL) return 0; if ((state->body = PyUnicode_InternFromString("body")) == NULL) return 0; + if ((state->bound = PyUnicode_InternFromString("bound")) == NULL) return 0; if ((state->cases = PyUnicode_InternFromString("cases")) == NULL) return 0; if ((state->cause = PyUnicode_InternFromString("cause")) == NULL) return 0; if ((state->cls = PyUnicode_InternFromString("cls")) == NULL) return 0; @@ -354,6 +362,7 @@ static int init_identifiers(struct ast_state *state) if ((state->type = PyUnicode_InternFromString("type")) == NULL) return 0; if ((state->type_comment = PyUnicode_InternFromString("type_comment")) == NULL) return 0; if ((state->type_ignores = PyUnicode_InternFromString("type_ignores")) == NULL) return 0; + if ((state->typeparams = PyUnicode_InternFromString("typeparams")) == NULL) return 0; if ((state->upper = PyUnicode_InternFromString("upper")) == NULL) return 0; if ((state->value = PyUnicode_InternFromString("value")) == NULL) return 0; if ((state->values = PyUnicode_InternFromString("values")) == NULL) return 0; @@ -374,6 +383,7 @@ GENERATE_ASDL_SEQ_CONSTRUCTOR(withitem, withitem_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(match_case, match_case_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(pattern, pattern_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(type_ignore, type_ignore_ty) +GENERATE_ASDL_SEQ_CONSTRUCTOR(typeparam, typeparam_ty) static PyObject* ast2obj_mod(struct ast_state *state, void*); static const char * const Module_fields[]={ @@ -399,6 +409,7 @@ static const char * const stmt_attributes[] = { static PyObject* ast2obj_stmt(struct ast_state *state, void*); static const char * const FunctionDef_fields[]={ "name", + "typeparams", "args", "body", "decorator_list", @@ -407,6 +418,7 @@ static const char * const FunctionDef_fields[]={ }; static const char * const AsyncFunctionDef_fields[]={ "name", + "typeparams", "args", "body", "decorator_list", @@ -415,6 +427,7 @@ static const char * const AsyncFunctionDef_fields[]={ }; static const char * const ClassDef_fields[]={ "name", + "typeparams", "bases", "keywords", "body", @@ -431,6 +444,11 @@ static const char * const Assign_fields[]={ "value", "type_comment", }; +static const char * const TypeAlias_fields[]={ + "name", + "typeparams", + "value", +}; static const char * const AugAssign_fields[]={ "target", "op", @@ -757,6 +775,23 @@ static const char * const TypeIgnore_fields[]={ "lineno", "tag", }; +static const char * const typeparam_attributes[] = { + "lineno", + "col_offset", + "end_lineno", + "end_col_offset", +}; +static PyObject* ast2obj_typeparam(struct ast_state *state, void*); +static const char * const TypeVar_fields[]={ + "name", + "bound", +}; +static const char * const ParamSpec_fields[]={ + "name", +}; +static const char * const TypeVarTuple_fields[]={ + "name", +}; @@ -1134,12 +1169,13 @@ init_types(struct ast_state *state) "FunctionType(expr* argtypes, expr returns)"); if (!state->FunctionType_type) return 0; state->stmt_type = make_type(state, "stmt", state->AST_type, NULL, 0, - "stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" - " | AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" - " | ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)\n" + "stmt = FunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" + " | AsyncFunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" + " | ClassDef(identifier name, typeparam* typeparams, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)\n" " | Return(expr? value)\n" " | Delete(expr* targets)\n" " | Assign(expr* targets, expr value, string? type_comment)\n" + " | TypeAlias(expr name, typeparam* typeparams, expr value)\n" " | AugAssign(expr target, operator op, expr value)\n" " | AnnAssign(expr target, expr annotation, expr? value, int simple)\n" " | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)\n" @@ -1169,8 +1205,8 @@ init_types(struct ast_state *state) -1) return 0; state->FunctionDef_type = make_type(state, "FunctionDef", state->stmt_type, - FunctionDef_fields, 6, - "FunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); + FunctionDef_fields, 7, + "FunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); if (!state->FunctionDef_type) return 0; if (PyObject_SetAttr(state->FunctionDef_type, state->returns, Py_None) == -1) @@ -1180,8 +1216,8 @@ init_types(struct ast_state *state) return 0; state->AsyncFunctionDef_type = make_type(state, "AsyncFunctionDef", state->stmt_type, - AsyncFunctionDef_fields, 6, - "AsyncFunctionDef(identifier name, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); + AsyncFunctionDef_fields, 7, + "AsyncFunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); if (!state->AsyncFunctionDef_type) return 0; if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->returns, Py_None) == -1) @@ -1190,8 +1226,8 @@ init_types(struct ast_state *state) Py_None) == -1) return 0; state->ClassDef_type = make_type(state, "ClassDef", state->stmt_type, - ClassDef_fields, 5, - "ClassDef(identifier name, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)"); + ClassDef_fields, 6, + "ClassDef(identifier name, typeparam* typeparams, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)"); if (!state->ClassDef_type) return 0; state->Return_type = make_type(state, "Return", state->stmt_type, Return_fields, 1, @@ -1210,6 +1246,10 @@ init_types(struct ast_state *state) if (PyObject_SetAttr(state->Assign_type, state->type_comment, Py_None) == -1) return 0; + state->TypeAlias_type = make_type(state, "TypeAlias", state->stmt_type, + TypeAlias_fields, 3, + "TypeAlias(expr name, typeparam* typeparams, expr value)"); + if (!state->TypeAlias_type) return 0; state->AugAssign_type = make_type(state, "AugAssign", state->stmt_type, AugAssign_fields, 3, "AugAssign(expr target, operator op, expr value)"); @@ -1854,6 +1894,36 @@ init_types(struct ast_state *state) TypeIgnore_fields, 2, "TypeIgnore(int lineno, string tag)"); if (!state->TypeIgnore_type) return 0; + state->typeparam_type = make_type(state, "typeparam", state->AST_type, + NULL, 0, + "typeparam = TypeVar(identifier name, expr? bound)\n" + " | ParamSpec(identifier name)\n" + " | TypeVarTuple(identifier name)"); + if (!state->typeparam_type) return 0; + if (!add_attributes(state, state->typeparam_type, typeparam_attributes, 4)) + return 0; + if (PyObject_SetAttr(state->typeparam_type, state->end_lineno, Py_None) == + -1) + return 0; + if (PyObject_SetAttr(state->typeparam_type, state->end_col_offset, Py_None) + == -1) + return 0; + state->TypeVar_type = make_type(state, "TypeVar", state->typeparam_type, + TypeVar_fields, 2, + "TypeVar(identifier name, expr? bound)"); + if (!state->TypeVar_type) return 0; + if (PyObject_SetAttr(state->TypeVar_type, state->bound, Py_None) == -1) + return 0; + state->ParamSpec_type = make_type(state, "ParamSpec", + state->typeparam_type, ParamSpec_fields, + 1, + "ParamSpec(identifier name)"); + if (!state->ParamSpec_type) return 0; + state->TypeVarTuple_type = make_type(state, "TypeVarTuple", + state->typeparam_type, + TypeVarTuple_fields, 1, + "TypeVarTuple(identifier name)"); + if (!state->TypeVarTuple_type) return 0; state->recursion_depth = 0; state->recursion_limit = 0; @@ -1897,6 +1967,8 @@ static int obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, PyArena* arena); static int obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* out, PyArena* arena); +static int obj2ast_typeparam(struct ast_state *state, PyObject* obj, + typeparam_ty* out, PyArena* arena); mod_ty _PyAST_Module(asdl_stmt_seq * body, asdl_type_ignore_seq * type_ignores, @@ -1960,10 +2032,11 @@ _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena) } stmt_ty -_PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body, - asdl_expr_seq * decorator_list, expr_ty returns, string - type_comment, int lineno, int col_offset, int end_lineno, - int end_col_offset, PyArena *arena) +_PyAST_FunctionDef(identifier name, asdl_typeparam_seq * typeparams, + arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * + decorator_list, expr_ty returns, string type_comment, int + lineno, int col_offset, int end_lineno, int end_col_offset, + PyArena *arena) { stmt_ty p; if (!name) { @@ -1981,6 +2054,7 @@ _PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body, return NULL; p->kind = FunctionDef_kind; p->v.FunctionDef.name = name; + p->v.FunctionDef.typeparams = typeparams; p->v.FunctionDef.args = args; p->v.FunctionDef.body = body; p->v.FunctionDef.decorator_list = decorator_list; @@ -1994,10 +2068,11 @@ _PyAST_FunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * body, } stmt_ty -_PyAST_AsyncFunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * - body, asdl_expr_seq * decorator_list, expr_ty returns, - string type_comment, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena) +_PyAST_AsyncFunctionDef(identifier name, asdl_typeparam_seq * typeparams, + arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq + * decorator_list, expr_ty returns, string type_comment, + int lineno, int col_offset, int end_lineno, int + end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { @@ -2015,6 +2090,7 @@ _PyAST_AsyncFunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * return NULL; p->kind = AsyncFunctionDef_kind; p->v.AsyncFunctionDef.name = name; + p->v.AsyncFunctionDef.typeparams = typeparams; p->v.AsyncFunctionDef.args = args; p->v.AsyncFunctionDef.body = body; p->v.AsyncFunctionDef.decorator_list = decorator_list; @@ -2028,10 +2104,10 @@ _PyAST_AsyncFunctionDef(identifier name, arguments_ty args, asdl_stmt_seq * } stmt_ty -_PyAST_ClassDef(identifier name, asdl_expr_seq * bases, asdl_keyword_seq * - keywords, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, - int lineno, int col_offset, int end_lineno, int end_col_offset, - PyArena *arena) +_PyAST_ClassDef(identifier name, asdl_typeparam_seq * typeparams, asdl_expr_seq + * bases, asdl_keyword_seq * keywords, asdl_stmt_seq * body, + asdl_expr_seq * decorator_list, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; if (!name) { @@ -2044,6 +2120,7 @@ _PyAST_ClassDef(identifier name, asdl_expr_seq * bases, asdl_keyword_seq * return NULL; p->kind = ClassDef_kind; p->v.ClassDef.name = name; + p->v.ClassDef.typeparams = typeparams; p->v.ClassDef.bases = bases; p->v.ClassDef.keywords = keywords; p->v.ClassDef.body = body; @@ -2114,6 +2191,36 @@ _PyAST_Assign(asdl_expr_seq * targets, expr_ty value, string type_comment, int return p; } +stmt_ty +_PyAST_TypeAlias(expr_ty name, asdl_typeparam_seq * typeparams, expr_ty value, + int lineno, int col_offset, int end_lineno, int + end_col_offset, PyArena *arena) +{ + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field 'name' is required for TypeAlias"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field 'value' is required for TypeAlias"); + return NULL; + } + p = (stmt_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = TypeAlias_kind; + p->v.TypeAlias.name = name; + p->v.TypeAlias.typeparams = typeparams; + p->v.TypeAlias.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + stmt_ty _PyAST_AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) @@ -3606,6 +3713,73 @@ _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena) return p; } +typeparam_ty +_PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) +{ + typeparam_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field 'name' is required for TypeVar"); + return NULL; + } + p = (typeparam_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = TypeVar_kind; + p->v.TypeVar.name = name; + p->v.TypeVar.bound = bound; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +typeparam_ty +_PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno, + int end_col_offset, PyArena *arena) +{ + typeparam_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field 'name' is required for ParamSpec"); + return NULL; + } + p = (typeparam_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = ParamSpec_kind; + p->v.ParamSpec.name = name; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + +typeparam_ty +_PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena) +{ + typeparam_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field 'name' is required for TypeVarTuple"); + return NULL; + } + p = (typeparam_ty)_PyArena_Malloc(arena, sizeof(*p)); + if (!p) + return NULL; + p->kind = TypeVarTuple_kind; + p->v.TypeVarTuple.name = name; + p->lineno = lineno; + p->col_offset = col_offset; + p->end_lineno = end_lineno; + p->end_col_offset = end_col_offset; + return p; +} + PyObject* ast2obj_mod(struct ast_state *state, void* _o) @@ -3708,6 +3882,12 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.typeparams, + ast2obj_typeparam); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->typeparams, value) == -1) + goto failed; + Py_DECREF(value); value = ast2obj_arguments(state, o->v.FunctionDef.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) @@ -3745,6 +3925,13 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(state, + (asdl_seq*)o->v.AsyncFunctionDef.typeparams, + ast2obj_typeparam); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->typeparams, value) == -1) + goto failed; + Py_DECREF(value); value = ast2obj_arguments(state, o->v.AsyncFunctionDef.args); if (!value) goto failed; if (PyObject_SetAttr(result, state->args, value) == -1) @@ -3783,6 +3970,12 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.typeparams, + ast2obj_typeparam); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->typeparams, value) == -1) + goto failed; + Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.bases, ast2obj_expr); if (!value) goto failed; @@ -3850,6 +4043,27 @@ ast2obj_stmt(struct ast_state *state, void* _o) goto failed; Py_DECREF(value); break; + case TypeAlias_kind: + tp = (PyTypeObject *)state->TypeAlias_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(state, o->v.TypeAlias.name); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->name, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(state, (asdl_seq*)o->v.TypeAlias.typeparams, + ast2obj_typeparam); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->typeparams, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(state, o->v.TypeAlias.value); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->value, value) == -1) + goto failed; + Py_DECREF(value); + break; case AugAssign_kind: tp = (PyTypeObject *)state->AugAssign_type; result = PyType_GenericNew(tp, NULL, NULL); @@ -5441,6 +5655,85 @@ ast2obj_type_ignore(struct ast_state *state, void* _o) return NULL; } +PyObject* +ast2obj_typeparam(struct ast_state *state, void* _o) +{ + typeparam_ty o = (typeparam_ty)_o; + PyObject *result = NULL, *value = NULL; + PyTypeObject *tp; + if (!o) { + Py_RETURN_NONE; + } + if (++state->recursion_depth > state->recursion_limit) { + PyErr_SetString(PyExc_RecursionError, + "maximum recursion depth exceeded during ast construction"); + return 0; + } + switch (o->kind) { + case TypeVar_kind: + tp = (PyTypeObject *)state->TypeVar_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(state, o->v.TypeVar.name); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->name, value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(state, o->v.TypeVar.bound); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->bound, value) == -1) + goto failed; + Py_DECREF(value); + break; + case ParamSpec_kind: + tp = (PyTypeObject *)state->ParamSpec_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(state, o->v.ParamSpec.name); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->name, value) == -1) + goto failed; + Py_DECREF(value); + break; + case TypeVarTuple_kind: + tp = (PyTypeObject *)state->TypeVarTuple_type; + result = PyType_GenericNew(tp, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(state, o->v.TypeVarTuple.name); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->name, value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(state, o->lineno); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(state, o->col_offset); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->col_offset, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(state, o->end_lineno); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->end_lineno, value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(state, o->end_col_offset); + if (!value) goto failed; + if (PyObject_SetAttr(result, state->end_col_offset, value) < 0) + goto failed; + Py_DECREF(value); + state->recursion_depth--; + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + int obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) @@ -5781,6 +6074,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; + asdl_typeparam_seq* typeparams; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; @@ -5804,6 +6098,42 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } + if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from FunctionDef"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "FunctionDef field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + typeparams = _Py_asdl_typeparam_seq_new(len, arena); + if (typeparams == NULL) goto failed; + for (i = 0; i < len; i++) { + typeparam_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { + goto failed; + } + res = obj2ast_typeparam(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"typeparams\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(typeparams, i, val); + } + Py_CLEAR(tmp); + } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } @@ -5927,9 +6257,9 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_FunctionDef(name, args, body, decorator_list, returns, - type_comment, lineno, col_offset, end_lineno, - end_col_offset, arena); + *out = _PyAST_FunctionDef(name, typeparams, args, body, decorator_list, + returns, type_comment, lineno, col_offset, + end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; } @@ -5940,6 +6270,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; + asdl_typeparam_seq* typeparams; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; @@ -5963,6 +6294,42 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } + if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from AsyncFunctionDef"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + typeparams = _Py_asdl_typeparam_seq_new(len, arena); + if (typeparams == NULL) goto failed; + for (i = 0; i < len; i++) { + typeparam_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { + goto failed; + } + res = obj2ast_typeparam(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"typeparams\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(typeparams, i, val); + } + Py_CLEAR(tmp); + } if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { return 1; } @@ -6086,10 +6453,10 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_AsyncFunctionDef(name, args, body, decorator_list, - returns, type_comment, lineno, - col_offset, end_lineno, end_col_offset, - arena); + *out = _PyAST_AsyncFunctionDef(name, typeparams, args, body, + decorator_list, returns, type_comment, + lineno, col_offset, end_lineno, + end_col_offset, arena); if (*out == NULL) goto failed; return 0; } @@ -6100,6 +6467,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; + asdl_typeparam_seq* typeparams; asdl_expr_seq* bases; asdl_keyword_seq* keywords; asdl_stmt_seq* body; @@ -6122,6 +6490,42 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } + if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from ClassDef"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "ClassDef field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + typeparams = _Py_asdl_typeparam_seq_new(len, arena); + if (typeparams == NULL) goto failed; + for (i = 0; i < len; i++) { + typeparam_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { + goto failed; + } + res = obj2ast_typeparam(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"typeparams\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(typeparams, i, val); + } + Py_CLEAR(tmp); + } if (_PyObject_LookupAttr(obj, state->bases, &tmp) < 0) { return 1; } @@ -6266,9 +6670,9 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - *out = _PyAST_ClassDef(name, bases, keywords, body, decorator_list, - lineno, col_offset, end_lineno, end_col_offset, - arena); + *out = _PyAST_ClassDef(name, typeparams, bases, keywords, body, + decorator_list, lineno, col_offset, end_lineno, + end_col_offset, arena); if (*out == NULL) goto failed; return 0; } @@ -6436,6 +6840,91 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (*out == NULL) goto failed; return 0; } + tp = state->TypeAlias_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + expr_ty name; + asdl_typeparam_seq* typeparams; + expr_ty value; + + if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from TypeAlias"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { + goto failed; + } + res = obj2ast_expr(state, tmp, &name, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from TypeAlias"); + return 1; + } + else { + int res; + Py_ssize_t len; + Py_ssize_t i; + if (!PyList_Check(tmp)) { + PyErr_Format(PyExc_TypeError, "TypeAlias field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + goto failed; + } + len = PyList_GET_SIZE(tmp); + typeparams = _Py_asdl_typeparam_seq_new(len, arena); + if (typeparams == NULL) goto failed; + for (i = 0; i < len; i++) { + typeparam_ty val; + PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); + if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { + goto failed; + } + res = obj2ast_typeparam(state, tmp2, &val, arena); + _Py_LeaveRecursiveCall(); + Py_DECREF(tmp2); + if (res != 0) goto failed; + if (len != PyList_GET_SIZE(tmp)) { + PyErr_SetString(PyExc_RuntimeError, "TypeAlias field \"typeparams\" changed size during iteration"); + goto failed; + } + asdl_seq_SET(typeparams, i, val); + } + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from TypeAlias"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { + goto failed; + } + res = obj2ast_expr(state, tmp, &value, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_TypeAlias(name, typeparams, value, lineno, col_offset, + end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } tp = state->AugAssign_type; isinstance = PyObject_IsInstance(obj, tp); if (isinstance == -1) { @@ -11803,6 +12292,206 @@ obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* return 1; } +int +obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, + PyArena* arena) +{ + int isinstance; + + PyObject *tmp = NULL; + PyObject *tp; + int lineno; + int col_offset; + int end_lineno; + int end_col_offset; + + if (obj == Py_None) { + *out = NULL; + return 0; + } + if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from typeparam"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + goto failed; + } + res = obj2ast_int(state, tmp, &lineno, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from typeparam"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + goto failed; + } + res = obj2ast_int(state, tmp, &col_offset, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + end_lineno = lineno; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + goto failed; + } + res = obj2ast_int(state, tmp, &end_lineno, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + end_col_offset = col_offset; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + goto failed; + } + res = obj2ast_int(state, tmp, &end_col_offset, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + tp = state->TypeVar_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + expr_ty bound; + + if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from TypeVar"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TypeVar' node")) { + goto failed; + } + res = obj2ast_identifier(state, tmp, &name, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + if (_PyObject_LookupAttr(obj, state->bound, &tmp) < 0) { + return 1; + } + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + bound = NULL; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TypeVar' node")) { + goto failed; + } + res = obj2ast_expr(state, tmp, &bound, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_TypeVar(name, bound, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->ParamSpec_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + + if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from ParamSpec"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'ParamSpec' node")) { + goto failed; + } + res = obj2ast_identifier(state, tmp, &name, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_ParamSpec(name, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + tp = state->TypeVarTuple_type; + isinstance = PyObject_IsInstance(obj, tp); + if (isinstance == -1) { + return 1; + } + if (isinstance) { + identifier name; + + if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + return 1; + } + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"name\" missing from TypeVarTuple"); + return 1; + } + else { + int res; + if (_Py_EnterRecursiveCall(" while traversing 'TypeVarTuple' node")) { + goto failed; + } + res = obj2ast_identifier(state, tmp, &name, arena); + _Py_LeaveRecursiveCall(); + if (res != 0) goto failed; + Py_CLEAR(tmp); + } + *out = _PyAST_TypeVarTuple(name, lineno, col_offset, end_lineno, + end_col_offset, arena); + if (*out == NULL) goto failed; + return 0; + } + + PyErr_Format(PyExc_TypeError, "expected some sort of typeparam, but got %R", obj); + failed: + Py_XDECREF(tmp); + return 1; +} + static int astmodule_exec(PyObject *m) @@ -11861,6 +12550,9 @@ astmodule_exec(PyObject *m) if (PyModule_AddObjectRef(m, "Assign", state->Assign_type) < 0) { return -1; } + if (PyModule_AddObjectRef(m, "TypeAlias", state->TypeAlias_type) < 0) { + return -1; + } if (PyModule_AddObjectRef(m, "AugAssign", state->AugAssign_type) < 0) { return -1; } @@ -12188,6 +12880,19 @@ astmodule_exec(PyObject *m) if (PyModule_AddObjectRef(m, "TypeIgnore", state->TypeIgnore_type) < 0) { return -1; } + if (PyModule_AddObjectRef(m, "typeparam", state->typeparam_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "TypeVar", state->TypeVar_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "ParamSpec", state->ParamSpec_type) < 0) { + return -1; + } + if (PyModule_AddObjectRef(m, "TypeVarTuple", state->TypeVarTuple_type) < 0) + { + return -1; + } return 0; } diff --git a/Python/ast.c b/Python/ast.c index f079e64bbdfc..0844f2afa06b 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -17,10 +17,12 @@ struct validator { static int validate_stmts(struct validator *, asdl_stmt_seq *); static int validate_exprs(struct validator *, asdl_expr_seq *, expr_context_ty, int); static int validate_patterns(struct validator *, asdl_pattern_seq *, int); +static int validate_typeparams(struct validator *, asdl_typeparam_seq *); static int _validate_nonempty_seq(asdl_seq *, const char *, const char *); static int validate_stmt(struct validator *, stmt_ty); static int validate_expr(struct validator *, expr_ty, expr_context_ty); static int validate_pattern(struct validator *, pattern_ty, int); +static int validate_typeparam(struct validator *, typeparam_ty); #define VALIDATE_POSITIONS(node) \ if (node->lineno > node->end_lineno) { \ @@ -726,6 +728,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) switch (stmt->kind) { case FunctionDef_kind: ret = validate_body(state, stmt->v.FunctionDef.body, "FunctionDef") && + validate_typeparams(state, stmt->v.FunctionDef.typeparams) && validate_arguments(state, stmt->v.FunctionDef.args) && validate_exprs(state, stmt->v.FunctionDef.decorator_list, Load, 0) && (!stmt->v.FunctionDef.returns || @@ -733,6 +736,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) break; case ClassDef_kind: ret = validate_body(state, stmt->v.ClassDef.body, "ClassDef") && + validate_typeparams(state, stmt->v.ClassDef.typeparams) && validate_exprs(state, stmt->v.ClassDef.bases, Load, 0) && validate_keywords(state, stmt->v.ClassDef.keywords) && validate_exprs(state, stmt->v.ClassDef.decorator_list, Load, 0); @@ -763,6 +767,11 @@ validate_stmt(struct validator *state, stmt_ty stmt) validate_expr(state, stmt->v.AnnAssign.value, Load)) && validate_expr(state, stmt->v.AnnAssign.annotation, Load); break; + case TypeAlias_kind: + ret = validate_expr(state, stmt->v.TypeAlias.name, Store) && + validate_typeparams(state, stmt->v.TypeAlias.typeparams) && + validate_expr(state, stmt->v.TypeAlias.value, Load); + break; case For_kind: ret = validate_expr(state, stmt->v.For.target, Store) && validate_expr(state, stmt->v.For.iter, Load) && @@ -910,6 +919,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) break; case AsyncFunctionDef_kind: ret = validate_body(state, stmt->v.AsyncFunctionDef.body, "AsyncFunctionDef") && + validate_typeparams(state, stmt->v.AsyncFunctionDef.typeparams) && validate_arguments(state, stmt->v.AsyncFunctionDef.args) && validate_exprs(state, stmt->v.AsyncFunctionDef.decorator_list, Load, 0) && (!stmt->v.AsyncFunctionDef.returns || @@ -982,6 +992,41 @@ validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ return 1; } +static int +validate_typeparam(struct validator *state, typeparam_ty tp) +{ + VALIDATE_POSITIONS(tp); + int ret = -1; + switch (tp->kind) { + case TypeVar_kind: + ret = validate_name(tp->v.TypeVar.name) && + (!tp->v.TypeVar.bound || + validate_expr(state, tp->v.TypeVar.bound, Load)); + break; + case ParamSpec_kind: + ret = validate_name(tp->v.ParamSpec.name); + break; + case TypeVarTuple_kind: + ret = validate_name(tp->v.TypeVarTuple.name); + break; + } + return ret; +} + +static int +validate_typeparams(struct validator *state, asdl_typeparam_seq *tps) +{ + Py_ssize_t i; + for (i = 0; i < asdl_seq_LEN(tps); i++) { + typeparam_ty tp = asdl_seq_GET(tps, i); + if (tp) { + if (!validate_typeparam(state, tp)) + return 0; + } + } + return 1; +} + /* See comments in symtable.c. */ #define COMPILER_STACK_FRAME_SCALE 3 diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 3883ec9e21c7..c5b3e0754673 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -642,6 +642,7 @@ static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeStat static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); +static int astfold_typeparam(typeparam_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); #define CALL(FUNC, TYPE, ARG) \ if (!FUNC((ARG), ctx_, state)) \ @@ -880,6 +881,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } switch (node_->kind) { case FunctionDef_kind: + CALL_SEQ(astfold_typeparam, typeparam, node_->v.FunctionDef.typeparams); CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args); CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body); CALL_SEQ(astfold_expr, expr, node_->v.FunctionDef.decorator_list); @@ -888,6 +890,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } break; case AsyncFunctionDef_kind: + CALL_SEQ(astfold_typeparam, typeparam, node_->v.AsyncFunctionDef.typeparams); CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args); CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body); CALL_SEQ(astfold_expr, expr, node_->v.AsyncFunctionDef.decorator_list); @@ -896,6 +899,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } break; case ClassDef_kind: + CALL_SEQ(astfold_typeparam, typeparam, node_->v.ClassDef.typeparams); CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.bases); CALL_SEQ(astfold_keyword, keyword, node_->v.ClassDef.keywords); CALL(astfold_body, asdl_seq, node_->v.ClassDef.body); @@ -922,6 +926,11 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } CALL_OPT(astfold_expr, expr_ty, node_->v.AnnAssign.value); break; + case TypeAlias_kind: + CALL(astfold_expr, expr_ty, node_->v.TypeAlias.name); + CALL_SEQ(astfold_typeparam, typeparam, node_->v.TypeAlias.typeparams); + CALL(astfold_expr, expr_ty, node_->v.TypeAlias.value); + break; case For_kind: CALL(astfold_expr, expr_ty, node_->v.For.target); CALL(astfold_expr, expr_ty, node_->v.For.iter); @@ -1074,6 +1083,21 @@ astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *stat return 1; } +static int +astfold_typeparam(typeparam_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) +{ + switch (node_->kind) { + case TypeVar_kind: + CALL_OPT(astfold_expr, expr_ty, node_->v.TypeVar.bound); + break; + case ParamSpec_kind: + break; + case TypeVarTuple_kind: + break; + } + return 1; +} + #undef CALL #undef CALL_OPT #undef CALL_SEQ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index d84a078f1100..1b8820f94dbc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -56,7 +56,7 @@ static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2; static PyObject *list, *tuple, *dict, *owner, *set, *str, *tup, *map, *keys; static PyObject *exit_func, *lasti, *val, *retval, *obj, *iter; -static PyObject *aiter, *awaitable, *iterable, *w, *exc_value, *bc; +static PyObject *aiter, *awaitable, *iterable, *w, *exc_value, *bc, *locals; static PyObject *orig, *excs, *update, *b, *fromlist, *level, *from; static PyObject **pieces, **values; static size_t jump; @@ -125,6 +125,7 @@ dummy_func( PyObject *subject; PyObject *top; PyObject *type; + PyObject *typevars; int values_or_none; switch (opcode) { @@ -1002,6 +1003,7 @@ dummy_func( } } + inst(STORE_NAME, (v -- )) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); @@ -1158,31 +1160,41 @@ dummy_func( } } - inst(LOAD_NAME, ( -- v)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); - PyObject *locals = LOCALS(); + op(_LOAD_LOCALS, ( -- locals)) { + locals = LOCALS(); if (locals == NULL) { - _PyErr_Format(tstate, PyExc_SystemError, - "no locals when loading %R", name); - goto error; + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + ERROR_IF(true, error); } - if (PyDict_CheckExact(locals)) { - v = PyDict_GetItemWithError(locals, name); + Py_INCREF(locals); + } + + macro(LOAD_LOCALS) = _LOAD_LOCALS; + + op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { + PyObject *name = GETITEM(frame->f_code->co_names, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { Py_INCREF(v); } else if (_PyErr_Occurred(tstate)) { + Py_DECREF(mod_or_class_dict); goto error; } } else { - v = PyObject_GetItem(locals, name); + v = PyObject_GetItem(mod_or_class_dict, name); if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(mod_or_class_dict); goto error; + } _PyErr_Clear(tstate); } } + Py_DECREF(mod_or_class_dict); if (v == NULL) { v = PyDict_GetItemWithError(GLOBALS(), name); if (v != NULL) { @@ -1219,6 +1231,10 @@ dummy_func( } } + macro(LOAD_NAME) = _LOAD_LOCALS + _LOAD_FROM_DICT_OR_GLOBALS; + + macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS; + family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { LOAD_GLOBAL, LOAD_GLOBAL_MODULE, @@ -1339,29 +1355,32 @@ dummy_func( Py_DECREF(oldobj); } - inst(LOAD_CLASSDEREF, ( -- value)) { - PyObject *name, *locals = LOCALS(); - assert(locals); + inst(LOAD_FROM_DICT_OR_DEREF, (class_dict -- value)) { + PyObject *name; + assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); - if (PyDict_CheckExact(locals)) { - value = PyDict_GetItemWithError(locals, name); + if (PyDict_CheckExact(class_dict)) { + value = PyDict_GetItemWithError(class_dict, name); if (value != NULL) { Py_INCREF(value); } else if (_PyErr_Occurred(tstate)) { + Py_DECREF(class_dict); goto error; } } else { - value = PyObject_GetItem(locals, name); + value = PyObject_GetItem(class_dict, name); if (value == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(class_dict); goto error; } _PyErr_Clear(tstate); } } + Py_DECREF(class_dict); if (!value) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); diff --git a/Python/compile.c b/Python/compile.c index bf5e4a52482a..7adbf9208989 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -147,6 +147,7 @@ enum { COMPILER_SCOPE_ASYNC_FUNCTION, COMPILER_SCOPE_LAMBDA, COMPILER_SCOPE_COMPREHENSION, + COMPILER_SCOPE_TYPEPARAMS, }; @@ -231,6 +232,7 @@ instr_sequence_next_inst(instr_sequence *seq) { &seq->s_allocated, INITIAL_INSTR_SEQUENCE_SIZE, sizeof(instruction))); + assert(seq->s_allocated >= 0); assert(seq->s_used < seq->s_allocated); return seq->s_used++; } @@ -714,6 +716,19 @@ compiler_set_qualname(struct compiler *c) capsule = PyList_GET_ITEM(c->c_stack, stack_size - 1); parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME); assert(parent); + if (parent->u_scope_type == COMPILER_SCOPE_TYPEPARAMS) { + /* The parent is a type parameter scope, so we need to + look at the grandparent. */ + if (stack_size == 2) { + // If we're immediately within the module, we can skip + // the rest and just set the qualname to be the same as name. + u->u_metadata.u_qualname = Py_NewRef(u->u_metadata.u_name); + return SUCCESS; + } + capsule = PyList_GET_ITEM(c->c_stack, stack_size - 2); + parent = (struct compiler_unit *)PyCapsule_GetPointer(capsule, CAPSULE_NAME); + assert(parent); + } if (u->u_scope_type == COMPILER_SCOPE_FUNCTION || u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION @@ -1114,16 +1129,18 @@ codegen_addop_j(instr_sequence *seq, location loc, return instr_sequence_addop(seq, opcode, target.id, loc); } -#define ADDOP(C, LOC, OP) \ - RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) - -#define ADDOP_IN_SCOPE(C, LOC, OP) { \ - if (codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)) < 0) { \ - compiler_exit_scope(C); \ +#define RETURN_IF_ERROR_IN_SCOPE(C, CALL) { \ + if ((CALL) < 0) { \ + compiler_exit_scope((C)); \ return ERROR; \ } \ } +#define ADDOP(C, LOC, OP) \ + RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) + +#define ADDOP_IN_SCOPE(C, LOC, OP) RETURN_IF_ERROR_IN_SCOPE((C), codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) + #define ADDOP_LOAD_CONST(C, LOC, O) \ RETURN_IF_ERROR(compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), (O))) @@ -1183,12 +1200,8 @@ codegen_addop_j(instr_sequence *seq, location loc, #define VISIT(C, TYPE, V) \ RETURN_IF_ERROR(compiler_visit_ ## TYPE((C), (V))); -#define VISIT_IN_SCOPE(C, TYPE, V) {\ - if (compiler_visit_ ## TYPE((C), (V)) < 0) { \ - compiler_exit_scope(C); \ - return ERROR; \ - } \ -} +#define VISIT_IN_SCOPE(C, TYPE, V) \ + RETURN_IF_ERROR_IN_SCOPE((C), compiler_visit_ ## TYPE((C), (V))) #define VISIT_SEQ(C, TYPE, SEQ) { \ int _i; \ @@ -1252,6 +1265,16 @@ compiler_enter_scope(struct compiler *c, identifier name, return ERROR; } } + if (u->u_ste->ste_needs_classdict) { + /* Cook up an implicit __classdict__ cell. */ + Py_ssize_t res; + assert(u->u_scope_type == COMPILER_SCOPE_CLASS); + res = dict_add_o(u->u_metadata.u_cellvars, &_Py_ID(__classdict__)); + if (res < 0) { + compiler_unit_free(u); + return ERROR; + } + } u->u_metadata.u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, PyDict_GET_SIZE(u->u_metadata.u_cellvars)); @@ -1718,8 +1741,10 @@ get_ref_type(struct compiler *c, PyObject *name) { int scope; if (c->u->u_scope_type == COMPILER_SCOPE_CLASS && - _PyUnicode_EqualToASCIIString(name, "__class__")) + (_PyUnicode_EqualToASCIIString(name, "__class__") || + _PyUnicode_EqualToASCIIString(name, "__classdict__"))) { return CELL; + } scope = _PyST_GetScope(c->u->u_ste, name); if (scope == 0) { PyErr_Format(PyExc_SystemError, @@ -2085,26 +2110,81 @@ wrap_in_stopiteration_handler(struct compiler *c) } static int -compiler_function(struct compiler *c, stmt_ty s, int is_async) +compiler_type_params(struct compiler *c, asdl_typeparam_seq *typeparams) +{ + if (!typeparams) { + return SUCCESS; + } + Py_ssize_t n = asdl_seq_LEN(typeparams); + + for (Py_ssize_t i = 0; i < n; i++) { + typeparam_ty typeparam = asdl_seq_GET(typeparams, i); + location loc = LOC(typeparam); + switch(typeparam->kind) { + case TypeVar_kind: + ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVar.name); + if (typeparam->v.TypeVar.bound) { + expr_ty bound = typeparam->v.TypeVar.bound; + if (compiler_enter_scope(c, typeparam->v.TypeVar.name, COMPILER_SCOPE_TYPEPARAMS, + (void *)typeparam, bound->lineno) == -1) { + return ERROR; + } + VISIT_IN_SCOPE(c, expr, bound); + ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); + PyCodeObject *co = optimize_and_assemble(c, 1); + compiler_exit_scope(c); + if (co == NULL) { + return ERROR; + } + if (compiler_make_closure(c, loc, co, 0) < 0) { + Py_DECREF(co); + return ERROR; + } + Py_DECREF(co); + + int intrinsic = bound->kind == Tuple_kind + ? INTRINSIC_TYPEVAR_WITH_CONSTRAINTS + : INTRINSIC_TYPEVAR_WITH_BOUND; + ADDOP_I(c, loc, CALL_INTRINSIC_2, intrinsic); + } + else { + ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVAR); + } + ADDOP_I(c, loc, COPY, 1); + RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVar.name, Store)); + break; + case TypeVarTuple_kind: + ADDOP_LOAD_CONST(c, loc, typeparam->v.TypeVarTuple.name); + ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEVARTUPLE); + ADDOP_I(c, loc, COPY, 1); + RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.TypeVarTuple.name, Store)); + break; + case ParamSpec_kind: + ADDOP_LOAD_CONST(c, loc, typeparam->v.ParamSpec.name); + ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_PARAMSPEC); + ADDOP_I(c, loc, COPY, 1); + RETURN_IF_ERROR(compiler_nameop(c, loc, typeparam->v.ParamSpec.name, Store)); + break; + } + } + ADDOP_I(c, LOC(asdl_seq_GET(typeparams, 0)), BUILD_TUPLE, n); + return SUCCESS; +} + +static int +compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t funcflags, + int firstlineno) { - PyCodeObject *co; PyObject *docstring = NULL; arguments_ty args; - expr_ty returns; identifier name; - asdl_expr_seq* decos; asdl_stmt_seq *body; - Py_ssize_t i, funcflags; - int annotations; int scope_type; - int firstlineno; if (is_async) { assert(s->kind == AsyncFunctionDef_kind); args = s->v.AsyncFunctionDef.args; - returns = s->v.AsyncFunctionDef.returns; - decos = s->v.AsyncFunctionDef.decorator_list; name = s->v.AsyncFunctionDef.name; body = s->v.AsyncFunctionDef.body; @@ -2113,33 +2193,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) assert(s->kind == FunctionDef_kind); args = s->v.FunctionDef.args; - returns = s->v.FunctionDef.returns; - decos = s->v.FunctionDef.decorator_list; name = s->v.FunctionDef.name; body = s->v.FunctionDef.body; scope_type = COMPILER_SCOPE_FUNCTION; } - RETURN_IF_ERROR(compiler_check_debug_args(c, args)); - RETURN_IF_ERROR(compiler_decorators(c, decos)); - - firstlineno = s->lineno; - if (asdl_seq_LEN(decos)) { - firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno; - } - - location loc = LOC(s); - funcflags = compiler_default_arguments(c, loc, args); - if (funcflags == -1) { - return ERROR; - } - annotations = compiler_visit_annotations(c, loc, args, returns); - RETURN_IF_ERROR(annotations); - if (annotations > 0) { - funcflags |= 0x04; - } - RETURN_IF_ERROR( compiler_enter_scope(c, name, scope_type, (void *)s, firstlineno)); @@ -2155,7 +2214,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) 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++) { + for (Py_ssize_t i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) { VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i)); } if (c->u->u_ste->ste_coroutine || c->u->u_ste->ste_generator) { @@ -2164,29 +2223,52 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) return ERROR; } } - co = optimize_and_assemble(c, 1); + PyCodeObject *co = optimize_and_assemble(c, 1); compiler_exit_scope(c); if (co == NULL) { Py_XDECREF(co); return ERROR; } + location loc = LOC(s); if (compiler_make_closure(c, loc, co, funcflags) < 0) { Py_DECREF(co); return ERROR; } Py_DECREF(co); - - RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); - return compiler_nameop(c, loc, name, Store); + return SUCCESS; } static int -compiler_class(struct compiler *c, stmt_ty s) +compiler_function(struct compiler *c, stmt_ty s, int is_async) { - PyCodeObject *co; - int i, firstlineno; - asdl_expr_seq *decos = s->v.ClassDef.decorator_list; + arguments_ty args; + expr_ty returns; + identifier name; + asdl_expr_seq *decos; + asdl_typeparam_seq *typeparams; + Py_ssize_t funcflags; + int annotations; + int firstlineno; + + if (is_async) { + assert(s->kind == AsyncFunctionDef_kind); + args = s->v.AsyncFunctionDef.args; + returns = s->v.AsyncFunctionDef.returns; + decos = s->v.AsyncFunctionDef.decorator_list; + name = s->v.AsyncFunctionDef.name; + typeparams = s->v.AsyncFunctionDef.typeparams; + } else { + assert(s->kind == FunctionDef_kind); + + args = s->v.FunctionDef.args; + returns = s->v.FunctionDef.returns; + decos = s->v.FunctionDef.decorator_list; + name = s->v.FunctionDef.name; + typeparams = s->v.FunctionDef.typeparams; + } + + RETURN_IF_ERROR(compiler_check_debug_args(c, args)); RETURN_IF_ERROR(compiler_decorators(c, decos)); firstlineno = s->lineno; @@ -2194,6 +2276,108 @@ compiler_class(struct compiler *c, stmt_ty s) firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno; } + location loc = LOC(s); + + int is_generic = asdl_seq_LEN(typeparams) > 0; + + if (is_generic) { + // Used by the CALL to the type parameters function. + ADDOP(c, loc, PUSH_NULL); + } + + funcflags = compiler_default_arguments(c, loc, args); + if (funcflags == -1) { + return ERROR; + } + + int num_typeparam_args = 0; + + if (is_generic) { + if (funcflags & 0x01) { + num_typeparam_args += 1; + } + if (funcflags & 0x02) { + num_typeparam_args += 1; + } + if (num_typeparam_args == 2) { + ADDOP_I(c, loc, SWAP, 2); + } + PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", name); + if (!typeparams_name) { + return ERROR; + } + if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS, + (void *)typeparams, firstlineno) == -1) { + Py_DECREF(typeparams_name); + return ERROR; + } + Py_DECREF(typeparams_name); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams)); + if ((funcflags & 0x01) || (funcflags & 0x02)) { + RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 0, loc)); + } + if ((funcflags & 0x01) && (funcflags & 0x02)) { + RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 1, loc)); + } + } + + annotations = compiler_visit_annotations(c, loc, args, returns); + if (annotations < 0) { + if (is_generic) { + compiler_exit_scope(c); + } + return ERROR; + } + if (annotations > 0) { + funcflags |= 0x04; + } + + if (compiler_function_body(c, s, is_async, funcflags, firstlineno) < 0) { + if (is_generic) { + compiler_exit_scope(c); + } + return ERROR; + } + + if (is_generic) { + RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i( + INSTR_SEQUENCE(c), SWAP, 2, loc)); + RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i( + INSTR_SEQUENCE(c), CALL_INTRINSIC_2, INTRINSIC_SET_FUNCTION_TYPE_PARAMS, loc)); + + c->u->u_metadata.u_argcount = num_typeparam_args; + PyCodeObject *co = optimize_and_assemble(c, 0); + compiler_exit_scope(c); + if (co == NULL) { + return ERROR; + } + if (compiler_make_closure(c, loc, co, 0) < 0) { + Py_DECREF(co); + return ERROR; + } + Py_DECREF(co); + if (num_typeparam_args > 0) { + ADDOP_I(c, loc, SWAP, num_typeparam_args + 1); + } + ADDOP_I(c, loc, CALL, num_typeparam_args); + } + + RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); + return compiler_nameop(c, loc, name, Store); +} + +static int +compiler_set_type_params_in_class(struct compiler *c, location loc) +{ + _Py_DECLARE_STR(type_params, ".type_params"); + RETURN_IF_ERROR(compiler_nameop(c, loc, &_Py_STR(type_params), Load)); + RETURN_IF_ERROR(compiler_nameop(c, loc, &_Py_ID(__type_params__), Store)); + return 1; +} + +static int +compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) +{ /* ultimately generate code for: <name> = __build_class__(<func>, <name>, *<bases>, **<keywords>) where: @@ -2204,68 +2388,100 @@ compiler_class(struct compiler *c, stmt_ty s) <keywords> is the keyword arguments and **kwds argument This borrows from compiler_call. */ + /* 1. compile the class body into a code object */ RETURN_IF_ERROR( compiler_enter_scope(c, s->v.ClassDef.name, COMPILER_SCOPE_CLASS, (void *)s, firstlineno)); - /* this block represents what we do in the new scope */ - { - location loc = LOCATION(firstlineno, firstlineno, 0, 0); - /* use the class name for name mangling */ - Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); - /* load (global) __name__ ... */ - if (compiler_nameop(c, loc, &_Py_ID(__name__), Load) < 0) { + location loc = LOCATION(firstlineno, firstlineno, 0, 0); + /* use the class name for name mangling */ + Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); + /* load (global) __name__ ... */ + if (compiler_nameop(c, loc, &_Py_ID(__name__), Load) < 0) { + compiler_exit_scope(c); + return ERROR; + } + /* ... and store it as __module__ */ + if (compiler_nameop(c, loc, &_Py_ID(__module__), Store) < 0) { + compiler_exit_scope(c); + return ERROR; + } + 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; + } + asdl_typeparam_seq *typeparams = s->v.ClassDef.typeparams; + if (asdl_seq_LEN(typeparams) > 0) { + if (!compiler_set_type_params_in_class(c, loc)) { compiler_exit_scope(c); return ERROR; } - /* ... and store it as __module__ */ - if (compiler_nameop(c, loc, &_Py_ID(__module__), Store) < 0) { + } + if (c->u->u_ste->ste_needs_classdict) { + ADDOP(c, loc, LOAD_LOCALS); + + // We can't use compiler_nameop here because we need to generate a + // STORE_DEREF in a class namespace, and compiler_nameop() won't do + // that by default. + PyObject *cellvars = c->u->u_metadata.u_cellvars; + if (compiler_addop_o(c->u, loc, STORE_DEREF, cellvars, + &_Py_ID(__classdict__)) < 0) { compiler_exit_scope(c); return ERROR; } - 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) { + } + /* compile the body proper */ + if (compiler_body(c, loc, s->v.ClassDef.body) < 0) { + compiler_exit_scope(c); + return ERROR; + } + /* The following code is artificial */ + /* Set __classdictcell__ if necessary */ + if (c->u->u_ste->ste_needs_classdict) { + /* Store __classdictcell__ into class namespace */ + int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__classdict__)); + if (i < 0) { compiler_exit_scope(c); return ERROR; } - /* compile the body proper */ - if (compiler_body(c, loc, s->v.ClassDef.body) < 0) { + ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); + if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classdictcell__), Store) < 0) { compiler_exit_scope(c); return ERROR; } - /* The following code is artificial */ - /* 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_metadata.u_cellvars, &_Py_ID(__class__)); - if (i < 0) { - compiler_exit_scope(c); - return ERROR; - } - ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); - ADDOP_I(c, NO_LOCATION, COPY, 1); - if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) { - compiler_exit_scope(c); - return ERROR; - } + } + /* 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 */ + int i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__)); + if (i < 0) { + compiler_exit_scope(c); + return ERROR; } - else { - /* No methods referenced __class__, so just return None */ - ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i); + ADDOP_I(c, NO_LOCATION, COPY, 1); + if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) { + compiler_exit_scope(c); + return ERROR; } - ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); - /* create the code object */ - co = optimize_and_assemble(c, 1); } + else { + /* No methods referenced __class__, so just return None */ + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); + } + ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); + /* create the code object */ + PyCodeObject *co = optimize_and_assemble(c, 1); + /* leave the new scope */ compiler_exit_scope(c); if (co == NULL) { return ERROR; } - location loc = LOC(s); /* 2. load the 'build_class' function */ ADDOP(c, loc, PUSH_NULL); ADDOP(c, loc, LOAD_BUILD_CLASS); @@ -2280,10 +2496,100 @@ compiler_class(struct compiler *c, stmt_ty s) /* 4. load class name */ ADDOP_LOAD_CONST(c, loc, s->v.ClassDef.name); - /* 5. generate the rest of the code for the call */ - RETURN_IF_ERROR(compiler_call_helper(c, loc, 2, - s->v.ClassDef.bases, - s->v.ClassDef.keywords)); + return SUCCESS; +} + +static int +compiler_class(struct compiler *c, stmt_ty s) +{ + asdl_expr_seq *decos = s->v.ClassDef.decorator_list; + + RETURN_IF_ERROR(compiler_decorators(c, decos)); + + int firstlineno = s->lineno; + if (asdl_seq_LEN(decos)) { + firstlineno = ((expr_ty)asdl_seq_GET(decos, 0))->lineno; + } + location loc = LOC(s); + + asdl_typeparam_seq *typeparams = s->v.ClassDef.typeparams; + int is_generic = asdl_seq_LEN(typeparams) > 0; + if (is_generic) { + Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); + ADDOP(c, loc, PUSH_NULL); + PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", + s->v.ClassDef.name); + if (!typeparams_name) { + return ERROR; + } + if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS, + (void *)typeparams, firstlineno) == -1) { + Py_DECREF(typeparams_name); + return ERROR; + } + Py_DECREF(typeparams_name); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams)); + _Py_DECLARE_STR(type_params, ".type_params"); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Store)); + } + + if (compiler_class_body(c, s, firstlineno) < 0) { + if (is_generic) { + compiler_exit_scope(c); + } + return ERROR; + } + + /* generate the rest of the code for the call */ + + if (is_generic) { + _Py_DECLARE_STR(type_params, ".type_params"); + _Py_DECLARE_STR(generic_base, ".generic_base"); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Load)); + RETURN_IF_ERROR_IN_SCOPE( + c, codegen_addop_i(INSTR_SEQUENCE(c), CALL_INTRINSIC_1, INTRINSIC_SUBSCRIPT_GENERIC, loc) + ) + RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(generic_base), Store)); + + Py_ssize_t original_len = asdl_seq_LEN(s->v.ClassDef.bases); + asdl_expr_seq *bases = _Py_asdl_expr_seq_new( + original_len + 1, c->c_arena); + if (bases == NULL) { + compiler_exit_scope(c); + return ERROR; + } + for (Py_ssize_t i = 0; i < original_len; i++) { + asdl_seq_SET(bases, i, asdl_seq_GET(s->v.ClassDef.bases, i)); + } + expr_ty name_node = _PyAST_Name( + &_Py_STR(generic_base), Load, + loc.lineno, loc.col_offset, loc.end_lineno, loc.end_col_offset, c->c_arena + ); + if (name_node == NULL) { + compiler_exit_scope(c); + return ERROR; + } + asdl_seq_SET(bases, original_len, name_node); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_call_helper(c, loc, 2, + bases, + s->v.ClassDef.keywords)); + + PyCodeObject *co = optimize_and_assemble(c, 0); + compiler_exit_scope(c); + if (co == NULL) { + return ERROR; + } + if (compiler_make_closure(c, loc, co, 0) < 0) { + Py_DECREF(co); + return ERROR; + } + Py_DECREF(co); + ADDOP_I(c, loc, CALL, 0); + } else { + RETURN_IF_ERROR(compiler_call_helper(c, loc, 2, + s->v.ClassDef.bases, + s->v.ClassDef.keywords)); + } /* 6. apply decorators */ RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); @@ -2293,6 +2599,87 @@ compiler_class(struct compiler *c, stmt_ty s) return SUCCESS; } +static int +compiler_typealias_body(struct compiler *c, stmt_ty s) +{ + location loc = LOC(s); + PyObject *name = s->v.TypeAlias.name->v.Name.id; + RETURN_IF_ERROR( + compiler_enter_scope(c, name, COMPILER_SCOPE_FUNCTION, s, loc.lineno)); + /* Make None the first constant, so the evaluate function can't have a + docstring. */ + RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None)); + VISIT_IN_SCOPE(c, expr, s->v.TypeAlias.value); + ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); + PyCodeObject *co = optimize_and_assemble(c, 0); + compiler_exit_scope(c); + if (co == NULL) { + return ERROR; + } + if (compiler_make_closure(c, loc, co, 0) < 0) { + Py_DECREF(co); + return ERROR; + } + Py_DECREF(co); + ADDOP_I(c, loc, BUILD_TUPLE, 3); + ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_TYPEALIAS); + return SUCCESS; +} + +static int +compiler_typealias(struct compiler *c, stmt_ty s) +{ + location loc = LOC(s); + asdl_typeparam_seq *typeparams = s->v.TypeAlias.typeparams; + int is_generic = asdl_seq_LEN(typeparams) > 0; + PyObject *name = s->v.TypeAlias.name->v.Name.id; + if (is_generic) { + ADDOP(c, loc, PUSH_NULL); + PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", + name); + if (!typeparams_name) { + return ERROR; + } + if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS, + (void *)typeparams, loc.lineno) == -1) { + Py_DECREF(typeparams_name); + return ERROR; + } + Py_DECREF(typeparams_name); + RETURN_IF_ERROR_IN_SCOPE( + c, compiler_addop_load_const(c->c_const_cache, c->u, loc, name) + ); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams)); + } + else { + ADDOP_LOAD_CONST(c, loc, name); + ADDOP_LOAD_CONST(c, loc, Py_None); + } + + if (compiler_typealias_body(c, s) < 0) { + if (is_generic) { + compiler_exit_scope(c); + } + return ERROR; + } + + if (is_generic) { + PyCodeObject *co = optimize_and_assemble(c, 0); + compiler_exit_scope(c); + if (co == NULL) { + return ERROR; + } + if (compiler_make_closure(c, loc, co, 0) < 0) { + Py_DECREF(co); + return ERROR; + } + Py_DECREF(co); + ADDOP_I(c, loc, CALL, 0); + } + RETURN_IF_ERROR(compiler_nameop(c, loc, name, Store)); + return SUCCESS; +} + /* Return false if the expression is a constant value except named singletons. Return true otherwise. */ static bool @@ -2705,7 +3092,7 @@ compiler_return(struct compiler *c, stmt_ty s) location loc = LOC(s); int preserve_tos = ((s->v.Return.value != NULL) && (s->v.Return.value->kind != Constant_kind)); - if (c->u->u_ste->ste_type != FunctionBlock) { + if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'return' outside function"); } if (s->v.Return.value != NULL && @@ -3519,6 +3906,8 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) return compiler_function(c, s, 0); case ClassDef_kind: return compiler_class(c, s); + case TypeAlias_kind: + return compiler_typealias(c, s); case Return_kind: return compiler_return(c, s); case Delete_kind: @@ -3725,12 +4114,12 @@ compiler_nameop(struct compiler *c, location loc, optype = OP_DEREF; break; case LOCAL: - if (c->u->u_ste->ste_type == FunctionBlock || + if (_PyST_IsFunctionLike(c->u->u_ste) || (PyDict_GetItem(c->u->u_metadata.u_fasthidden, mangled) == Py_True)) optype = OP_FAST; break; case GLOBAL_IMPLICIT: - if (c->u->u_ste->ste_type == FunctionBlock) + if (_PyST_IsFunctionLike(c->u->u_ste)) optype = OP_GLOBAL; break; case GLOBAL_EXPLICIT: @@ -3748,7 +4137,24 @@ compiler_nameop(struct compiler *c, location loc, case OP_DEREF: switch (ctx) { case Load: - op = (c->u->u_ste->ste_type == ClassBlock) ? LOAD_CLASSDEREF : LOAD_DEREF; + if (c->u->u_ste->ste_type == ClassBlock) { + op = LOAD_FROM_DICT_OR_DEREF; + // First load the locals + if (codegen_addop_noarg(INSTR_SEQUENCE(c), LOAD_LOCALS, loc) < 0) { + return ERROR; + } + } + else if (c->u->u_ste->ste_can_see_class_scope) { + op = LOAD_FROM_DICT_OR_DEREF; + // First load the classdict + if (compiler_addop_o(c->u, loc, LOAD_DEREF, + c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) { + return ERROR; + } + } + else { + op = LOAD_DEREF; + } break; case Store: op = STORE_DEREF; break; case Del: op = DELETE_DEREF; break; @@ -3764,7 +4170,18 @@ compiler_nameop(struct compiler *c, location loc, return SUCCESS; case OP_GLOBAL: switch (ctx) { - case Load: op = LOAD_GLOBAL; break; + case Load: + if (c->u->u_ste->ste_can_see_class_scope && scope == GLOBAL_IMPLICIT) { + op = LOAD_FROM_DICT_OR_GLOBALS; + // First load the classdict + if (compiler_addop_o(c->u, loc, LOAD_DEREF, + c->u->u_metadata.u_freevars, &_Py_ID(__classdict__)) < 0) { + return ERROR; + } + } else { + op = LOAD_GLOBAL; + } + break; case Store: op = STORE_GLOBAL; break; case Del: op = DELETE_GLOBAL; break; } @@ -5008,7 +5425,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc, // assignment expression to a nonlocal in the comprehension, these don't // need handling here since they shouldn't be isolated if (symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) { - if (c->u->u_ste->ste_type != FunctionBlock) { + if (!_PyST_IsFunctionLike(c->u->u_ste)) { // non-function scope: override this name to use fast locals PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k); if (orig != Py_True) { @@ -5604,7 +6021,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) case DictComp_kind: return compiler_dictcomp(c, e); case Yield_kind: - if (c->u->u_ste->ste_type != FunctionBlock) { + if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'yield' outside function"); } if (e->v.Yield.value) { @@ -5616,7 +6033,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) ADDOP_YIELD(c, loc); break; case YieldFrom_kind: - if (c->u->u_ste->ste_type != FunctionBlock) { + if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'yield' outside function"); } if (c->u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION) { @@ -5629,7 +6046,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) break; case Await_kind: if (!IS_TOP_LEVEL_AWAIT(c)){ - if (c->u->u_ste->ste_type != FunctionBlock){ + if (!_PyST_IsFunctionLike(c->u->u_ste)) { return compiler_error(c, loc, "'await' outside function"); } @@ -6916,7 +7333,7 @@ compute_code_flags(struct compiler *c) { PySTEntryObject *ste = c->u->u_ste; int flags = 0; - if (ste->ste_type == FunctionBlock) { + if (_PyST_IsFunctionLike(c->u->u_ste)) { flags |= CO_NEWLOCALS | CO_OPTIMIZED; if (ste->ste_nested) flags |= CO_NESTED; @@ -7114,7 +7531,7 @@ fix_cell_offsets(_PyCompile_CodeUnitMetadata *umd, basicblock *entryblock, int * case LOAD_DEREF: case STORE_DEREF: case DELETE_DEREF: - case LOAD_CLASSDEREF: + case LOAD_FROM_DICT_OR_DEREF: assert(oldoffset >= 0); assert(oldoffset < noffsets); assert(fixedmap[oldoffset] >= 0); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 014a69ff7e96..fa4ff5ccee78 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 137 "Python/bytecodes.c" + #line 138 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -25,7 +25,7 @@ } TARGET(INSTRUMENTED_RESUME) { - #line 151 "Python/bytecodes.c" + #line 152 "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? @@ -57,7 +57,7 @@ TARGET(LOAD_CLOSURE) { PyObject *value; - #line 179 "Python/bytecodes.c" + #line 180 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; @@ -70,7 +70,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 186 "Python/bytecodes.c" + #line 187 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -82,7 +82,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -94,7 +94,7 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 198 "Python/bytecodes.c" + #line 199 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -107,7 +107,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - #line 204 "Python/bytecodes.c" + #line 205 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 114 "Python/generated_cases.c.h" @@ -118,7 +118,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 209 "Python/bytecodes.c" + #line 210 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 124 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -130,7 +130,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -140,7 +140,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -158,7 +158,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -168,7 +168,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 204 "Python/bytecodes.c" + #line 205 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 175 "Python/generated_cases.c.h" @@ -184,14 +184,14 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; - #line 209 "Python/bytecodes.c" + #line 210 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 190 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -207,14 +207,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 209 "Python/bytecodes.c" + #line 210 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 213 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; - #line 209 "Python/bytecodes.c" + #line 210 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 220 "Python/generated_cases.c.h" } @@ -227,7 +227,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 204 "Python/bytecodes.c" + #line 205 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 234 "Python/generated_cases.c.h" @@ -236,7 +236,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -251,7 +251,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 219 "Python/bytecodes.c" + #line 220 "Python/bytecodes.c" #line 256 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -260,7 +260,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 223 "Python/bytecodes.c" + #line 224 "Python/bytecodes.c" res = NULL; #line 266 "Python/generated_cases.c.h" STACK_GROW(1); @@ -273,13 +273,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 219 "Python/bytecodes.c" + #line 220 "Python/bytecodes.c" #line 278 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 219 "Python/bytecodes.c" + #line 220 "Python/bytecodes.c" #line 284 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -290,7 +290,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 229 "Python/bytecodes.c" + #line 230 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -310,7 +310,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 242 "Python/bytecodes.c" + #line 243 "Python/bytecodes.c" Py_DECREF(receiver); #line 316 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -321,7 +321,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 246 "Python/bytecodes.c" + #line 247 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -339,11 +339,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 257 "Python/bytecodes.c" + #line 258 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 345 "Python/generated_cases.c.h" Py_DECREF(value); - #line 259 "Python/bytecodes.c" + #line 260 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 349 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -353,11 +353,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 263 "Python/bytecodes.c" + #line 264 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 359 "Python/generated_cases.c.h" Py_DECREF(value); - #line 265 "Python/bytecodes.c" + #line 266 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -374,11 +374,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 276 "Python/bytecodes.c" + #line 277 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 380 "Python/generated_cases.c.h" Py_DECREF(value); - #line 278 "Python/bytecodes.c" + #line 279 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 384 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -389,7 +389,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 295 "Python/bytecodes.c" + #line 296 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -408,7 +408,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 305 "Python/bytecodes.c" + #line 306 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -426,7 +426,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 314 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -445,7 +445,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 324 "Python/bytecodes.c" + #line 325 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -462,7 +462,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 332 "Python/bytecodes.c" + #line 333 "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); @@ -480,7 +480,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 348 "Python/bytecodes.c" + #line 349 "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]; @@ -516,7 +516,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 377 "Python/bytecodes.c" + #line 378 "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); @@ -534,7 +534,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 386 "Python/bytecodes.c" + #line 387 "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); @@ -555,7 +555,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 404 "Python/bytecodes.c" + #line 405 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -570,7 +570,7 @@ #line 571 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 416 "Python/bytecodes.c" + #line 417 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 576 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -584,7 +584,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 420 "Python/bytecodes.c" + #line 421 "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. @@ -608,7 +608,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 435 "Python/bytecodes.c" + #line 436 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -630,7 +630,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 450 "Python/bytecodes.c" + #line 451 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -655,7 +655,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 466 "Python/bytecodes.c" + #line 467 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -680,7 +680,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 482 "Python/bytecodes.c" + #line 483 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -691,7 +691,7 @@ #line 692 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 490 "Python/bytecodes.c" + #line 491 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -707,7 +707,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 497 "Python/bytecodes.c" + #line 498 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -736,7 +736,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 522 "Python/bytecodes.c" + #line 523 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 742 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -747,11 +747,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 527 "Python/bytecodes.c" + #line 528 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 753 "Python/generated_cases.c.h" Py_DECREF(v); - #line 529 "Python/bytecodes.c" + #line 530 "Python/bytecodes.c" if (err) goto pop_1_error; #line 757 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -766,7 +766,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 540 "Python/bytecodes.c" + #line 541 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -785,7 +785,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 555 "Python/bytecodes.c" + #line 556 "Python/bytecodes.c" if (err) goto pop_3_error; #line 791 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -797,7 +797,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 559 "Python/bytecodes.c" + #line 560 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -824,7 +824,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 578 "Python/bytecodes.c" + #line 579 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -839,13 +839,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 586 "Python/bytecodes.c" + #line 587 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 846 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 589 "Python/bytecodes.c" + #line 590 "Python/bytecodes.c" if (err) goto pop_2_error; #line 851 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -855,12 +855,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 593 "Python/bytecodes.c" + #line 594 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 862 "Python/generated_cases.c.h" Py_DECREF(value); - #line 596 "Python/bytecodes.c" + #line 597 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 866 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -871,13 +871,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 600 "Python/bytecodes.c" + #line 601 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 878 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 603 "Python/bytecodes.c" + #line 604 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 883 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -887,7 +887,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 607 "Python/bytecodes.c" + #line 608 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -910,7 +910,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 627 "Python/bytecodes.c" + #line 628 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -926,7 +926,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 640 "Python/bytecodes.c" + #line 641 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -944,7 +944,7 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 655 "Python/bytecodes.c" + #line 656 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -965,7 +965,7 @@ } TARGET(RETURN_CONST) { - #line 674 "Python/bytecodes.c" + #line 675 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -983,7 +983,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 690 "Python/bytecodes.c" + #line 691 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1007,7 +1007,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 710 "Python/bytecodes.c" + #line 711 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1022,14 +1022,14 @@ type->tp_name); #line 1024 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 723 "Python/bytecodes.c" + #line 724 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1031 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 728 "Python/bytecodes.c" + #line 729 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1050,7 +1050,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 743 "Python/bytecodes.c" + #line 744 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1105,7 +1105,7 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 790 "Python/bytecodes.c" + #line 791 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -1114,7 +1114,7 @@ #line 1116 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 797 "Python/bytecodes.c" + #line 798 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1144,7 +1144,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 823 "Python/bytecodes.c" + #line 824 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1200,7 +1200,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 872 "Python/bytecodes.c" + #line 873 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1221,7 +1221,7 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 890 "Python/bytecodes.c" + #line 891 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1243,7 +1243,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 909 "Python/bytecodes.c" + #line 910 "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. @@ -1264,7 +1264,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 927 "Python/bytecodes.c" + #line 928 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1271 "Python/generated_cases.c.h" @@ -1275,7 +1275,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 932 "Python/bytecodes.c" + #line 933 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1299,13 +1299,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 952 "Python/bytecodes.c" + #line 953 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1306 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 955 "Python/bytecodes.c" + #line 956 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1323,7 +1323,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 964 "Python/bytecodes.c" + #line 965 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1332,7 +1332,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 969 "Python/bytecodes.c" + #line 970 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { @@ -1348,7 +1348,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 978 "Python/bytecodes.c" + #line 979 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1354 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1358,7 +1358,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 982 "Python/bytecodes.c" + #line 983 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1388,7 +1388,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1006 "Python/bytecodes.c" + #line 1008 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1397,7 +1397,7 @@ "no locals found when storing %R", name); #line 1399 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1013 "Python/bytecodes.c" + #line 1015 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1406,7 +1406,7 @@ err = PyObject_SetItem(ns, name, v); #line 1408 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1020 "Python/bytecodes.c" + #line 1022 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1412 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1414,7 +1414,7 @@ } TARGET(DELETE_NAME) { - #line 1024 "Python/bytecodes.c" + #line 1026 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1439,7 +1439,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1050 "Python/bytecodes.c" + #line 1052 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1454,7 +1454,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1456 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1063 "Python/bytecodes.c" + #line 1065 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1460 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1466,7 +1466,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1067 "Python/bytecodes.c" + #line 1069 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1484,7 +1484,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1077 "Python/bytecodes.c" + #line 1079 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1503,7 +1503,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1088 "Python/bytecodes.c" + #line 1090 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1521,13 +1521,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1099 "Python/bytecodes.c" + #line 1101 "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 1529 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1103 "Python/bytecodes.c" + #line 1105 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1533 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1540,7 +1540,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1114 "Python/bytecodes.c" + #line 1116 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1559,7 +1559,7 @@ #line 1560 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1130 "Python/bytecodes.c" + #line 1132 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1565 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1569,12 +1569,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1134 "Python/bytecodes.c" + #line 1136 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1576 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1137 "Python/bytecodes.c" + #line 1139 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1580 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1583,12 +1583,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1141 "Python/bytecodes.c" + #line 1143 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1590 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1144 "Python/bytecodes.c" + #line 1146 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1594 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1596,7 +1596,7 @@ } TARGET(DELETE_GLOBAL) { - #line 1148 "Python/bytecodes.c" + #line 1150 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1612,70 +1612,175 @@ DISPATCH(); } + TARGET(LOAD_LOCALS) { + PyObject *_tmp_1; + { + PyObject *locals; + #line 1164 "Python/bytecodes.c" + locals = LOCALS(); + if (locals == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + if (true) goto error; + } + Py_INCREF(locals); + #line 1628 "Python/generated_cases.c.h" + _tmp_1 = locals; + } + STACK_GROW(1); + stack_pointer[-1] = _tmp_1; + DISPATCH(); + } + TARGET(LOAD_NAME) { - PyObject *v; - #line 1162 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); - PyObject *locals = LOCALS(); - if (locals == NULL) { - _PyErr_Format(tstate, PyExc_SystemError, - "no locals when loading %R", name); - goto error; + PyObject *_tmp_1; + { + PyObject *locals; + #line 1164 "Python/bytecodes.c" + locals = LOCALS(); + if (locals == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + if (true) goto error; + } + Py_INCREF(locals); + #line 1648 "Python/generated_cases.c.h" + _tmp_1 = locals; } - if (PyDict_CheckExact(locals)) { - v = PyDict_GetItemWithError(locals, name); - if (v != NULL) { - Py_INCREF(v); + { + PyObject *mod_or_class_dict = _tmp_1; + PyObject *v; + #line 1176 "Python/bytecodes.c" + PyObject *name = GETITEM(frame->f_code->co_names, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + Py_DECREF(mod_or_class_dict); + goto error; + } } - else if (_PyErr_Occurred(tstate)) { - goto error; + else { + v = PyObject_GetItem(mod_or_class_dict, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(mod_or_class_dict); + goto error; + } + _PyErr_Clear(tstate); + } } - } - else { - v = PyObject_GetItem(locals, name); + Py_DECREF(mod_or_class_dict); if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { goto error; - _PyErr_Clear(tstate); + } + else { + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); + } + else { + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + } + } } + #line 1711 "Python/generated_cases.c.h" + _tmp_1 = v; } - if (v == NULL) { - v = PyDict_GetItemWithError(GLOBALS(), name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - goto error; + STACK_GROW(1); + stack_pointer[-1] = _tmp_1; + DISPATCH(); + } + + TARGET(LOAD_FROM_DICT_OR_GLOBALS) { + PyObject *_tmp_1 = stack_pointer[-1]; + { + PyObject *mod_or_class_dict = _tmp_1; + PyObject *v; + #line 1176 "Python/bytecodes.c" + PyObject *name = GETITEM(frame->f_code->co_names, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + Py_DECREF(mod_or_class_dict); + goto error; + } } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } + v = PyObject_GetItem(mod_or_class_dict, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(mod_or_class_dict); goto error; } + _PyErr_Clear(tstate); + } + } + Py_DECREF(mod_or_class_dict); + if (v == NULL) { + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { Py_INCREF(v); } + else if (_PyErr_Occurred(tstate)) { + goto error; + } else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); + } + else { + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; } - goto error; } } } + #line 1781 "Python/generated_cases.c.h" + _tmp_1 = v; } - #line 1677 "Python/generated_cases.c.h" - STACK_GROW(1); - stack_pointer[-1] = v; + stack_pointer[-1] = _tmp_1; DISPATCH(); } @@ -1684,7 +1789,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1229 "Python/bytecodes.c" + #line 1245 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1736,7 +1841,7 @@ } } null = NULL; - #line 1740 "Python/generated_cases.c.h" + #line 1845 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1750,7 +1855,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1283 "Python/bytecodes.c" + #line 1299 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1761,7 +1866,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1765 "Python/generated_cases.c.h" + #line 1870 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1776,7 +1881,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 1296 "Python/bytecodes.c" + #line 1312 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1791,7 +1896,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1795 "Python/generated_cases.c.h" + #line 1900 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1801,16 +1906,16 @@ } TARGET(DELETE_FAST) { - #line 1313 "Python/bytecodes.c" + #line 1329 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1809 "Python/generated_cases.c.h" + #line 1914 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1319 "Python/bytecodes.c" + #line 1335 "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); @@ -1819,12 +1924,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1823 "Python/generated_cases.c.h" + #line 1928 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1330 "Python/bytecodes.c" + #line 1346 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1835,35 +1940,39 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1839 "Python/generated_cases.c.h" + #line 1944 "Python/generated_cases.c.h" DISPATCH(); } - TARGET(LOAD_CLASSDEREF) { + TARGET(LOAD_FROM_DICT_OR_DEREF) { + PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1343 "Python/bytecodes.c" - PyObject *name, *locals = LOCALS(); - assert(locals); + #line 1359 "Python/bytecodes.c" + PyObject *name; + assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); - if (PyDict_CheckExact(locals)) { - value = PyDict_GetItemWithError(locals, name); + if (PyDict_CheckExact(class_dict)) { + value = PyDict_GetItemWithError(class_dict, name); if (value != NULL) { Py_INCREF(value); } else if (_PyErr_Occurred(tstate)) { + Py_DECREF(class_dict); goto error; } } else { - value = PyObject_GetItem(locals, name); + value = PyObject_GetItem(class_dict, name); if (value == NULL) { if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(class_dict); goto error; } _PyErr_Clear(tstate); } } + Py_DECREF(class_dict); if (!value) { PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); @@ -1873,15 +1982,14 @@ } Py_INCREF(value); } - #line 1877 "Python/generated_cases.c.h" - STACK_GROW(1); + #line 1986 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1377 "Python/bytecodes.c" + #line 1396 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1889,7 +1997,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1893 "Python/generated_cases.c.h" + #line 2001 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1897,18 +2005,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1387 "Python/bytecodes.c" + #line 1406 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1906 "Python/generated_cases.c.h" + #line 2014 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1394 "Python/bytecodes.c" + #line 1413 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1919,22 +2027,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1923 "Python/generated_cases.c.h" + #line 2031 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1407 "Python/bytecodes.c" + #line 1426 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1932 "Python/generated_cases.c.h" + #line 2040 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1409 "Python/bytecodes.c" + #line 1428 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1938 "Python/generated_cases.c.h" + #line 2046 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1944,10 +2052,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1413 "Python/bytecodes.c" + #line 1432 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1951 "Python/generated_cases.c.h" + #line 2059 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1957,10 +2065,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1418 "Python/bytecodes.c" + #line 1437 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1964 "Python/generated_cases.c.h" + #line 2072 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1970,7 +2078,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1423 "Python/bytecodes.c" + #line 1442 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1981,13 +2089,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1985 "Python/generated_cases.c.h" + #line 2093 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1434 "Python/bytecodes.c" + #line 1453 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1991 "Python/generated_cases.c.h" + #line 2099 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1996,13 +2104,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1441 "Python/bytecodes.c" + #line 1460 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2002 "Python/generated_cases.c.h" + #line 2110 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1443 "Python/bytecodes.c" + #line 1462 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2006 "Python/generated_cases.c.h" + #line 2114 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2010,7 +2118,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1447 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2025,7 +2133,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2029 "Python/generated_cases.c.h" + #line 2137 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2035,7 +2143,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1464 "Python/bytecodes.c" + #line 1483 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2043,13 +2151,13 @@ if (map == NULL) goto error; - #line 2047 "Python/generated_cases.c.h" + #line 2155 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1472 "Python/bytecodes.c" + #line 1491 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2053 "Python/generated_cases.c.h" + #line 2161 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2057,7 +2165,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1476 "Python/bytecodes.c" + #line 1495 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2097,7 +2205,7 @@ Py_DECREF(ann_dict); } } - #line 2101 "Python/generated_cases.c.h" + #line 2209 "Python/generated_cases.c.h" DISPATCH(); } @@ -2105,7 +2213,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1518 "Python/bytecodes.c" + #line 1537 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2115,14 +2223,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2119 "Python/generated_cases.c.h" + #line 2227 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1528 "Python/bytecodes.c" + #line 1547 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2126 "Python/generated_cases.c.h" + #line 2234 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2130,7 +2238,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1532 "Python/bytecodes.c" + #line 1551 "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)) { @@ -2138,12 +2246,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2142 "Python/generated_cases.c.h" + #line 2250 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1540 "Python/bytecodes.c" + #line 1559 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2147 "Python/generated_cases.c.h" + #line 2255 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2151,17 +2259,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1546 "Python/bytecodes.c" + #line 1565 "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 2160 "Python/generated_cases.c.h" + #line 2268 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1551 "Python/bytecodes.c" + #line 1570 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2165 "Python/generated_cases.c.h" + #line 2273 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2171,13 +2279,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1558 "Python/bytecodes.c" + #line 1577 "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 2181 "Python/generated_cases.c.h" + #line 2289 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2191,7 +2299,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1573 "Python/bytecodes.c" + #line 1592 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2209,16 +2317,16 @@ // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); - #line 2213 "Python/generated_cases.c.h" + #line 2321 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1591 "Python/bytecodes.c" + #line 1610 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2222 "Python/generated_cases.c.h" + #line 2330 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2233,20 +2341,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1598 "Python/bytecodes.c" + #line 1617 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2244 "Python/generated_cases.c.h" + #line 2352 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1605 "Python/bytecodes.c" + #line 1624 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2250 "Python/generated_cases.c.h" + #line 2358 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2261,7 +2369,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1609 "Python/bytecodes.c" + #line 1628 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2282,7 +2390,7 @@ res = res2; res2 = NULL; } - #line 2286 "Python/generated_cases.c.h" + #line 2394 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2296,7 +2404,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1646 "Python/bytecodes.c" + #line 1665 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2330,9 +2438,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2334 "Python/generated_cases.c.h" + #line 2442 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1680 "Python/bytecodes.c" + #line 1699 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2341,12 +2449,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2345 "Python/generated_cases.c.h" + #line 2453 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1689 "Python/bytecodes.c" + #line 1708 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2350 "Python/generated_cases.c.h" + #line 2458 "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; } @@ -2360,7 +2468,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1694 "Python/bytecodes.c" + #line 1713 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2373,7 +2481,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2377 "Python/generated_cases.c.h" + #line 2485 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2388,7 +2496,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1710 "Python/bytecodes.c" + #line 1729 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2401,7 +2509,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2405 "Python/generated_cases.c.h" + #line 2513 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2416,7 +2524,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1726 "Python/bytecodes.c" + #line 1745 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2443,7 +2551,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2447 "Python/generated_cases.c.h" + #line 2555 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2458,7 +2566,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1756 "Python/bytecodes.c" + #line 1775 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2468,7 +2576,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2472 "Python/generated_cases.c.h" + #line 2580 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2483,7 +2591,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1769 "Python/bytecodes.c" + #line 1788 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2495,7 +2603,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2499 "Python/generated_cases.c.h" + #line 2607 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2509,7 +2617,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 1784 "Python/bytecodes.c" + #line 1803 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2533,7 +2641,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2537 "Python/generated_cases.c.h" + #line 2645 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2541,7 +2649,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 1810 "Python/bytecodes.c" + #line 1829 "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); @@ -2567,7 +2675,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2571 "Python/generated_cases.c.h" + #line 2679 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2575,7 +2683,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 1838 "Python/bytecodes.c" + #line 1857 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2593,7 +2701,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2597 "Python/generated_cases.c.h" + #line 2705 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2604,7 +2712,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 1858 "Python/bytecodes.c" + #line 1877 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2643,7 +2751,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2647 "Python/generated_cases.c.h" + #line 2755 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2654,7 +2762,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 1899 "Python/bytecodes.c" + #line 1918 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2664,7 +2772,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2668 "Python/generated_cases.c.h" + #line 2776 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2676,7 +2784,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1918 "Python/bytecodes.c" + #line 1937 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2689,12 +2797,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2693 "Python/generated_cases.c.h" + #line 2801 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1931 "Python/bytecodes.c" + #line 1950 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2698 "Python/generated_cases.c.h" + #line 2806 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2705,7 +2813,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1935 "Python/bytecodes.c" + #line 1954 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2717,7 +2825,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2721 "Python/generated_cases.c.h" + #line 2829 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2728,7 +2836,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1950 "Python/bytecodes.c" + #line 1969 "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); @@ -2744,7 +2852,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2748 "Python/generated_cases.c.h" + #line 2856 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2755,7 +2863,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1969 "Python/bytecodes.c" + #line 1988 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2768,7 +2876,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2772 "Python/generated_cases.c.h" + #line 2880 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2779,14 +2887,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1984 "Python/bytecodes.c" + #line 2003 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2785 "Python/generated_cases.c.h" + #line 2893 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1986 "Python/bytecodes.c" + #line 2005 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2790 "Python/generated_cases.c.h" + #line 2898 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2796,15 +2904,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1990 "Python/bytecodes.c" + #line 2009 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2802 "Python/generated_cases.c.h" + #line 2910 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1992 "Python/bytecodes.c" + #line 2011 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2808 "Python/generated_cases.c.h" + #line 2916 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2815,12 +2923,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1997 "Python/bytecodes.c" + #line 2016 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2821 "Python/generated_cases.c.h" + #line 2929 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1999 "Python/bytecodes.c" + #line 2018 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2828,10 +2936,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2832 "Python/generated_cases.c.h" + #line 2940 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2007 "Python/bytecodes.c" + #line 2026 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2840,7 +2948,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2844 "Python/generated_cases.c.h" + #line 2952 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2850,21 +2958,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2018 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2857 "Python/generated_cases.c.h" + #line 2965 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2021 "Python/bytecodes.c" + #line 2040 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2864 "Python/generated_cases.c.h" + #line 2972 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2026 "Python/bytecodes.c" + #line 2045 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2868 "Python/generated_cases.c.h" + #line 2976 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2873,15 +2981,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2030 "Python/bytecodes.c" + #line 2049 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2880 "Python/generated_cases.c.h" + #line 2988 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2033 "Python/bytecodes.c" + #line 2052 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2885 "Python/generated_cases.c.h" + #line 2993 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2890,29 +2998,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2037 "Python/bytecodes.c" + #line 2056 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2898 "Python/generated_cases.c.h" + #line 3006 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2043 "Python/bytecodes.c" + #line 2062 "Python/bytecodes.c" JUMPBY(oparg); - #line 2907 "Python/generated_cases.c.h" + #line 3015 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2047 "Python/bytecodes.c" + #line 2066 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2916 "Python/generated_cases.c.h" + #line 3024 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2920,7 +3028,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2053 "Python/bytecodes.c" + #line 2072 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2930,9 +3038,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2934 "Python/generated_cases.c.h" + #line 3042 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2063 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2940,14 +3048,14 @@ if (err < 0) goto pop_1_error; } } - #line 2944 "Python/generated_cases.c.h" + #line 3052 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2073 "Python/bytecodes.c" + #line 2092 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2957,9 +3065,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2961 "Python/generated_cases.c.h" + #line 3069 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2083 "Python/bytecodes.c" + #line 2102 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2967,67 +3075,67 @@ if (err < 0) goto pop_1_error; } } - #line 2971 "Python/generated_cases.c.h" + #line 3079 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2093 "Python/bytecodes.c" + #line 2112 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2980 "Python/generated_cases.c.h" + #line 3088 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2095 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2988 "Python/generated_cases.c.h" + #line 3096 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2103 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 3001 "Python/generated_cases.c.h" + #line 3109 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2109 "Python/bytecodes.c" + #line 2128 "Python/bytecodes.c" } - #line 3005 "Python/generated_cases.c.h" + #line 3113 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2113 "Python/bytecodes.c" + #line 2132 "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 3018 "Python/generated_cases.c.h" + #line 3126 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2122 "Python/bytecodes.c" + #line 2141 "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 3031 "Python/generated_cases.c.h" + #line 3139 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3038,16 +3146,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2130 "Python/bytecodes.c" + #line 2149 "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 3047 "Python/generated_cases.c.h" + #line 3155 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2135 "Python/bytecodes.c" + #line 2154 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3055,7 +3163,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3059 "Python/generated_cases.c.h" + #line 3167 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3064,10 +3172,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2145 "Python/bytecodes.c" + #line 2164 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3071 "Python/generated_cases.c.h" + #line 3179 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3077,10 +3185,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2151 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3084 "Python/generated_cases.c.h" + #line 3192 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3091,11 +3199,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2157 "Python/bytecodes.c" + #line 2176 "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 3099 "Python/generated_cases.c.h" + #line 3207 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3104,14 +3212,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2163 "Python/bytecodes.c" + #line 2182 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3111 "Python/generated_cases.c.h" + #line 3219 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2166 "Python/bytecodes.c" + #line 2185 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3115 "Python/generated_cases.c.h" + #line 3223 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3119,7 +3227,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2170 "Python/bytecodes.c" + #line 2189 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3142,11 +3250,11 @@ if (iter == NULL) { goto error; } - #line 3146 "Python/generated_cases.c.h" + #line 3254 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2193 "Python/bytecodes.c" + #line 2212 "Python/bytecodes.c" } - #line 3150 "Python/generated_cases.c.h" + #line 3258 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3157,7 +3265,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2212 "Python/bytecodes.c" + #line 2231 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3188,7 +3296,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3192 "Python/generated_cases.c.h" + #line 3300 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3196,7 +3304,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2245 "Python/bytecodes.c" + #line 2264 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3222,14 +3330,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3226 "Python/generated_cases.c.h" + #line 3334 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2273 "Python/bytecodes.c" + #line 2292 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3249,7 +3357,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3253 "Python/generated_cases.c.h" + #line 3361 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3259,7 +3367,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2295 "Python/bytecodes.c" + #line 2314 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3279,7 +3387,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3283 "Python/generated_cases.c.h" + #line 3391 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3289,7 +3397,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2317 "Python/bytecodes.c" + #line 2336 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3307,7 +3415,7 @@ if (next == NULL) { goto error; } - #line 3311 "Python/generated_cases.c.h" + #line 3419 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3316,7 +3424,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2337 "Python/bytecodes.c" + #line 2356 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3332,14 +3440,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3336 "Python/generated_cases.c.h" + #line 3444 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2355 "Python/bytecodes.c" + #line 2374 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3362,16 +3470,16 @@ Py_DECREF(enter); goto error; } - #line 3366 "Python/generated_cases.c.h" + #line 3474 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2378 "Python/bytecodes.c" + #line 2397 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3375 "Python/generated_cases.c.h" + #line 3483 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3383,7 +3491,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2388 "Python/bytecodes.c" + #line 2407 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3409,16 +3517,16 @@ Py_DECREF(enter); goto error; } - #line 3413 "Python/generated_cases.c.h" + #line 3521 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2414 "Python/bytecodes.c" + #line 2433 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3422 "Python/generated_cases.c.h" + #line 3530 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3430,7 +3538,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2423 "Python/bytecodes.c" + #line 2442 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3451,7 +3559,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3455 "Python/generated_cases.c.h" + #line 3563 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3460,7 +3568,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2446 "Python/bytecodes.c" + #line 2465 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3470,7 +3578,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3474 "Python/generated_cases.c.h" + #line 3582 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3484,7 +3592,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 2458 "Python/bytecodes.c" + #line 2477 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3501,7 +3609,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3505 "Python/generated_cases.c.h" + #line 3613 "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; } @@ -3515,7 +3623,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2477 "Python/bytecodes.c" + #line 2496 "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); @@ -3525,7 +3633,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3529 "Python/generated_cases.c.h" + #line 3637 "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; } @@ -3539,7 +3647,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2489 "Python/bytecodes.c" + #line 2508 "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; @@ -3553,7 +3661,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3557 "Python/generated_cases.c.h" + #line 3665 "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; } @@ -3562,16 +3670,16 @@ } TARGET(KW_NAMES) { - #line 2505 "Python/bytecodes.c" + #line 2524 "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 3570 "Python/generated_cases.c.h" + #line 3678 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2511 "Python/bytecodes.c" + #line 2530 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3584,7 +3692,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3588 "Python/generated_cases.c.h" + #line 3696 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3594,7 +3702,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2556 "Python/bytecodes.c" + #line 2575 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3676,7 +3784,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3680 "Python/generated_cases.c.h" + #line 3788 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3688,7 +3796,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2644 "Python/bytecodes.c" + #line 2663 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3698,7 +3806,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3702 "Python/generated_cases.c.h" + #line 3810 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3707,7 +3815,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2656 "Python/bytecodes.c" + #line 2675 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3733,7 +3841,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3737 "Python/generated_cases.c.h" + #line 3845 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3741,7 +3849,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2684 "Python/bytecodes.c" + #line 2703 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3777,7 +3885,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3781 "Python/generated_cases.c.h" + #line 3889 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3785,7 +3893,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2722 "Python/bytecodes.c" + #line 2741 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3795,7 +3903,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3799 "Python/generated_cases.c.h" + #line 3907 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3808,7 +3916,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2734 "Python/bytecodes.c" + #line 2753 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3819,7 +3927,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3823 "Python/generated_cases.c.h" + #line 3931 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3833,7 +3941,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2748 "Python/bytecodes.c" + #line 2767 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3844,7 +3952,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3848 "Python/generated_cases.c.h" + #line 3956 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3858,7 +3966,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2762 "Python/bytecodes.c" + #line 2781 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3880,7 +3988,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3884 "Python/generated_cases.c.h" + #line 3992 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3894,7 +4002,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2787 "Python/bytecodes.c" + #line 2806 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3922,7 +4030,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3926 "Python/generated_cases.c.h" + #line 4034 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3936,7 +4044,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2818 "Python/bytecodes.c" + #line 2837 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -3968,7 +4076,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3972 "Python/generated_cases.c.h" + #line 4080 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3982,7 +4090,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2853 "Python/bytecodes.c" + #line 2872 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4014,7 +4122,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4018 "Python/generated_cases.c.h" + #line 4126 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4028,7 +4136,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2888 "Python/bytecodes.c" + #line 2907 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4053,7 +4161,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4057 "Python/generated_cases.c.h" + #line 4165 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4066,7 +4174,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2915 "Python/bytecodes.c" + #line 2934 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4093,7 +4201,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4097 "Python/generated_cases.c.h" + #line 4205 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4105,7 +4213,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2945 "Python/bytecodes.c" + #line 2964 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4123,14 +4231,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4127 "Python/generated_cases.c.h" + #line 4235 "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 2965 "Python/bytecodes.c" + #line 2984 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4161,7 +4269,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4165 "Python/generated_cases.c.h" + #line 4273 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4174,7 +4282,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2999 "Python/bytecodes.c" + #line 3018 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4203,7 +4311,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4207 "Python/generated_cases.c.h" + #line 4315 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4216,7 +4324,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3031 "Python/bytecodes.c" + #line 3050 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4245,7 +4353,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4249 "Python/generated_cases.c.h" + #line 4357 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4258,7 +4366,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3063 "Python/bytecodes.c" + #line 3082 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4286,7 +4394,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4290 "Python/generated_cases.c.h" + #line 4398 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4296,9 +4404,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3094 "Python/bytecodes.c" + #line 3113 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4302 "Python/generated_cases.c.h" + #line 4410 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4307,7 +4415,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3098 "Python/bytecodes.c" + #line 3117 "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)); @@ -4369,14 +4477,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4373 "Python/generated_cases.c.h" + #line 4481 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3160 "Python/bytecodes.c" + #line 3179 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4380 "Python/generated_cases.c.h" + #line 4488 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4391,7 +4499,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 3170 "Python/bytecodes.c" + #line 3189 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4420,14 +4528,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4424 "Python/generated_cases.c.h" + #line 4532 "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 3201 "Python/bytecodes.c" + #line 3220 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4448,7 +4556,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4452 "Python/generated_cases.c.h" + #line 4560 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4456,15 +4564,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3224 "Python/bytecodes.c" + #line 3243 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4462 "Python/generated_cases.c.h" + #line 4570 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3226 "Python/bytecodes.c" + #line 3245 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4468 "Python/generated_cases.c.h" + #line 4576 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4475,7 +4583,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 3230 "Python/bytecodes.c" + #line 3249 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4510,7 +4618,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 4514 "Python/generated_cases.c.h" + #line 4622 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4519,10 +4627,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3267 "Python/bytecodes.c" + #line 3286 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4526 "Python/generated_cases.c.h" + #line 4634 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4534,7 +4642,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3272 "Python/bytecodes.c" + #line 3291 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4549,12 +4657,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4553 "Python/generated_cases.c.h" + #line 4661 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3287 "Python/bytecodes.c" + #line 3306 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4558 "Python/generated_cases.c.h" + #line 4666 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4564,16 +4672,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3292 "Python/bytecodes.c" + #line 3311 "Python/bytecodes.c" assert(oparg >= 2); - #line 4570 "Python/generated_cases.c.h" + #line 4678 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3296 "Python/bytecodes.c" + #line 3315 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4585,26 +4693,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4589 "Python/generated_cases.c.h" + #line 4697 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3310 "Python/bytecodes.c" + #line 3329 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4595 "Python/generated_cases.c.h" + #line 4703 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3314 "Python/bytecodes.c" + #line 3333 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4602 "Python/generated_cases.c.h" + #line 4710 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3319 "Python/bytecodes.c" + #line 3338 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4613,12 +4721,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4617 "Python/generated_cases.c.h" + #line 4725 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3330 "Python/bytecodes.c" + #line 3349 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4627,12 +4735,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4631 "Python/generated_cases.c.h" + #line 4739 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3341 "Python/bytecodes.c" + #line 3360 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4645,12 +4753,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4649 "Python/generated_cases.c.h" + #line 4757 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3356 "Python/bytecodes.c" + #line 3375 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4663,30 +4771,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4667 "Python/generated_cases.c.h" + #line 4775 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3371 "Python/bytecodes.c" + #line 3390 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4678 "Python/generated_cases.c.h" + #line 4786 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3379 "Python/bytecodes.c" + #line 3398 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4685 "Python/generated_cases.c.h" + #line 4793 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3384 "Python/bytecodes.c" + #line 3403 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4692 "Python/generated_cases.c.h" + #line 4800 "Python/generated_cases.c.h" } diff --git a/Python/intrinsics.c b/Python/intrinsics.c index cca29d859902..c6f5ac5402d6 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -3,10 +3,12 @@ #include "Python.h" #include "pycore_frame.h" +#include "pycore_function.h" #include "pycore_runtime.h" #include "pycore_global_objects.h" #include "pycore_intrinsics.h" #include "pycore_pyerrors.h" +#include "pycore_typevarobject.h" /******** Unary functions ********/ @@ -199,6 +201,13 @@ list_to_tuple(PyThreadState* unused, PyObject *v) return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v)); } +static PyObject * +make_typevar(PyThreadState* Py_UNUSED(ignored), PyObject *v) +{ + assert(PyUnicode_Check(v)); + return _Py_make_typevar(v, NULL, NULL); +} + const instrinsic_func1 _PyIntrinsics_UnaryFunctions[] = { [0] = no_intrinsic, @@ -208,6 +217,11 @@ _PyIntrinsics_UnaryFunctions[] = { [INTRINSIC_ASYNC_GEN_WRAP] = _PyAsyncGenValueWrapperNew, [INTRINSIC_UNARY_POSITIVE] = unary_pos, [INTRINSIC_LIST_TO_TUPLE] = list_to_tuple, + [INTRINSIC_TYPEVAR] = make_typevar, + [INTRINSIC_PARAMSPEC] = _Py_make_paramspec, + [INTRINSIC_TYPEVARTUPLE] = _Py_make_typevartuple, + [INTRINSIC_SUBSCRIPT_GENERIC] = _Py_subscript_generic, + [INTRINSIC_TYPEALIAS] = _Py_make_typealias, }; @@ -221,8 +235,26 @@ prep_reraise_star(PyThreadState* unused, PyObject *orig, PyObject *excs) return _PyExc_PrepReraiseStar(orig, excs); } +static PyObject * +make_typevar_with_bound(PyThreadState* Py_UNUSED(ignored), PyObject *name, + PyObject *evaluate_bound) +{ + assert(PyUnicode_Check(name)); + return _Py_make_typevar(name, evaluate_bound, NULL); +} + +static PyObject * +make_typevar_with_constraints(PyThreadState* Py_UNUSED(ignored), PyObject *name, + PyObject *evaluate_constraints) +{ + assert(PyUnicode_Check(name)); + return _Py_make_typevar(name, NULL, evaluate_constraints); +} + const instrinsic_func2 _PyIntrinsics_BinaryFunctions[] = { [INTRINSIC_PREP_RERAISE_STAR] = prep_reraise_star, + [INTRINSIC_TYPEVAR_WITH_BOUND] = make_typevar_with_bound, + [INTRINSIC_TYPEVAR_WITH_CONSTRAINTS] = make_typevar_with_constraints, + [INTRINSIC_SET_FUNCTION_TYPE_PARAMS] = _Py_set_function_type_params, }; - diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index ae68e045a611..601ad3874b79 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -161,8 +161,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case DELETE_GLOBAL: return 0; - case LOAD_NAME: + case LOAD_LOCALS: return 0; + case LOAD_NAME: + return 0+1; + case LOAD_FROM_DICT_OR_GLOBALS: + return 1; case LOAD_GLOBAL: return 0; case LOAD_GLOBAL_MODULE: @@ -175,8 +179,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case DELETE_DEREF: return 0; - case LOAD_CLASSDEREF: - return 0; + case LOAD_FROM_DICT_OR_DEREF: + return 1; case LOAD_DEREF: return 0; case STORE_DEREF: @@ -551,7 +555,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case DELETE_GLOBAL: return 0; + case LOAD_LOCALS: + return 1; case LOAD_NAME: + return 1+1; + case LOAD_FROM_DICT_OR_GLOBALS: return 1; case LOAD_GLOBAL: return ((oparg & 1) ? 1 : 0) + 1; @@ -565,7 +573,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case DELETE_DEREF: return 0; - case LOAD_CLASSDEREF: + case LOAD_FROM_DICT_OR_DEREF: return 1; case LOAD_DEREF: return 1; @@ -869,14 +877,16 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [DELETE_ATTR] = { true, INSTR_FMT_IB }, [STORE_GLOBAL] = { true, INSTR_FMT_IB }, [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, + [LOAD_LOCALS] = { true, INSTR_FMT_IB }, [LOAD_NAME] = { true, INSTR_FMT_IB }, + [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB }, [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, [DELETE_FAST] = { true, INSTR_FMT_IB }, [MAKE_CELL] = { true, INSTR_FMT_IB }, [DELETE_DEREF] = { true, INSTR_FMT_IB }, - [LOAD_CLASSDEREF] = { true, INSTR_FMT_IB }, + [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB }, [LOAD_DEREF] = { true, INSTR_FMT_IB }, [STORE_DEREF] = { true, INSTR_FMT_IB }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f2742f4ad1f2..af05a33058f3 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -86,8 +86,8 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_LOCALS, &&TARGET_LOAD_FAST__LOAD_FAST, - &&TARGET_LOAD_GLOBAL_BUILTIN, &&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_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -147,7 +147,7 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_LOAD_CLASSDEREF, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, @@ -174,8 +174,8 @@ static void *opcode_targets[256] = { &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_2, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_LOAD_FROM_DICT_OR_GLOBALS, + &&TARGET_LOAD_FROM_DICT_OR_DEREF, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index cb87f2c08601..740901f53d2d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -26,6 +26,7 @@ #include "pycore_sysmodule.h" // _PySys_ClearAuditHooks() #include "pycore_traceback.h" // _Py_DumpTracebackThreads() #include "pycore_typeobject.h" // _PyTypes_InitTypes() +#include "pycore_typevarobject.h" // _Py_clear_generic_types() #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" @@ -1698,6 +1699,7 @@ finalize_interp_clear(PyThreadState *tstate) int is_main_interp = _Py_IsMainInterpreter(tstate->interp); _PyExc_ClearExceptionGroupType(tstate->interp); + _Py_clear_generic_types(tstate->interp); /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); diff --git a/Python/symtable.c b/Python/symtable.c index 2c29f6084135..3451f6c7bffb 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -47,6 +47,18 @@ #define ANNOTATION_NOT_ALLOWED \ "'%s' can not be used within an annotation" +#define TYPEVAR_BOUND_NOT_ALLOWED \ +"'%s' can not be used within a TypeVar bound" + +#define TYPEALIAS_NOT_ALLOWED \ +"'%s' can not be used within a type alias" + +#define TYPEPARAM_NOT_ALLOWED \ +"'%s' can not be used within the definition of a generic" + +#define DUPLICATE_TYPE_PARAM \ +"duplicate type parameter '%U'" + #define LOCATION(x) \ (x)->lineno, (x)->col_offset, (x)->end_lineno, (x)->end_col_offset @@ -95,7 +107,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block, if (st->st_cur != NULL && (st->st_cur->ste_nested || - st->st_cur->ste_type == FunctionBlock)) + _PyST_IsFunctionLike(st->st_cur))) ste->ste_nested = 1; ste->ste_child_free = 0; ste->ste_generator = 0; @@ -105,7 +117,9 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block, ste->ste_needs_class_closure = 0; ste->ste_comp_inlined = 0; ste->ste_comp_iter_target = 0; + ste->ste_can_see_class_scope = 0; ste->ste_comp_iter_expr = 0; + ste->ste_needs_classdict = 0; ste->ste_symbols = PyDict_New(); ste->ste_varnames = PyList_New(0); @@ -208,6 +222,7 @@ static int symtable_enter_block(struct symtable *st, identifier name, static int symtable_exit_block(struct symtable *st); static int symtable_visit_stmt(struct symtable *st, stmt_ty s); static int symtable_visit_expr(struct symtable *st, expr_ty s); +static int symtable_visit_typeparam(struct symtable *st, typeparam_ty s); static int symtable_visit_genexp(struct symtable *st, expr_ty s); static int symtable_visit_listcomp(struct symtable *st, expr_ty s); static int symtable_visit_setcomp(struct symtable *st, expr_ty s); @@ -403,6 +418,15 @@ _PyST_GetScope(PySTEntryObject *ste, PyObject *name) return (symbol >> SCOPE_OFFSET) & SCOPE_MASK; } +int +_PyST_IsFunctionLike(PySTEntryObject *ste) +{ + return ste->ste_type == FunctionBlock + || ste->ste_type == TypeVarBoundBlock + || ste->ste_type == TypeAliasBlock + || ste->ste_type == TypeParamBlock; +} + static int error_at_directive(PySTEntryObject *ste, PyObject *name) { @@ -495,7 +519,7 @@ error_at_directive(PySTEntryObject *ste, PyObject *name) static int analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, PyObject *bound, PyObject *local, PyObject *free, - PyObject *global) + PyObject *global, PyObject *typeparams, PySTEntryObject *class_entry) { if (flags & DEF_GLOBAL) { if (flags & DEF_NONLOCAL) { @@ -524,6 +548,12 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, return error_at_directive(ste, name); } + if (PySet_Contains(typeparams, name)) { + PyErr_Format(PyExc_SyntaxError, + "nonlocal binding not allowed for type parameter '%U'", + name); + return error_at_directive(ste, name); + } SET_SCOPE(scopes, name, FREE); ste->ste_free = 1; return PySet_Add(free, name) >= 0; @@ -534,8 +564,34 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, return 0; if (PySet_Discard(global, name) < 0) return 0; + if (flags & DEF_TYPE_PARAM) { + if (PySet_Add(typeparams, name) < 0) + return 0; + } + else { + if (PySet_Discard(typeparams, name) < 0) + return 0; + } return 1; } + // If we were passed class_entry (i.e., we're in an ste_can_see_class_scope scope) + // and the bound name is in that set, then the name is potentially bound both by + // the immediately enclosing class namespace, and also by an outer function namespace. + // In that case, we want the runtime name resolution to look at only the class + // namespace and the globals (not the namespace providing the bound). + // Similarly, if the name is explicitly global in the class namespace (through the + // global statement), we want to also treat it as a global in this scope. + if (class_entry != NULL) { + long class_flags = _PyST_GetSymbol(class_entry, name); + if (class_flags & DEF_GLOBAL) { + SET_SCOPE(scopes, name, GLOBAL_EXPLICIT); + return 1; + } + else if (class_flags & DEF_BOUND && !(class_flags & DEF_NONLOCAL)) { + SET_SCOPE(scopes, name, GLOBAL_IMPLICIT); + return 1; + } + } /* If an enclosing block has a binding for this name, it is a free variable rather than a global variable. Note that having a non-NULL bound implies that the block @@ -611,7 +667,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, if (PyLong_AsLong(existing) & DEF_BOUND) { // cell vars in comprehension that are locals in outer scope // must be promoted to cell so u_cellvars isn't wrong - if (scope == CELL && ste->ste_type == FunctionBlock) { + if (scope == CELL && _PyST_IsFunctionLike(ste)) { if (PySet_Add(promote_to_cell, k) < 0) { return 0; } @@ -682,6 +738,11 @@ drop_class_free(PySTEntryObject *ste, PyObject *free) return 0; if (res) ste->ste_needs_class_closure = 1; + res = PySet_Discard(free, &_Py_ID(__classdict__)); + if (res < 0) + return 0; + if (res) + ste->ste_needs_classdict = 1; return 1; } @@ -799,11 +860,13 @@ update_symbols(PyObject *symbols, PyObject *scopes, static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, - PyObject *global, PyObject **child_free); + PyObject *global, PyObject *typeparams, + PySTEntryObject *class_entry, PyObject **child_free); static int analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, - PyObject *global) + PyObject *global, PyObject *typeparams, + PySTEntryObject *class_entry) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; PyObject *newglobal = NULL, *newfree = NULL, *promote_to_cell = NULL; @@ -865,14 +928,14 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) { long flags = PyLong_AS_LONG(v); if (!analyze_name(ste, scopes, name, flags, - bound, local, free, global)) + bound, local, free, global, typeparams, class_entry)) goto error; } /* Populate global and bound sets to be passed to children. */ if (ste->ste_type != ClassBlock) { /* Add function locals to bound set */ - if (ste->ste_type == FunctionBlock) { + if (_PyST_IsFunctionLike(ste)) { temp = PyNumber_InPlaceOr(newbound, local); if (!temp) goto error; @@ -892,9 +955,11 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, Py_DECREF(temp); } else { - /* Special-case __class__ */ + /* Special-case __class__ and __classdict__ */ if (PySet_Add(newbound, &_Py_ID(__class__)) < 0) goto error; + if (PySet_Add(newbound, &_Py_ID(__classdict__)) < 0) + goto error; } /* Recursively call analyze_child_block() on each child block. @@ -910,13 +975,23 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, assert(c && PySTEntry_Check(c)); entry = (PySTEntryObject*)c; + PySTEntryObject *new_class_entry = NULL; + if (entry->ste_can_see_class_scope) { + if (ste->ste_type == ClassBlock) { + new_class_entry = ste; + } + else if (class_entry) { + new_class_entry = class_entry; + } + } + // we inline all non-generator-expression comprehensions int inline_comp = entry->ste_comprehension && !entry->ste_generator; if (!analyze_child_block(entry, newbound, newfree, newglobal, - &child_free)) + typeparams, new_class_entry, &child_free)) { goto error; } @@ -952,7 +1027,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, } /* Check if any local variables must be converted to cell variables */ - if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree, promote_to_cell)) + if (_PyST_IsFunctionLike(ste) && !analyze_cells(scopes, newfree, promote_to_cell)) goto error; else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree)) goto error; @@ -980,9 +1055,11 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, - PyObject *global, PyObject** child_free) + PyObject *global, PyObject *typeparams, + PySTEntryObject *class_entry, PyObject** child_free) { PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL; + PyObject *temp_typeparams = NULL; /* Copy the bound/global/free sets. @@ -1000,24 +1077,30 @@ analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, temp_global = PySet_New(global); if (!temp_global) goto error; + temp_typeparams = PySet_New(typeparams); + if (!temp_typeparams) + goto error; - if (!analyze_block(entry, temp_bound, temp_free, temp_global)) + if (!analyze_block(entry, temp_bound, temp_free, temp_global, + temp_typeparams, class_entry)) goto error; *child_free = temp_free; Py_DECREF(temp_bound); Py_DECREF(temp_global); + Py_DECREF(temp_typeparams); return 1; error: Py_XDECREF(temp_bound); Py_XDECREF(temp_free); Py_XDECREF(temp_global); + Py_XDECREF(temp_typeparams); return 0; } static int symtable_analyze(struct symtable *st) { - PyObject *free, *global; + PyObject *free, *global, *typeparams; int r; free = PySet_New(NULL); @@ -1028,9 +1111,16 @@ symtable_analyze(struct symtable *st) Py_DECREF(free); return 0; } - r = analyze_block(st->st_top, NULL, free, global); + typeparams = PySet_New(NULL); + if (!typeparams) { + Py_DECREF(free); + Py_DECREF(global); + return 0; + } + r = analyze_block(st->st_top, NULL, free, global, typeparams, NULL); Py_DECREF(free); Py_DECREF(global); + Py_DECREF(typeparams); return r; } @@ -1133,6 +1223,13 @@ symtable_add_def_helper(struct symtable *st, PyObject *name, int flag, struct _s end_lineno, end_col_offset + 1); goto error; } + if ((flag & DEF_TYPE_PARAM) && (val & DEF_TYPE_PARAM)) { + PyErr_Format(PyExc_SyntaxError, DUPLICATE_TYPE_PARAM, name); + PyErr_RangedSyntaxLocationObject(st->st_filename, + lineno, col_offset + 1, + end_lineno, end_col_offset + 1); + goto error; + } val |= flag; } else if (PyErr_Occurred()) { @@ -1204,6 +1301,65 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag, lineno, col_offset, end_lineno, end_col_offset); } +static int +symtable_enter_typeparam_block(struct symtable *st, identifier name, + void *ast, int has_defaults, int has_kwdefaults, + enum _stmt_kind kind, + int lineno, int col_offset, + int end_lineno, int end_col_offset) +{ + _Py_block_ty current_type = st->st_cur->ste_type; + if(!symtable_enter_block(st, name, TypeParamBlock, ast, lineno, + col_offset, end_lineno, end_col_offset)) { + return 0; + } + if (current_type == ClassBlock) { + st->st_cur->ste_can_see_class_scope = 1; + if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + } + if (kind == ClassDef_kind) { + _Py_DECLARE_STR(type_params, ".type_params"); + // It gets "set" when we create the type params tuple and + // "used" when we build up the bases. + if (!symtable_add_def(st, &_Py_STR(type_params), DEF_LOCAL, + lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + if (!symtable_add_def(st, &_Py_STR(type_params), USE, + lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + st->st_private = name; + // This is used for setting the generic base + _Py_DECLARE_STR(generic_base, ".generic_base"); + if (!symtable_add_def(st, &_Py_STR(generic_base), DEF_LOCAL, + lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + if (!symtable_add_def(st, &_Py_STR(generic_base), USE, + lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + } + if (has_defaults) { + _Py_DECLARE_STR(defaults, ".defaults"); + if (!symtable_add_def(st, &_Py_STR(defaults), DEF_PARAM, + lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + } + if (has_kwdefaults) { + _Py_DECLARE_STR(kwdefaults, ".kwdefaults"); + if (!symtable_add_def(st, &_Py_STR(kwdefaults), DEF_PARAM, + lineno, col_offset, end_lineno, end_col_offset)) { + return 0; + } + } + return 1; +} + /* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument. They use the ASDL name to synthesize the name of the C type and the visit function. @@ -1275,6 +1431,17 @@ symtable_record_directive(struct symtable *st, identifier name, int lineno, return res == 0; } +static int +has_kwonlydefaults(asdl_arg_seq *kwonlyargs, asdl_expr_seq *kw_defaults) +{ + for (int i = 0; i < asdl_seq_LEN(kwonlyargs); i++) { + expr_ty default_ = asdl_seq_GET(kw_defaults, i); + if (default_) { + return 1; + } + } + return 0; +} static int symtable_visit_stmt(struct symtable *st, stmt_ty s) @@ -1292,11 +1459,24 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults); if (s->v.FunctionDef.args->kw_defaults) VISIT_SEQ_WITH_NULL(st, expr, s->v.FunctionDef.args->kw_defaults); + if (s->v.FunctionDef.decorator_list) + VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list); + if (asdl_seq_LEN(s->v.FunctionDef.typeparams) > 0) { + if (!symtable_enter_typeparam_block( + st, s->v.FunctionDef.name, + (void *)s->v.FunctionDef.typeparams, + s->v.FunctionDef.args->defaults != NULL, + has_kwonlydefaults(s->v.FunctionDef.args->kwonlyargs, + s->v.FunctionDef.args->kw_defaults), + s->kind, + LOCATION(s))) { + VISIT_QUIT(st, 0); + } + VISIT_SEQ(st, typeparam, s->v.FunctionDef.typeparams); + } if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args, s->v.FunctionDef.returns)) VISIT_QUIT(st, 0); - if (s->v.FunctionDef.decorator_list) - VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list); if (!symtable_enter_block(st, s->v.FunctionDef.name, FunctionBlock, (void *)s, LOCATION(s))) @@ -1305,25 +1485,85 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ(st, stmt, s->v.FunctionDef.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); + if (asdl_seq_LEN(s->v.FunctionDef.typeparams) > 0) { + if (!symtable_exit_block(st)) + VISIT_QUIT(st, 0); + } break; case ClassDef_kind: { PyObject *tmp; if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL, LOCATION(s))) VISIT_QUIT(st, 0); - VISIT_SEQ(st, expr, s->v.ClassDef.bases); - VISIT_SEQ(st, keyword, s->v.ClassDef.keywords); if (s->v.ClassDef.decorator_list) VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list); + if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) { + if (!symtable_enter_typeparam_block(st, s->v.ClassDef.name, + (void *)s->v.ClassDef.typeparams, + false, false, s->kind, + LOCATION(s))) { + VISIT_QUIT(st, 0); + } + VISIT_SEQ(st, typeparam, s->v.ClassDef.typeparams); + } + VISIT_SEQ(st, expr, s->v.ClassDef.bases); + VISIT_SEQ(st, keyword, s->v.ClassDef.keywords); if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, (void *)s, s->lineno, s->col_offset, s->end_lineno, s->end_col_offset)) VISIT_QUIT(st, 0); tmp = st->st_private; st->st_private = s->v.ClassDef.name; + if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) { + if (!symtable_add_def(st, &_Py_ID(__type_params__), + DEF_LOCAL, LOCATION(s))) { + VISIT_QUIT(st, 0); + } + _Py_DECLARE_STR(type_params, ".type_params"); + if (!symtable_add_def(st, &_Py_STR(type_params), + USE, LOCATION(s))) { + VISIT_QUIT(st, 0); + } + } VISIT_SEQ(st, stmt, s->v.ClassDef.body); st->st_private = tmp; if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); + if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) { + if (!symtable_exit_block(st)) + VISIT_QUIT(st, 0); + } + break; + } + case TypeAlias_kind: { + VISIT(st, expr, s->v.TypeAlias.name); + assert(s->v.TypeAlias.name->kind == Name_kind); + PyObject *name = s->v.TypeAlias.name->v.Name.id; + int is_in_class = st->st_cur->ste_type == ClassBlock; + int is_generic = asdl_seq_LEN(s->v.TypeAlias.typeparams) > 0; + if (is_generic) { + if (!symtable_enter_typeparam_block( + st, name, + (void *)s->v.TypeAlias.typeparams, + false, false, s->kind, + LOCATION(s))) { + VISIT_QUIT(st, 0); + } + VISIT_SEQ(st, typeparam, s->v.TypeAlias.typeparams); + } + if (!symtable_enter_block(st, name, TypeAliasBlock, + (void *)s, LOCATION(s))) + VISIT_QUIT(st, 0); + st->st_cur->ste_can_see_class_scope = is_in_class; + if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(s->v.TypeAlias.value))) { + VISIT_QUIT(st, 0); + } + VISIT(st, expr, s->v.TypeAlias.value); + if (!symtable_exit_block(st)) + VISIT_QUIT(st, 0); + if (is_generic) { + if (!symtable_exit_block(st)) + VISIT_QUIT(st, 0); + } break; } case Return_kind: @@ -1532,11 +1772,24 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) if (s->v.AsyncFunctionDef.args->kw_defaults) VISIT_SEQ_WITH_NULL(st, expr, s->v.AsyncFunctionDef.args->kw_defaults); + if (s->v.AsyncFunctionDef.decorator_list) + VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list); + if (asdl_seq_LEN(s->v.AsyncFunctionDef.typeparams) > 0) { + if (!symtable_enter_typeparam_block( + st, s->v.AsyncFunctionDef.name, + (void *)s->v.AsyncFunctionDef.typeparams, + s->v.AsyncFunctionDef.args->defaults != NULL, + has_kwonlydefaults(s->v.AsyncFunctionDef.args->kwonlyargs, + s->v.AsyncFunctionDef.args->kw_defaults), + s->kind, + LOCATION(s))) { + VISIT_QUIT(st, 0); + } + VISIT_SEQ(st, typeparam, s->v.AsyncFunctionDef.typeparams); + } if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args, s->v.AsyncFunctionDef.returns)) VISIT_QUIT(st, 0); - if (s->v.AsyncFunctionDef.decorator_list) - VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list); if (!symtable_enter_block(st, s->v.AsyncFunctionDef.name, FunctionBlock, (void *)s, s->lineno, s->col_offset, @@ -1547,6 +1800,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); + if (asdl_seq_LEN(s->v.AsyncFunctionDef.typeparams) > 0) { + if (!symtable_exit_block(st)) + VISIT_QUIT(st, 0); + } break; case AsyncWith_kind: VISIT_SEQ(st, withitem, s->v.AsyncWith.items); @@ -1598,7 +1855,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e) } /* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */ - if (ste->ste_type == FunctionBlock) { + if (_PyST_IsFunctionLike(ste)) { long target_in_scope = _PyST_GetSymbol(ste, target_name); if (target_in_scope & DEF_GLOBAL) { if (!symtable_add_def(st, target_name, DEF_GLOBAL, LOCATION(e))) @@ -1633,7 +1890,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e) } } - /* We should always find either a FunctionBlock, ModuleBlock or ClassBlock + /* We should always find either a function-like block, ModuleBlock or ClassBlock and should never fall to this case */ Py_UNREACHABLE(); @@ -1806,7 +2063,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) VISIT_QUIT(st, 0); /* Special-case super: it counts as a use of __class__ */ if (e->v.Name.ctx == Load && - st->st_cur->ste_type == FunctionBlock && + _PyST_IsFunctionLike(st->st_cur) && _PyUnicode_EqualToASCIIString(e->v.Name.id, "super")) { if (!symtable_add_def(st, &_Py_ID(__class__), USE, LOCATION(e))) VISIT_QUIT(st, 0); @@ -1823,6 +2080,45 @@ symtable_visit_expr(struct symtable *st, expr_ty e) VISIT_QUIT(st, 1); } +static int +symtable_visit_typeparam(struct symtable *st, typeparam_ty tp) +{ + if (++st->recursion_depth > st->recursion_limit) { + PyErr_SetString(PyExc_RecursionError, + "maximum recursion depth exceeded during compilation"); + VISIT_QUIT(st, 0); + } + switch(tp->kind) { + case TypeVar_kind: + if (!symtable_add_def(st, tp->v.TypeVar.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) + VISIT_QUIT(st, 0); + if (tp->v.TypeVar.bound) { + int is_in_class = st->st_cur->ste_can_see_class_scope; + if (!symtable_enter_block(st, tp->v.TypeVar.name, + TypeVarBoundBlock, (void *)tp, + LOCATION(tp))) + VISIT_QUIT(st, 0); + st->st_cur->ste_can_see_class_scope = is_in_class; + if (is_in_class && !symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(tp->v.TypeVar.bound))) { + VISIT_QUIT(st, 0); + } + VISIT(st, expr, tp->v.TypeVar.bound); + if (!symtable_exit_block(st)) + VISIT_QUIT(st, 0); + } + break; + case TypeVarTuple_kind: + if (!symtable_add_def(st, tp->v.TypeVarTuple.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) + VISIT_QUIT(st, 0); + break; + case ParamSpec_kind: + if (!symtable_add_def(st, tp->v.ParamSpec.name, DEF_TYPE_PARAM | DEF_LOCAL, LOCATION(tp))) + VISIT_QUIT(st, 0); + break; + } + VISIT_QUIT(st, 1); +} + static int symtable_visit_pattern(struct symtable *st, pattern_ty p) { @@ -2194,11 +2490,18 @@ symtable_visit_dictcomp(struct symtable *st, expr_ty e) static int symtable_raise_if_annotation_block(struct symtable *st, const char *name, expr_ty e) { - if (st->st_cur->ste_type != AnnotationBlock) { + enum _block_type type = st->st_cur->ste_type; + if (type == AnnotationBlock) + PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name); + else if (type == TypeVarBoundBlock) + PyErr_Format(PyExc_SyntaxError, TYPEVAR_BOUND_NOT_ALLOWED, name); + else if (type == TypeAliasBlock) + PyErr_Format(PyExc_SyntaxError, TYPEALIAS_NOT_ALLOWED, name); + else if (type == TypeParamBlock) + PyErr_Format(PyExc_SyntaxError, TYPEPARAM_NOT_ALLOWED, name); + else return 1; - } - PyErr_Format(PyExc_SyntaxError, ANNOTATION_NOT_ALLOWED, name); PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, From webhook-mailer at python.org Tue May 16 02:20:51 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 16 May 2023 06:20:51 -0000 Subject: [Python-checkins] gh-69152: add method get_proxy_response_headers to HTTPConnection class (#104248) Message-ID: <mailman.380.1684218051.13550.python-checkins@python.org> https://github.com/python/cpython/commit/85ec192ac4b000d4e47df6123b65eacbd1fdccfa commit: 85ec192ac4b000d4e47df6123b65eacbd1fdccfa branch: main author: Alexey Namyotkin <62434915+nametkin at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-16T06:20:30Z summary: gh-69152: add method get_proxy_response_headers to HTTPConnection class (#104248) Add http.client.HTTPConnection method get_proxy_response_headers() - this is a followup to https://github.com/python/cpython/pull/26152 which added it as a non-public attribute. This way we don't pre-compute a headers dictionary that most users will never access. The new method is properly public and documented and triggers full proxy header parsing into a dict only when actually called. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: M Doc/library/http.client.rst M Lib/http/client.py M Lib/test/test_httplib.py M Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index bf1f2e392078..46d616aae95c 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -394,6 +394,17 @@ HTTPConnection Objects one will be automatically generated and transmitted if not provided in the headers argument. + +.. method:: HTTPConnection.get_proxy_response_headers() + + Returns a dictionary with the headers of the response received from + the proxy server to the CONNECT request. + + If the CONNECT request was not sent, the method returns an empty dictionary. + + .. versionadded:: 3.12 + + .. method:: HTTPConnection.connect() Connect to the server specified when the object was created. By default, diff --git a/Lib/http/client.py b/Lib/http/client.py index 50f2b4680769..59a9fd72b472 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -221,8 +221,9 @@ def _read_headers(fp): break return headers -def parse_headers(fp, _class=HTTPMessage): - """Parses only RFC2822 headers from a file pointer. +def _parse_header_lines(header_lines, _class=HTTPMessage): + """ + Parses only RFC2822 headers from header lines. email Parser wants to see strings rather than bytes. But a TextIOWrapper around self.rfile would buffer too many bytes @@ -231,10 +232,15 @@ def parse_headers(fp, _class=HTTPMessage): to parse. """ - headers = _read_headers(fp) - hstring = b''.join(headers).decode('iso-8859-1') + hstring = b''.join(header_lines).decode('iso-8859-1') return email.parser.Parser(_class=_class).parsestr(hstring) +def parse_headers(fp, _class=HTTPMessage): + """Parses only RFC2822 headers from a file pointer.""" + + headers = _read_headers(fp) + return _parse_header_lines(headers, _class) + class HTTPResponse(io.BufferedIOBase): @@ -858,7 +864,7 @@ def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, self._tunnel_host = None self._tunnel_port = None self._tunnel_headers = {} - self._proxy_response_headers = None + self._raw_proxy_headers = None (self.host, self.port) = self._get_hostport(host, port) @@ -945,11 +951,11 @@ def _tunnel(self): try: (version, code, message) = response._read_status() - self._proxy_response_headers = parse_headers(response.fp) + self._raw_proxy_headers = _read_headers(response.fp) if self.debuglevel > 0: - for hdr, val in self._proxy_response_headers.items(): - print("header:", hdr + ":", val) + for header in self._raw_proxy_headers: + print('header:', header.decode()) if code != http.HTTPStatus.OK: self.close() @@ -958,6 +964,21 @@ def _tunnel(self): finally: response.close() + def get_proxy_response_headers(self): + """ + Returns a dictionary with the headers of the response + received from the proxy server to the CONNECT request + sent to set the tunnel. + + If the CONNECT request was not sent, the method returns + an empty dictionary. + """ + return ( + _parse_header_lines(self._raw_proxy_headers) + if self._raw_proxy_headers is not None + else {} + ) + def connect(self): """Connect to the host and port specified in __init__.""" sys.audit("http.client.connect", self, self.host, self.port) diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 4b1d355f550b..8955d45fa93d 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2401,7 +2401,7 @@ def test_proxy_response_headers(self): self.conn.set_tunnel('destination.com') self.conn.request('PUT', '/', '') - headers = self.conn._proxy_response_headers + headers = self.conn.get_proxy_response_headers() self.assertIn(expected_header, headers.items()) def test_tunnel_leak(self): diff --git a/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst b/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst index ba113673b7fb..0904b162e635 100644 --- a/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst +++ b/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst @@ -1,3 +1,3 @@ -Added attribute '_proxy_response_headers' to HTTPConnection class. This -attribute contains the headers of the proxy server response to the CONNECT -request. +Added :meth:`http.client.HTTPConnection.get_proxy_response_headers` that +provides access to the HTTP headers on a proxy server response to the +``CONNECT`` request. From webhook-mailer at python.org Tue May 16 03:44:29 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 16 May 2023 07:44:29 -0000 Subject: [Python-checkins] gh-103861: Fix Zip64 extensions not being properly applied in some cases (#103863) Message-ID: <mailman.381.1684223070.13550.python-checkins@python.org> https://github.com/python/cpython/commit/798bcaa1eb01de7db9ff1881a3088603ad09b096 commit: 798bcaa1eb01de7db9ff1881a3088603ad09b096 branch: main author: Carey Metcalfe <carey at cmetcalfe.ca> committer: gpshead <greg at krypto.org> date: 2023-05-16T00:43:44-07:00 summary: gh-103861: Fix Zip64 extensions not being properly applied in some cases (#103863) Fix Zip64 extensions not being properly applied in some cases: Fixes an issue where adding a small file to a `ZipFile` object while forcing zip64 extensions causes an extra Zip64 record to be added to the zip, but doesn't update the `min_version` or file sizes in the primary central directory header. Also fixed an edge case in checking if zip64 extensions are required: This fixes an issue where if data requiring zip64 extensions was added to an unseekable stream without specifying `force_zip64=True`, zip64 extensions would not be used and a RuntimeError would not be raised when closing the file (even though the size would be known at that point). This would result in successfully writing corrupt zip files. Deciding if zip64 extensions are required outside of the `FileHeader` function means that both `FileHeader` and `_ZipWriteFile` will always be in sync. Previously, the `FileHeader` function could enable zip64 extensions without propagating that decision to the `_ZipWriteFile` class, which would then not correctly write the data descriptor record or check for errors on close. If anyone is actually using `ZipInfo.FileHeader` as a public API without explicitly passing True or False in for zip64, their own code may still be susceptible to that kind of bug unless they make a similar change to where the zip64 decision happens. Fixes #103861 --------- Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst M Lib/test/test_zipfile/test_core.py M Lib/zipfile/__init__.py diff --git a/Lib/test/test_zipfile/test_core.py b/Lib/test/test_zipfile/test_core.py index 73c6b0185a1a..9960259c4cde 100644 --- a/Lib/test/test_zipfile/test_core.py +++ b/Lib/test/test_zipfile/test_core.py @@ -1080,6 +1080,159 @@ def test_generated_valid_zip64_extra(self): self.assertEqual(zinfo.header_offset, expected_header_offset) self.assertEqual(zf.read(zinfo), expected_content) + def test_force_zip64(self): + """Test that forcing zip64 extensions correctly notes this in the zip file""" + + # GH-103861 describes an issue where forcing a small file to use zip64 + # extensions would add a zip64 extra record, but not change the data + # sizes to 0xFFFFFFFF to indicate to the extractor that the zip64 + # record should be read. Additionally, it would not set the required + # version to indicate that zip64 extensions are required to extract it. + # This test replicates the situation and reads the raw data to specifically ensure: + # - The required extract version is always >= ZIP64_VERSION + # - The compressed and uncompressed size in the file headers are both + # 0xFFFFFFFF (ie. point to zip64 record) + # - The zip64 record is provided and has the correct sizes in it + # Other aspects of the zip are checked as well, but verifying the above is the main goal. + # Because this is hard to verify by parsing the data as a zip, the raw + # bytes are checked to ensure that they line up with the zip spec. + # The spec for this can be found at: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + # The relevent sections for this test are: + # - 4.3.7 for local file header + # - 4.5.3 for zip64 extra field + + data = io.BytesIO() + with zipfile.ZipFile(data, mode="w", allowZip64=True) as zf: + with zf.open("text.txt", mode="w", force_zip64=True) as zi: + zi.write(b"_") + + zipdata = data.getvalue() + + # pull out and check zip information + ( + header, vers, os, flags, comp, csize, usize, fn_len, + ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize, cd_sig + ) = struct.unpack("<4sBBHH8xIIHH8shhQQx4s", zipdata[:63]) + + self.assertEqual(header, b"PK\x03\x04") # local file header + self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract + self.assertEqual(os, 0) # compatible with MS-DOS + self.assertEqual(flags, 0) # no flags + self.assertEqual(comp, 0) # compression method = stored + self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra + self.assertEqual(usize, 0xFFFFFFFF) + self.assertEqual(fn_len, 8) # filename len + self.assertEqual(ex_total_len, 20) # size of extra records + self.assertEqual(ex_id, 1) # Zip64 extra record + self.assertEqual(ex_len, 16) # 16 bytes of data + self.assertEqual(ex_usize, 1) # uncompressed size + self.assertEqual(ex_csize, 1) # compressed size + self.assertEqual(cd_sig, b"PK\x01\x02") # ensure the central directory header is next + + z = zipfile.ZipFile(io.BytesIO(zipdata)) + zinfos = z.infolist() + self.assertEqual(len(zinfos), 1) + self.assertGreaterEqual(zinfos[0].extract_version, zipfile.ZIP64_VERSION) # requires zip64 to extract + + def test_unseekable_zip_unknown_filesize(self): + """Test that creating a zip with/without seeking will raise a RuntimeError if zip64 was required but not used""" + + def make_zip(fp): + with zipfile.ZipFile(fp, mode="w", allowZip64=True) as zf: + with zf.open("text.txt", mode="w", force_zip64=False) as zi: + zi.write(b"_" * (zipfile.ZIP64_LIMIT + 1)) + + self.assertRaises(RuntimeError, make_zip, io.BytesIO()) + self.assertRaises(RuntimeError, make_zip, Unseekable(io.BytesIO())) + + def test_zip64_required_not_allowed_fail(self): + """Test that trying to add a large file to a zip that doesn't allow zip64 extensions fails on add""" + def make_zip(fp): + with zipfile.ZipFile(fp, mode="w", allowZip64=False) as zf: + # pretend zipfile.ZipInfo.from_file was used to get the name and filesize + info = zipfile.ZipInfo("text.txt") + info.file_size = zipfile.ZIP64_LIMIT + 1 + zf.open(info, mode="w") + + self.assertRaises(zipfile.LargeZipFile, make_zip, io.BytesIO()) + self.assertRaises(zipfile.LargeZipFile, make_zip, Unseekable(io.BytesIO())) + + def test_unseekable_zip_known_filesize(self): + """Test that creating a zip without seeking will use zip64 extensions if the file size is provided up-front""" + + # This test ensures that the zip will use a zip64 data descriptor (same + # as a regular data descriptor except the sizes are 8 bytes instead of + # 4) record to communicate the size of a file if the zip is being + # written to an unseekable stream. + # Because this sort of thing is hard to verify by parsing the data back + # in as a zip, this test looks at the raw bytes created to ensure that + # the correct data has been generated. + # The spec for this can be found at: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + # The relevent sections for this test are: + # - 4.3.7 for local file header + # - 4.3.9 for the data descriptor + # - 4.5.3 for zip64 extra field + + file_size = zipfile.ZIP64_LIMIT + 1 + + def make_zip(fp): + with zipfile.ZipFile(fp, mode="w", allowZip64=True) as zf: + # pretend zipfile.ZipInfo.from_file was used to get the name and filesize + info = zipfile.ZipInfo("text.txt") + info.file_size = file_size + with zf.open(info, mode="w", force_zip64=False) as zi: + zi.write(b"_" * file_size) + return fp + + # check seekable file information + seekable_data = make_zip(io.BytesIO()).getvalue() + ( + header, vers, os, flags, comp, csize, usize, fn_len, + ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize, + cd_sig + ) = struct.unpack("<4sBBHH8xIIHH8shhQQ{}x4s".format(file_size), seekable_data[:62 + file_size]) + + self.assertEqual(header, b"PK\x03\x04") # local file header + self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract + self.assertEqual(os, 0) # compatible with MS-DOS + self.assertEqual(flags, 0) # no flags set + self.assertEqual(comp, 0) # compression method = stored + self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra + self.assertEqual(usize, 0xFFFFFFFF) + self.assertEqual(fn_len, 8) # filename len + self.assertEqual(ex_total_len, 20) # size of extra records + self.assertEqual(ex_id, 1) # Zip64 extra record + self.assertEqual(ex_len, 16) # 16 bytes of data + self.assertEqual(ex_usize, file_size) # uncompressed size + self.assertEqual(ex_csize, file_size) # compressed size + self.assertEqual(cd_sig, b"PK\x01\x02") # ensure the central directory header is next + + # check unseekable file information + unseekable_data = make_zip(Unseekable(io.BytesIO())).fp.getvalue() + ( + header, vers, os, flags, comp, csize, usize, fn_len, + ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize, + dd_header, dd_usize, dd_csize, cd_sig + ) = struct.unpack("<4sBBHH8xIIHH8shhQQ{}x4s4xQQ4s".format(file_size), unseekable_data[:86 + file_size]) + + self.assertEqual(header, b"PK\x03\x04") # local file header + self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract + self.assertEqual(os, 0) # compatible with MS-DOS + self.assertEqual("{:b}".format(flags), "1000") # streaming flag set + self.assertEqual(comp, 0) # compression method = stored + self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra + self.assertEqual(usize, 0xFFFFFFFF) + self.assertEqual(fn_len, 8) # filename len + self.assertEqual(ex_total_len, 20) # size of extra records + self.assertEqual(ex_id, 1) # Zip64 extra record + self.assertEqual(ex_len, 16) # 16 bytes of data + self.assertEqual(ex_usize, 0) # uncompressed size - 0 to defer to data descriptor + self.assertEqual(ex_csize, 0) # compressed size - 0 to defer to data descriptor + self.assertEqual(dd_header, b"PK\07\x08") # data descriptor + self.assertEqual(dd_usize, file_size) # file size (8 bytes because zip64) + self.assertEqual(dd_csize, file_size) # compressed size (8 bytes because zip64) + self.assertEqual(cd_sig, b"PK\x01\x02") # ensure the central directory header is next + @requires_zlib() class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 116b939e55fe..9fc1840ba1e5 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -442,7 +442,12 @@ def __repr__(self): return ''.join(result) def FileHeader(self, zip64=None): - """Return the per-file header as a bytes object.""" + """Return the per-file header as a bytes object. + + When the optional zip64 arg is None rather than a bool, we will + decide based upon the file_size and compress_size, if known, + False otherwise. + """ dt = self.date_time dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2) @@ -458,16 +463,13 @@ def FileHeader(self, zip64=None): min_version = 0 if zip64 is None: + # We always explicitly pass zip64 within this module.... This + # remains for anyone using ZipInfo.FileHeader as a public API. zip64 = file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT if zip64: fmt = '<HHQQ' extra = extra + struct.pack(fmt, 1, struct.calcsize(fmt)-4, file_size, compress_size) - if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT: - if not zip64: - raise LargeZipFile("Filesize would require ZIP64 extensions") - # File is larger than what fits into a 4 byte integer, - # fall back to the ZIP64 extension file_size = 0xffffffff compress_size = 0xffffffff min_version = ZIP64_VERSION @@ -1219,6 +1221,12 @@ def close(self): self._zinfo.CRC = self._crc self._zinfo.file_size = self._file_size + if not self._zip64: + if self._file_size > ZIP64_LIMIT: + raise RuntimeError("File size too large, try using force_zip64") + if self._compress_size > ZIP64_LIMIT: + raise RuntimeError("Compressed size too large, try using force_zip64") + # Write updated header info if self._zinfo.flag_bits & _MASK_USE_DATA_DESCRIPTOR: # Write CRC and file sizes after the file data @@ -1227,13 +1235,6 @@ def close(self): self._zinfo.compress_size, self._zinfo.file_size)) self._zipfile.start_dir = self._fileobj.tell() else: - if not self._zip64: - if self._file_size > ZIP64_LIMIT: - raise RuntimeError( - 'File size too large, try using force_zip64') - if self._compress_size > ZIP64_LIMIT: - raise RuntimeError( - 'Compressed size too large, try using force_zip64') # Seek backwards and write file header (which will now include # correct CRC and file sizes) @@ -1672,8 +1673,9 @@ def _open_to_write(self, zinfo, force_zip64=False): zinfo.external_attr = 0o600 << 16 # permissions: ?rw------- # Compressed size can be larger than uncompressed size - zip64 = self._allowZip64 and \ - (force_zip64 or zinfo.file_size * 1.05 > ZIP64_LIMIT) + zip64 = force_zip64 or (zinfo.file_size * 1.05 > ZIP64_LIMIT) + if not self._allowZip64 and zip64: + raise LargeZipFile("Filesize would require ZIP64 extensions") if self._seekable: self.fp.seek(self.start_dir) diff --git a/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst b/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst new file mode 100644 index 000000000000..cc1c444449fe --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst @@ -0,0 +1,2 @@ +Fix ``zipfile.Zipfile`` creating invalid zip files when ``force_zip64`` was +used to add files to them. Patch by Carey Metcalfe. From webhook-mailer at python.org Tue May 16 04:05:20 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 16 May 2023 08:05:20 -0000 Subject: [Python-checkins] gh-104523: Inline minimal PGO rules (#104524) Message-ID: <mailman.382.1684224321.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9084e1b04f8d35721b535a3acd550b920d50f11a commit: 9084e1b04f8d35721b535a3acd550b920d50f11a branch: main author: Gregory Szorc <gregory.szorc at gmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-16T10:04:58+02:00 summary: gh-104523: Inline minimal PGO rules (#104524) Inline profiling rules where the existing indirection was unneeded. files: M Makefile.pre.in diff --git a/Makefile.pre.in b/Makefile.pre.in index d66574143267..8f43def305f3 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -643,7 +643,7 @@ profile-gen-stamp: profile-clean-stamp exit 1;\ fi @echo "Building with support for profile generation:" - $(MAKE) build_all_generate_profile + $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)" touch $@ # Run task with profile generation build to create profile information. @@ -653,8 +653,9 @@ profile-run-stamp: # enabled. $(MAKE) profile-gen-stamp # Next, run the profile task to generate the profile information. - $(MAKE) run_profile_task - $(MAKE) build_all_merge_profile + @ # FIXME: can't run for a cross build + $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) || true + $(LLVM_PROF_MERGER) # Remove profile generation binary since we are done with it. $(MAKE) clean-retain-profile # This is an expensive target to build and it does not have proper @@ -662,19 +663,6 @@ profile-run-stamp: # to record its completion and avoid re-running it. touch $@ -.PHONY: build_all_generate_profile -build_all_generate_profile: - $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)" - -.PHONY: run_profile_task -run_profile_task: - @ # FIXME: can't run for a cross build - $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) || true - -.PHONY: build_all_merge_profile -build_all_merge_profile: - $(LLVM_PROF_MERGER) - # Compile Python binary with profile guided optimization. # To force re-running of the profile task, remove the profile-run-stamp file. .PHONY: profile-opt From webhook-mailer at python.org Tue May 16 05:15:21 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 16 May 2023 09:15:21 -0000 Subject: [Python-checkins] [3.11] gh-104482: Fix error handling bugs in ast.c (#104514) Message-ID: <mailman.383.1684228523.13550.python-checkins@python.org> https://github.com/python/cpython/commit/52a18feaaa39054e09fa0cf4c6675e7f4d024faf commit: 52a18feaaa39054e09fa0cf4c6675e7f4d024faf branch: 3.11 author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-16T10:14:36+01:00 summary: [3.11] gh-104482: Fix error handling bugs in ast.c (#104514) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst M Lib/test/test_ast.py M Python/ast.c diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 7d9d0c431a66..f7221955e3e0 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1790,6 +1790,12 @@ def test_stdlib_validates(self): kwd_attrs=[], kwd_patterns=[ast.MatchStar()] ), + ast.MatchClass( + constant_true, # invalid name + patterns=[], + kwd_attrs=['True'], + kwd_patterns=[pattern_1] + ), ast.MatchSequence( [ ast.MatchStar("True") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst new file mode 100644 index 000000000000..07c09a3a84a6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst @@ -0,0 +1 @@ +Fix three error handling bugs in ast.c's validation of pattern matching statements. diff --git a/Python/ast.c b/Python/ast.c index a0321b58ba8c..95179cb70281 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -46,6 +46,7 @@ static int validate_pattern(struct validator *, pattern_ty, int); static int validate_name(PyObject *name) { + assert(!PyErr_Occurred()); assert(PyUnicode_Check(name)); static const char * const forbidden[] = { "None", @@ -65,12 +66,12 @@ validate_name(PyObject *name) static int validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) { - Py_ssize_t i; + assert(!PyErr_Occurred()); if (!asdl_seq_LEN(gens)) { PyErr_SetString(PyExc_ValueError, "comprehension with no generators"); return 0; } - for (i = 0; i < asdl_seq_LEN(gens); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(gens); i++) { comprehension_ty comp = asdl_seq_GET(gens, i); if (!validate_expr(state, comp->target, Store) || !validate_expr(state, comp->iter, Load) || @@ -83,8 +84,8 @@ validate_comprehension(struct validator *state, asdl_comprehension_seq *gens) static int validate_keywords(struct validator *state, asdl_keyword_seq *keywords) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(keywords); i++) + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(keywords); i++) if (!validate_expr(state, (asdl_seq_GET(keywords, i))->value, Load)) return 0; return 1; @@ -93,8 +94,8 @@ validate_keywords(struct validator *state, asdl_keyword_seq *keywords) static int validate_args(struct validator *state, asdl_arg_seq *args) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(args); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(args); i++) { arg_ty arg = asdl_seq_GET(args, i); VALIDATE_POSITIONS(arg); if (arg->annotation && !validate_expr(state, arg->annotation, Load)) @@ -121,6 +122,7 @@ expr_context_name(expr_context_ty ctx) static int validate_arguments(struct validator *state, arguments_ty args) { + assert(!PyErr_Occurred()); if (!validate_args(state, args->posonlyargs) || !validate_args(state, args->args)) { return 0; } @@ -149,6 +151,7 @@ validate_arguments(struct validator *state, arguments_ty args) static int validate_constant(struct validator *state, PyObject *value) { + assert(!PyErr_Occurred()); if (value == Py_None || value == Py_Ellipsis) return 1; @@ -205,6 +208,7 @@ validate_constant(struct validator *state, PyObject *value) static int validate_expr(struct validator *state, expr_ty exp, expr_context_ty ctx) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(exp); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { @@ -465,6 +469,7 @@ ensure_literal_complex(expr_ty exp) static int validate_pattern_match_value(struct validator *state, expr_ty exp) { + assert(!PyErr_Occurred()); if (!validate_expr(state, exp, Load)) { return 0; } @@ -518,6 +523,7 @@ validate_pattern_match_value(struct validator *state, expr_ty exp) static int validate_capture(PyObject *name) { + assert(!PyErr_Occurred()); if (_PyUnicode_EqualToASCIIString(name, "_")) { PyErr_Format(PyExc_ValueError, "can't capture name '_' in patterns"); return 0; @@ -528,6 +534,7 @@ validate_capture(PyObject *name) static int validate_pattern(struct validator *state, pattern_ty p, int star_ok) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(p); int ret = -1; if (++state->recursion_depth > state->recursion_limit) { @@ -580,7 +587,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } - + if (ret == 0) { + break; + } ret = validate_patterns(state, p->v.MatchMapping.patterns, /*star_ok=*/0); break; case MatchClass_kind: @@ -611,6 +620,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } + if (ret == 0) { + break; + } for (Py_ssize_t i = 0; i < asdl_seq_LEN(p->v.MatchClass.kwd_attrs); i++) { PyObject *identifier = asdl_seq_GET(p->v.MatchClass.kwd_attrs, i); @@ -619,6 +631,9 @@ validate_pattern(struct validator *state, pattern_ty p, int star_ok) break; } } + if (ret == 0) { + break; + } if (!validate_patterns(state, p->v.MatchClass.patterns, /*star_ok=*/0)) { ret = 0; @@ -685,6 +700,7 @@ _validate_nonempty_seq(asdl_seq *seq, const char *what, const char *owner) static int validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_context_ty ctx) { + assert(!PyErr_Occurred()); return validate_nonempty_seq(targets, "targets", ctx == Del ? "Delete" : "Assign") && validate_exprs(state, targets, ctx, 0); } @@ -692,15 +708,16 @@ validate_assignlist(struct validator *state, asdl_expr_seq *targets, expr_contex static int validate_body(struct validator *state, asdl_stmt_seq *body, const char *owner) { + assert(!PyErr_Occurred()); return validate_nonempty_seq(body, "body", owner) && validate_stmts(state, body); } static int validate_stmt(struct validator *state, stmt_ty stmt) { + assert(!PyErr_Occurred()); VALIDATE_POSITIONS(stmt); int ret = -1; - Py_ssize_t i; if (++state->recursion_depth > state->recursion_limit) { PyErr_SetString(PyExc_RecursionError, "maximum recursion depth exceeded during compilation"); @@ -771,7 +788,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) case With_kind: if (!validate_nonempty_seq(stmt->v.With.items, "items", "With")) return 0; - for (i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.With.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.With.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) @@ -782,7 +799,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) case AsyncWith_kind: if (!validate_nonempty_seq(stmt->v.AsyncWith.items, "items", "AsyncWith")) return 0; - for (i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.AsyncWith.items); i++) { withitem_ty item = asdl_seq_GET(stmt->v.AsyncWith.items, i); if (!validate_expr(state, item->context_expr, Load) || (item->optional_vars && !validate_expr(state, item->optional_vars, Store))) @@ -795,7 +812,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) || !validate_nonempty_seq(stmt->v.Match.cases, "cases", "Match")) { return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Match.cases); i++) { match_case_ty m = asdl_seq_GET(stmt->v.Match.cases, i); if (!validate_pattern(state, m->pattern, /*star_ok=*/0) || (m->guard && !validate_expr(state, m->guard, Load)) @@ -830,7 +847,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) PyErr_SetString(PyExc_ValueError, "Try has orelse but no except handlers"); return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.Try.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.Try.handlers, i); VALIDATE_POSITIONS(handler); if ((handler->v.ExceptHandler.type && @@ -856,7 +873,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) PyErr_SetString(PyExc_ValueError, "TryStar has orelse but no except handlers"); return 0; } - for (i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { + for (Py_ssize_t i = 0; i < asdl_seq_LEN(stmt->v.TryStar.handlers); i++) { excepthandler_ty handler = asdl_seq_GET(stmt->v.TryStar.handlers, i); if ((handler->v.ExceptHandler.type && !validate_expr(state, handler->v.ExceptHandler.type, Load)) || @@ -916,8 +933,8 @@ validate_stmt(struct validator *state, stmt_ty stmt) static int validate_stmts(struct validator *state, asdl_stmt_seq *seq) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(seq); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(seq); i++) { stmt_ty stmt = asdl_seq_GET(seq, i); if (stmt) { if (!validate_stmt(state, stmt)) @@ -935,8 +952,8 @@ validate_stmts(struct validator *state, asdl_stmt_seq *seq) static int validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ctx, int null_ok) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(exprs); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(exprs); i++) { expr_ty expr = asdl_seq_GET(exprs, i); if (expr) { if (!validate_expr(state, expr, ctx)) @@ -955,8 +972,8 @@ validate_exprs(struct validator *state, asdl_expr_seq *exprs, expr_context_ty ct static int validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ok) { - Py_ssize_t i; - for (i = 0; i < asdl_seq_LEN(patterns); i++) { + assert(!PyErr_Occurred()); + for (Py_ssize_t i = 0; i < asdl_seq_LEN(patterns); i++) { pattern_ty pattern = asdl_seq_GET(patterns, i); if (!validate_pattern(state, pattern, star_ok)) { return 0; @@ -972,6 +989,7 @@ validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ int _PyAST_Validate(mod_ty mod) { + assert(!PyErr_Occurred()); int res = -1; struct validator state; PyThreadState *tstate; From webhook-mailer at python.org Tue May 16 06:26:03 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 16 May 2023 10:26:03 -0000 Subject: [Python-checkins] gh-64595: Fix write file logic in Argument Clinic (#104507) Message-ID: <mailman.384.1684232764.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cca90b690679ed62a689b7867e83776b15c8a5e8 commit: cca90b690679ed62a689b7867e83776b15c8a5e8 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-16T12:25:43+02:00 summary: gh-64595: Fix write file logic in Argument Clinic (#104507) Check if any clinic output actually changes any of the output files before deciding if we should touch the source file. files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 4270fb3cc566..13fd66b0406f 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1965,17 +1965,17 @@ def dump(self): return_converters = {} -def write_file(filename, new_contents, force=False): +def file_changed(filename: str, new_contents: str) -> bool: + """Return true if file contents changed (meaning we must update it)""" try: with open(filename, 'r', encoding="utf-8") as fp: old_contents = fp.read() - - if old_contents == new_contents and not force: - # no change: avoid modifying the file modification time - return + return old_contents != new_contents except FileNotFoundError: - pass + return True + +def write_file(filename: str, new_contents: str): # Atomic write using a temporary file and os.replace() filename_new = f"{filename}.new" with open(filename_new, "w", encoding="utf-8") as fp: @@ -2237,11 +2237,12 @@ def parse_file(filename, *, verify=True, output=None): clinic = Clinic(language, verify=verify, filename=filename) src_out, clinic_out = clinic.parse(raw) - # If clinic output changed, force updating the source file as well. - force = bool(clinic_out) - write_file(output, src_out, force=force) - for fn, data in clinic_out: - write_file(fn, data) + changes = [(fn, data) for fn, data in clinic_out if file_changed(fn, data)] + if changes: + # Always (re)write the source file. + write_file(output, src_out) + for fn, data in clinic_out: + write_file(fn, data) def compute_checksum(input, length=None): From webhook-mailer at python.org Tue May 16 07:47:44 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 16 May 2023 11:47:44 -0000 Subject: [Python-checkins] gh-104050: Add basic typing to CConverter in clinic.py (#104538) Message-ID: <mailman.385.1684237664.13550.python-checkins@python.org> https://github.com/python/cpython/commit/505e2954a9bbc843128de818bf2f3cd15e55f146 commit: 505e2954a9bbc843128de818bf2f3cd15e55f146 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-16T11:47:35Z summary: gh-104050: Add basic typing to CConverter in clinic.py (#104538) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 13fd66b0406f..6020935f8304 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2669,15 +2669,15 @@ class CConverter(metaclass=CConverterAutoRegister): # keep in sync with self_converter.__init__! def __init__(self, # Positional args: - name, - py_name, + name: str, + py_name: str, function, default=unspecified, *, # Keyword only args: - c_default=None, - py_default=None, - annotation=unspecified, - unused=False, + c_default: str | None = None, + py_default: str | None = None, + annotation: str | Unspecified = unspecified, + unused: bool = False, **kwargs ): self.name = ensure_legal_c_identifier(name) @@ -2713,10 +2713,10 @@ def __init__(self, def converter_init(self): pass - def is_optional(self): + def is_optional(self) -> bool: return (self.default is not unspecified) - def _render_self(self, parameter, data): + def _render_self(self, parameter: str, data: CRenderData) -> None: self.parameter = parameter name = self.parser_name @@ -2776,7 +2776,7 @@ def _render_non_self(self, parameter, data): if cleanup: data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") - def render(self, parameter, data): + def render(self, parameter: str, data: CRenderData) -> None: """ parameter is a clinic.Parameter instance. data is a CRenderData instance. @@ -2852,7 +2852,7 @@ def declaration(self, *, in_parser=False): declaration.append(';') return "".join(declaration) - def initialize(self): + def initialize(self) -> str: """ The C statements required to set up this variable before parsing. Returns a string containing this code indented at column 0. @@ -2860,7 +2860,7 @@ def initialize(self): """ return "" - def modify(self): + def modify(self) -> str: """ The C statements required to modify this variable after parsing. Returns a string containing this code indented at column 0. @@ -2868,7 +2868,7 @@ def modify(self): """ return "" - def post_parsing(self): + def post_parsing(self) -> str: """ The C statements required to do some operations after the end of parsing but before cleaning up. Return a string containing this code indented at column 0. @@ -2876,7 +2876,7 @@ def post_parsing(self): """ return "" - def cleanup(self): + def cleanup(self) -> str: """ The C statements required to clean up after this variable. Returns a string containing this code indented at column 0. @@ -2929,7 +2929,7 @@ def parse_arg(self, argname, displayname): """.format(argname=argname, paramname=self.parser_name, cast=cast) return None - def set_template_dict(self, template_dict): + def set_template_dict(self, template_dict: dict[str, str]): pass @property From webhook-mailer at python.org Tue May 16 08:02:25 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 16 May 2023 12:02:25 -0000 Subject: [Python-checkins] gh-104050: Don't star-import 'types' in Argument Clinic (#104543) Message-ID: <mailman.386.1684238547.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c22fced96c4d472221071d12e8e88b0a33f6bb4b commit: c22fced96c4d472221071d12e8e88b0a33f6bb4b branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-16T12:02:18Z summary: gh-104050: Don't star-import 'types' in Argument Clinic (#104543) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 6020935f8304..0ef5deb586d6 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -25,10 +25,9 @@ import sys import textwrap import traceback -import types from collections.abc import Callable -from types import * +from types import FunctionType, NoneType from typing import Any, NamedTuple # TODO: @@ -4037,7 +4036,7 @@ def eval_ast_expr(node, globals, *, filename='-'): node = ast.Expression(node) co = compile(node, filename, 'eval') - fn = types.FunctionType(co, globals) + fn = FunctionType(co, globals) return fn() From webhook-mailer at python.org Tue May 16 08:14:09 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 16 May 2023 12:14:09 -0000 Subject: [Python-checkins] gh-104539: Fix indentation error in logging.config.rst (#104545) Message-ID: <mailman.387.1684239250.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0bb61dd5b0ffc248e18f1b33cddd18788f28e60a commit: 0bb61dd5b0ffc248e18f1b33cddd18788f28e60a branch: main author: Jesper Noordsij <45041769+jnoordsij at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-16T13:13:53+01:00 summary: gh-104539: Fix indentation error in logging.config.rst (#104545) Fix indentation error in logging.config.rst files: M Doc/library/logging.config.rst diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 250246b5cd9a..8f0b833f8534 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -111,7 +111,7 @@ in :mod:`logging` itself) and defining handlers which are declared either in they or their ancestors are explicitly named in the logging configuration. - :param encoding: The encoding used to open file when *fname* is filename. + :param encoding: The encoding used to open file when *fname* is filename. .. versionchanged:: 3.4 An instance of a subclass of :class:`~configparser.RawConfigParser` is From webhook-mailer at python.org Tue May 16 08:53:25 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 16 May 2023 12:53:25 -0000 Subject: [Python-checkins] [3.11] gh-104539: Fix indentation error in logging.config.rst (GH-104545) (#104546) Message-ID: <mailman.388.1684241606.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9cac6c414fc03c72f00f7765f8824be0f4c713a3 commit: 9cac6c414fc03c72f00f7765f8824be0f4c713a3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-16T13:53:18+01:00 summary: [3.11] gh-104539: Fix indentation error in logging.config.rst (GH-104545) (#104546) gh-104539: Fix indentation error in logging.config.rst (GH-104545) Fix indentation error in logging.config.rst (cherry picked from commit 0bb61dd5b0ffc248e18f1b33cddd18788f28e60a) Co-authored-by: Jesper Noordsij <45041769+jnoordsij at users.noreply.github.com> files: M Doc/library/logging.config.rst diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst index 93e452962218..45dc975db474 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -111,7 +111,7 @@ in :mod:`logging` itself) and defining handlers which are declared either in they or their ancestors are explicitly named in the logging configuration. - :param encoding: The encoding used to open file when *fname* is filename. + :param encoding: The encoding used to open file when *fname* is filename. .. versionchanged:: 3.4 An instance of a subclass of :class:`~configparser.RawConfigParser` is From webhook-mailer at python.org Tue May 16 10:38:37 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 16 May 2023 14:38:37 -0000 Subject: [Python-checkins] GH-104510: Fix refleaks in `_io` base types (#104516) Message-ID: <mailman.389.1684247919.13550.python-checkins@python.org> https://github.com/python/cpython/commit/442a3e65da2594bedee88a3e81338d86926bde56 commit: 442a3e65da2594bedee88a3e81338d86926bde56 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-16T20:08:17+05:30 summary: GH-104510: Fix refleaks in `_io` base types (#104516) files: M Modules/_io/bufferedio.c M Modules/_io/iobase.c M Modules/_io/textio.c diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 7a0c516411c7..f30d54a5e11b 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2424,13 +2424,6 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, #include "clinic/bufferedio.c.h" #undef clinic_state -static int -bufferediobase_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef bufferediobase_methods[] = { _IO__BUFFEREDIOBASE_DETACH_METHODDEF _IO__BUFFEREDIOBASE_READ_METHODDEF @@ -2444,13 +2437,13 @@ static PyMethodDef bufferediobase_methods[] = { static PyType_Slot bufferediobase_slots[] = { {Py_tp_doc, (void *)bufferediobase_doc}, {Py_tp_methods, bufferediobase_methods}, - {Py_tp_traverse, bufferediobase_traverse}, {0, NULL}, }; +/* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ PyType_Spec bufferediobase_spec = { .name = "_io._BufferedIOBase", - .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE), .slots = bufferediobase_slots, }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 14d48813aefe..bcb498d9c5b5 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -1036,13 +1036,6 @@ rawiobase_write(PyObject *self, PyObject *args) return NULL; } -static int -rawiobase_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} - static PyMethodDef rawiobase_methods[] = { _IO__RAWIOBASE_READ_METHODDEF _IO__RAWIOBASE_READALL_METHODDEF @@ -1054,13 +1047,13 @@ static PyMethodDef rawiobase_methods[] = { static PyType_Slot rawiobase_slots[] = { {Py_tp_doc, (void *)rawiobase_doc}, {Py_tp_methods, rawiobase_methods}, - {Py_tp_traverse, rawiobase_traverse}, {0, NULL}, }; +/* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ PyType_Spec rawiobase_spec = { .name = "_io._RawIOBase", - .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE), .slots = rawiobase_slots, }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index e858a1fb498f..46411c70a967 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -167,12 +167,6 @@ textiobase_errors_get(PyObject *self, void *context) Py_RETURN_NONE; } -static int -textiobase_traverse(PyObject *self, visitproc visit, void *arg) -{ - Py_VISIT(Py_TYPE(self)); - return 0; -} static PyMethodDef textiobase_methods[] = { _IO__TEXTIOBASE_DETACH_METHODDEF @@ -193,13 +187,13 @@ static PyType_Slot textiobase_slots[] = { {Py_tp_doc, (void *)textiobase_doc}, {Py_tp_methods, textiobase_methods}, {Py_tp_getset, textiobase_getset}, - {Py_tp_traverse, textiobase_traverse}, {0, NULL}, }; +/* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ PyType_Spec textiobase_spec = { .name = "_io._TextIOBase", - .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_IMMUTABLETYPE), .slots = textiobase_slots, }; From webhook-mailer at python.org Tue May 16 11:49:22 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 16 May 2023 15:49:22 -0000 Subject: [Python-checkins] CODEOWNERS: Assign new PEP 695 files to myself (#104551) Message-ID: <mailman.390.1684252163.13550.python-checkins@python.org> https://github.com/python/cpython/commit/febcc6ccfb0726dab588e64b68d91abb37db1939 commit: febcc6ccfb0726dab588e64b68d91abb37db1939 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-16T08:48:52-07:00 summary: CODEOWNERS: Assign new PEP 695 files to myself (#104551) files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d40519e40d3c..32ba5355a585 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,6 +22,7 @@ configure* @erlend-aasland @corona10 **/*hamt* @1st1 Objects/set* @rhettinger Objects/dict* @methane @markshannon +Objects/typevarobject.c @JelleZijlstra Objects/type* @markshannon Objects/codeobject.c @markshannon Objects/frameobject.c @markshannon @@ -33,6 +34,7 @@ Python/flowgraph.c @markshannon @iritkatriel Python/ast_opt.c @isidentical Lib/test/test_patma.py @brandtbucher Lib/test/test_peepholer.py @brandtbucher +Lib/test/test_type_*.py @JelleZijlstra # Exceptions Lib/traceback.py @iritkatriel From webhook-mailer at python.org Tue May 16 12:29:08 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 16 May 2023 16:29:08 -0000 Subject: [Python-checkins] gh-103865: add monitoring support to LOAD_SUPER_ATTR (#103866) Message-ID: <mailman.391.1684254549.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f40890b124a330b589c8093127be1274e15dbd7f commit: f40890b124a330b589c8093127be1274e15dbd7f branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-16T10:29:00-06:00 summary: gh-103865: add monitoring support to LOAD_SUPER_ATTR (#103866) files: M Include/internal/pycore_opcode.h M Include/opcode.h M Lib/opcode.py M Lib/test/test_monitoring.py M Python/bytecodes.c M Python/compile.c M Python/generated_cases.c.h M Python/instrumentation.c M Python/opcode_metadata.h M Python/opcode_targets.h diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index c2fa5692dbe4..15d96503830f 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -138,6 +138,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, + [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, [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, @@ -481,7 +482,7 @@ static const char *const _PyOpcode_OpName[267] = { [234] = "<234>", [235] = "<235>", [236] = "<236>", - [237] = "<237>", + [INSTRUMENTED_LOAD_SUPER_ATTR] = "INSTRUMENTED_LOAD_SUPER_ATTR", [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", @@ -577,7 +578,6 @@ static const char *const _PyOpcode_OpName[267] = { case 234: \ case 235: \ case 236: \ - case 237: \ case 255: \ ; diff --git a/Include/opcode.h b/Include/opcode.h index dea7687c39da..9806511ba428 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -120,7 +120,8 @@ extern "C" { #define CALL_INTRINSIC_2 174 #define LOAD_FROM_DICT_OR_GLOBALS 175 #define LOAD_FROM_DICT_OR_DEREF 176 -#define MIN_INSTRUMENTED_OPCODE 238 +#define MIN_INSTRUMENTED_OPCODE 237 +#define INSTRUMENTED_LOAD_SUPER_ATTR 237 #define INSTRUMENTED_POP_JUMP_IF_NONE 238 #define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 239 #define INSTRUMENTED_RESUME 240 diff --git a/Lib/opcode.py b/Lib/opcode.py index 97d0a654a03a..6bb2f1c140b1 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -233,8 +233,9 @@ def pseudo_op(name, op, real_ops): hasfree.append(176) # Instrumented instructions -MIN_INSTRUMENTED_OPCODE = 238 +MIN_INSTRUMENTED_OPCODE = 237 +def_op('INSTRUMENTED_LOAD_SUPER_ATTR', 237) def_op('INSTRUMENTED_POP_JUMP_IF_NONE', 238) def_op('INSTRUMENTED_POP_JUMP_IF_NOT_NONE', 239) def_op('INSTRUMENTED_RESUME', 240) diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 06e54fa2965f..46b817d74f09 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1,9 +1,11 @@ """Test suite for the sys.monitoring.""" import collections +import dis import functools import operator import sys +import textwrap import types import unittest @@ -506,7 +508,7 @@ def test_lines_single(self): 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]) + self.assertEqual(events, [start+7, 16, start+8]) finally: sys.monitoring.set_events(TEST_TOOL, 0) sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) @@ -524,7 +526,7 @@ def test_lines_loop(self): 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, 21, 22, 21, start+8]) + self.assertEqual(events, [start+7, 23, 24, 23, 24, 23, start+8]) finally: sys.monitoring.set_events(TEST_TOOL, 0) sys.monitoring.register_callback(TEST_TOOL, E.LINE, None) @@ -546,7 +548,7 @@ def test_lines_two(self): 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] + expected = [start+10, 16, start+11] self.assertEqual(events, expected) self.assertEqual(events2, expected) finally: @@ -1177,6 +1179,221 @@ def func(): ('return', None), ('line', 'check_events', 11)]) +class TestLoadSuperAttr(CheckEvents): + RECORDERS = CallRecorder, LineRecorder, CRaiseRecorder, CReturnRecorder + + def _exec(self, co): + d = {} + exec(co, d, d) + return d + + def _exec_super(self, codestr, optimized=False): + # The compiler checks for statically visible shadowing of the name + # `super`, and declines to emit `LOAD_SUPER_ATTR` if shadowing is found. + # So inserting `super = super` prevents the compiler from emitting + # `LOAD_SUPER_ATTR`, and allows us to test that monitoring events for + # `LOAD_SUPER_ATTR` are equivalent to those we'd get from the + # un-optimized `LOAD_GLOBAL super; CALL; LOAD_ATTR` form. + assignment = "x = 1" if optimized else "super = super" + codestr = f"{assignment}\n{textwrap.dedent(codestr)}" + co = compile(codestr, "<string>", "exec") + # validate that we really do have a LOAD_SUPER_ATTR, only when optimized + self.assertEqual(self._has_load_super_attr(co), optimized) + return self._exec(co) + + def _has_load_super_attr(self, co): + has = any(instr.opname == "LOAD_SUPER_ATTR" for instr in dis.get_instructions(co)) + if not has: + has = any( + isinstance(c, types.CodeType) and self._has_load_super_attr(c) + for c in co.co_consts + ) + return has + + def _super_method_call(self, optimized=False): + codestr = """ + class A: + def method(self, x): + return x + + class B(A): + def method(self, x): + return super( + ).method( + x + ) + + b = B() + def f(): + return b.method(1) + """ + d = self._exec_super(codestr, optimized) + expected = [ + ('line', 'check_events', 10), + ('call', 'f', sys.monitoring.MISSING), + ('line', 'f', 1), + ('call', 'method', d["b"]), + ('line', 'method', 1), + ('call', 'super', sys.monitoring.MISSING), + ('C return', 'super', sys.monitoring.MISSING), + ('line', 'method', 2), + ('line', 'method', 3), + ('line', 'method', 2), + ('call', 'method', 1), + ('line', 'method', 1), + ('line', 'method', 1), + ('line', 'check_events', 11), + ('call', 'set_events', 2), + ] + return d["f"], expected + + def test_method_call(self): + nonopt_func, nonopt_expected = self._super_method_call(optimized=False) + opt_func, opt_expected = self._super_method_call(optimized=True) + + self.check_events(nonopt_func, recorders=self.RECORDERS, expected=nonopt_expected) + self.check_events(opt_func, recorders=self.RECORDERS, expected=opt_expected) + + def _super_method_call_error(self, optimized=False): + codestr = """ + class A: + def method(self, x): + return x + + class B(A): + def method(self, x): + return super( + x, + self, + ).method( + x + ) + + b = B() + def f(): + try: + return b.method(1) + except TypeError: + pass + else: + assert False, "should have raised TypeError" + """ + d = self._exec_super(codestr, optimized) + expected = [ + ('line', 'check_events', 10), + ('call', 'f', sys.monitoring.MISSING), + ('line', 'f', 1), + ('line', 'f', 2), + ('call', 'method', d["b"]), + ('line', 'method', 1), + ('line', 'method', 2), + ('line', 'method', 3), + ('line', 'method', 1), + ('call', 'super', 1), + ('C raise', 'super', 1), + ('line', 'f', 3), + ('line', 'f', 4), + ('line', 'check_events', 11), + ('call', 'set_events', 2), + ] + return d["f"], expected + + def test_method_call_error(self): + nonopt_func, nonopt_expected = self._super_method_call_error(optimized=False) + opt_func, opt_expected = self._super_method_call_error(optimized=True) + + self.check_events(nonopt_func, recorders=self.RECORDERS, expected=nonopt_expected) + self.check_events(opt_func, recorders=self.RECORDERS, expected=opt_expected) + + def _super_attr(self, optimized=False): + codestr = """ + class A: + x = 1 + + class B(A): + def method(self): + return super( + ).x + + b = B() + def f(): + return b.method() + """ + d = self._exec_super(codestr, optimized) + expected = [ + ('line', 'check_events', 10), + ('call', 'f', sys.monitoring.MISSING), + ('line', 'f', 1), + ('call', 'method', d["b"]), + ('line', 'method', 1), + ('call', 'super', sys.monitoring.MISSING), + ('C return', 'super', sys.monitoring.MISSING), + ('line', 'method', 2), + ('line', 'method', 1), + ('line', 'check_events', 11), + ('call', 'set_events', 2) + ] + return d["f"], expected + + def test_attr(self): + nonopt_func, nonopt_expected = self._super_attr(optimized=False) + opt_func, opt_expected = self._super_attr(optimized=True) + + self.check_events(nonopt_func, recorders=self.RECORDERS, expected=nonopt_expected) + self.check_events(opt_func, recorders=self.RECORDERS, expected=opt_expected) + + def test_vs_other_type_call(self): + code_template = textwrap.dedent(""" + class C: + def method(self): + return {cls}().__repr__{call} + c = C() + def f(): + return c.method() + """) + + def get_expected(name, call_method, ns): + repr_arg = 0 if name == "int" else sys.monitoring.MISSING + return [ + ('line', 'check_events', 10), + ('call', 'f', sys.monitoring.MISSING), + ('line', 'f', 1), + ('call', 'method', ns["c"]), + ('line', 'method', 1), + ('call', name, sys.monitoring.MISSING), + ('C return', name, sys.monitoring.MISSING), + *( + [ + ('call', '__repr__', repr_arg), + ('C return', '__repr__', repr_arg), + ] if call_method else [] + ), + ('line', 'check_events', 11), + ('call', 'set_events', 2), + ] + + for call_method in [True, False]: + with self.subTest(call_method=call_method): + call_str = "()" if call_method else "" + code_super = code_template.format(cls="super", call=call_str) + code_int = code_template.format(cls="int", call=call_str) + co_super = compile(code_super, '<string>', 'exec') + self.assertTrue(self._has_load_super_attr(co_super)) + ns_super = self._exec(co_super) + ns_int = self._exec(code_int) + + self.check_events( + ns_super["f"], + recorders=self.RECORDERS, + expected=get_expected("super", call_method, ns_super) + ) + self.check_events( + ns_int["f"], + recorders=self.RECORDERS, + expected=get_expected("int", call_method, ns_int) + ) + + class TestSetGetEvents(MonitoringTestBase, unittest.TestCase): def test_global(self): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1b8820f94dbc..b38d37a7773b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1582,6 +1582,14 @@ dummy_func( PREDICT(JUMP_BACKWARD); } + inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused if (oparg & 1), unused)) { + _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; + // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we + // don't want to specialize instrumented instructions + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); + } + family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { LOAD_SUPER_ATTR, LOAD_SUPER_ATTR_ATTR, @@ -1602,10 +1610,34 @@ dummy_func( DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ + if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { + PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr-1, global_super, arg); + ERROR_IF(err, error); + } + // we make no attempt to optimize here; specializations should // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); + if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { + PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + if (super == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, global_super, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, global_super, arg); + if (err < 0) { + Py_CLEAR(super); + } + } + } DECREF_INPUTS(); ERROR_IF(super == NULL, error); res = PyObject_GetAttr(super, name); diff --git a/Python/compile.c b/Python/compile.c index 7adbf9208989..60c845a821b6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4846,6 +4846,8 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e) int opcode = asdl_seq_LEN(meth->v.Attribute.value->v.Call.args) ? LOAD_SUPER_METHOD : LOAD_ZERO_SUPER_METHOD; ADDOP_NAME(c, loc, opcode, meth->v.Attribute.attr, names); + loc = update_start_location_to_match_attr(c, loc, meth); + ADDOP(c, loc, NOP); } else { VISIT(c, expr, meth->v.Attribute.value); loc = update_start_location_to_match_attr(c, loc, meth); @@ -6079,6 +6081,8 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) int opcode = asdl_seq_LEN(e->v.Attribute.value->v.Call.args) ? LOAD_SUPER_ATTR : LOAD_ZERO_SUPER_ATTR; ADDOP_NAME(c, loc, opcode, e->v.Attribute.attr, names); + loc = update_start_location_to_match_attr(c, loc, e); + ADDOP(c, loc, NOP); return SUCCESS; } VISIT(c, expr, e->v.Attribute.value); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index fa4ff5ccee78..bd1f2988e2f1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2291,6 +2291,16 @@ DISPATCH(); } + TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { + #line 1586 "Python/bytecodes.c" + _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; + // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we + // don't want to specialize instrumented instructions + INCREMENT_ADAPTIVE_COUNTER(cache->counter); + GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); + #line 2302 "Python/generated_cases.c.h" + } + TARGET(LOAD_SUPER_ATTR) { PREDICTED(LOAD_SUPER_ATTR); static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 1, "incorrect cache size"); @@ -2299,7 +2309,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1592 "Python/bytecodes.c" + #line 1600 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2313,20 +2323,44 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ + if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { + PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr-1, global_super, arg); + if (err) goto pop_3_error; + } + // we make no attempt to optimize here; specializations should // handle any case whose performance we care about PyObject *stack[] = {class, self}; PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); - #line 2321 "Python/generated_cases.c.h" + if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { + PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + if (super == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, global_super, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, global_super, arg); + if (err < 0) { + Py_CLEAR(super); + } + } + } + #line 2355 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1610 "Python/bytecodes.c" + #line 1642 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2330 "Python/generated_cases.c.h" + #line 2364 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2341,20 +2375,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1617 "Python/bytecodes.c" + #line 1649 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2352 "Python/generated_cases.c.h" + #line 2386 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1624 "Python/bytecodes.c" + #line 1656 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2358 "Python/generated_cases.c.h" + #line 2392 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2369,7 +2403,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1628 "Python/bytecodes.c" + #line 1660 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2390,7 +2424,7 @@ res = res2; res2 = NULL; } - #line 2394 "Python/generated_cases.c.h" + #line 2428 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2404,7 +2438,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1665 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2438,9 +2472,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2442 "Python/generated_cases.c.h" + #line 2476 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1699 "Python/bytecodes.c" + #line 1731 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2449,12 +2483,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2453 "Python/generated_cases.c.h" + #line 2487 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1708 "Python/bytecodes.c" + #line 1740 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2458 "Python/generated_cases.c.h" + #line 2492 "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; } @@ -2468,7 +2502,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1713 "Python/bytecodes.c" + #line 1745 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2481,7 +2515,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2485 "Python/generated_cases.c.h" + #line 2519 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2496,7 +2530,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1729 "Python/bytecodes.c" + #line 1761 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2509,7 +2543,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2513 "Python/generated_cases.c.h" + #line 2547 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2524,7 +2558,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1745 "Python/bytecodes.c" + #line 1777 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2551,7 +2585,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2555 "Python/generated_cases.c.h" + #line 2589 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2566,7 +2600,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1775 "Python/bytecodes.c" + #line 1807 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2576,7 +2610,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2580 "Python/generated_cases.c.h" + #line 2614 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2591,7 +2625,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1788 "Python/bytecodes.c" + #line 1820 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2603,7 +2637,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2607 "Python/generated_cases.c.h" + #line 2641 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2617,7 +2651,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 1803 "Python/bytecodes.c" + #line 1835 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2641,7 +2675,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2645 "Python/generated_cases.c.h" + #line 2679 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2649,7 +2683,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 1829 "Python/bytecodes.c" + #line 1861 "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); @@ -2675,7 +2709,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2679 "Python/generated_cases.c.h" + #line 2713 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2683,7 +2717,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 1857 "Python/bytecodes.c" + #line 1889 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2701,7 +2735,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2705 "Python/generated_cases.c.h" + #line 2739 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2712,7 +2746,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 1877 "Python/bytecodes.c" + #line 1909 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2751,7 +2785,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2755 "Python/generated_cases.c.h" + #line 2789 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2762,7 +2796,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 1918 "Python/bytecodes.c" + #line 1950 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2772,7 +2806,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2776 "Python/generated_cases.c.h" + #line 2810 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2784,7 +2818,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1937 "Python/bytecodes.c" + #line 1969 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2797,12 +2831,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2801 "Python/generated_cases.c.h" + #line 2835 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1950 "Python/bytecodes.c" + #line 1982 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2806 "Python/generated_cases.c.h" + #line 2840 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2813,7 +2847,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1954 "Python/bytecodes.c" + #line 1986 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2825,7 +2859,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2829 "Python/generated_cases.c.h" + #line 2863 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2836,7 +2870,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1969 "Python/bytecodes.c" + #line 2001 "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); @@ -2852,7 +2886,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2856 "Python/generated_cases.c.h" + #line 2890 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2863,7 +2897,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1988 "Python/bytecodes.c" + #line 2020 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2876,7 +2910,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; Py_INCREF(res); - #line 2880 "Python/generated_cases.c.h" + #line 2914 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2887,14 +2921,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2003 "Python/bytecodes.c" + #line 2035 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2893 "Python/generated_cases.c.h" + #line 2927 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2005 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2898 "Python/generated_cases.c.h" + #line 2932 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2904,15 +2938,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2009 "Python/bytecodes.c" + #line 2041 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2910 "Python/generated_cases.c.h" + #line 2944 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2011 "Python/bytecodes.c" + #line 2043 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2916 "Python/generated_cases.c.h" + #line 2950 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2923,12 +2957,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2016 "Python/bytecodes.c" + #line 2048 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2929 "Python/generated_cases.c.h" + #line 2963 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2018 "Python/bytecodes.c" + #line 2050 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2936,10 +2970,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2940 "Python/generated_cases.c.h" + #line 2974 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2026 "Python/bytecodes.c" + #line 2058 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2948,7 +2982,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2952 "Python/generated_cases.c.h" + #line 2986 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2958,21 +2992,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2037 "Python/bytecodes.c" + #line 2069 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2965 "Python/generated_cases.c.h" + #line 2999 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2040 "Python/bytecodes.c" + #line 2072 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2972 "Python/generated_cases.c.h" + #line 3006 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2045 "Python/bytecodes.c" + #line 2077 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2976 "Python/generated_cases.c.h" + #line 3010 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2981,15 +3015,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2049 "Python/bytecodes.c" + #line 2081 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2988 "Python/generated_cases.c.h" + #line 3022 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2052 "Python/bytecodes.c" + #line 2084 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2993 "Python/generated_cases.c.h" + #line 3027 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2998,29 +3032,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2056 "Python/bytecodes.c" + #line 2088 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3006 "Python/generated_cases.c.h" + #line 3040 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2062 "Python/bytecodes.c" + #line 2094 "Python/bytecodes.c" JUMPBY(oparg); - #line 3015 "Python/generated_cases.c.h" + #line 3049 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2066 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3024 "Python/generated_cases.c.h" + #line 3058 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3028,7 +3062,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2072 "Python/bytecodes.c" + #line 2104 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -3038,9 +3072,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 3042 "Python/generated_cases.c.h" + #line 3076 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2082 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3048,14 +3082,14 @@ if (err < 0) goto pop_1_error; } } - #line 3052 "Python/generated_cases.c.h" + #line 3086 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2092 "Python/bytecodes.c" + #line 2124 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -3065,9 +3099,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 3069 "Python/generated_cases.c.h" + #line 3103 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2102 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3075,67 +3109,67 @@ if (err < 0) goto pop_1_error; } } - #line 3079 "Python/generated_cases.c.h" + #line 3113 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2112 "Python/bytecodes.c" + #line 2144 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3088 "Python/generated_cases.c.h" + #line 3122 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2114 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 3096 "Python/generated_cases.c.h" + #line 3130 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2122 "Python/bytecodes.c" + #line 2154 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 3109 "Python/generated_cases.c.h" + #line 3143 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2128 "Python/bytecodes.c" + #line 2160 "Python/bytecodes.c" } - #line 3113 "Python/generated_cases.c.h" + #line 3147 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2132 "Python/bytecodes.c" + #line 2164 "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 3126 "Python/generated_cases.c.h" + #line 3160 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2141 "Python/bytecodes.c" + #line 2173 "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 3139 "Python/generated_cases.c.h" + #line 3173 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3146,16 +3180,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2149 "Python/bytecodes.c" + #line 2181 "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 3155 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2154 "Python/bytecodes.c" + #line 2186 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3163,7 +3197,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 3167 "Python/generated_cases.c.h" + #line 3201 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3172,10 +3206,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2164 "Python/bytecodes.c" + #line 2196 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 3179 "Python/generated_cases.c.h" + #line 3213 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3185,10 +3219,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2170 "Python/bytecodes.c" + #line 2202 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 3192 "Python/generated_cases.c.h" + #line 3226 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3199,11 +3233,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2176 "Python/bytecodes.c" + #line 2208 "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 3207 "Python/generated_cases.c.h" + #line 3241 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3212,14 +3246,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2182 "Python/bytecodes.c" + #line 2214 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3219 "Python/generated_cases.c.h" + #line 3253 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2185 "Python/bytecodes.c" + #line 2217 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3223 "Python/generated_cases.c.h" + #line 3257 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3227,7 +3261,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2189 "Python/bytecodes.c" + #line 2221 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3250,11 +3284,11 @@ if (iter == NULL) { goto error; } - #line 3254 "Python/generated_cases.c.h" + #line 3288 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2212 "Python/bytecodes.c" + #line 2244 "Python/bytecodes.c" } - #line 3258 "Python/generated_cases.c.h" + #line 3292 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3265,7 +3299,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2231 "Python/bytecodes.c" + #line 2263 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3296,7 +3330,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3300 "Python/generated_cases.c.h" + #line 3334 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3304,7 +3338,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2264 "Python/bytecodes.c" + #line 2296 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3330,14 +3364,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3334 "Python/generated_cases.c.h" + #line 3368 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2292 "Python/bytecodes.c" + #line 2324 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3357,7 +3391,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3361 "Python/generated_cases.c.h" + #line 3395 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3367,7 +3401,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2314 "Python/bytecodes.c" + #line 2346 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3387,7 +3421,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3391 "Python/generated_cases.c.h" + #line 3425 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3397,7 +3431,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2336 "Python/bytecodes.c" + #line 2368 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3415,7 +3449,7 @@ if (next == NULL) { goto error; } - #line 3419 "Python/generated_cases.c.h" + #line 3453 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3424,7 +3458,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2356 "Python/bytecodes.c" + #line 2388 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3440,14 +3474,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3444 "Python/generated_cases.c.h" + #line 3478 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2374 "Python/bytecodes.c" + #line 2406 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3470,16 +3504,16 @@ Py_DECREF(enter); goto error; } - #line 3474 "Python/generated_cases.c.h" + #line 3508 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2397 "Python/bytecodes.c" + #line 2429 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3483 "Python/generated_cases.c.h" + #line 3517 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3491,7 +3525,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2407 "Python/bytecodes.c" + #line 2439 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3517,16 +3551,16 @@ Py_DECREF(enter); goto error; } - #line 3521 "Python/generated_cases.c.h" + #line 3555 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2433 "Python/bytecodes.c" + #line 2465 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3530 "Python/generated_cases.c.h" + #line 3564 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3538,7 +3572,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2442 "Python/bytecodes.c" + #line 2474 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3559,7 +3593,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3563 "Python/generated_cases.c.h" + #line 3597 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3568,7 +3602,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2465 "Python/bytecodes.c" + #line 2497 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3578,7 +3612,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3582 "Python/generated_cases.c.h" + #line 3616 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3592,7 +3626,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 2477 "Python/bytecodes.c" + #line 2509 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3609,7 +3643,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3613 "Python/generated_cases.c.h" + #line 3647 "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; } @@ -3623,7 +3657,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2496 "Python/bytecodes.c" + #line 2528 "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); @@ -3633,7 +3667,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3637 "Python/generated_cases.c.h" + #line 3671 "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; } @@ -3647,7 +3681,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2508 "Python/bytecodes.c" + #line 2540 "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; @@ -3661,7 +3695,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3665 "Python/generated_cases.c.h" + #line 3699 "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; } @@ -3670,16 +3704,16 @@ } TARGET(KW_NAMES) { - #line 2524 "Python/bytecodes.c" + #line 2556 "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 3678 "Python/generated_cases.c.h" + #line 3712 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2530 "Python/bytecodes.c" + #line 2562 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3692,7 +3726,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3696 "Python/generated_cases.c.h" + #line 3730 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3702,7 +3736,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2575 "Python/bytecodes.c" + #line 2607 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3784,7 +3818,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3788 "Python/generated_cases.c.h" + #line 3822 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3796,7 +3830,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2663 "Python/bytecodes.c" + #line 2695 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3806,7 +3840,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3810 "Python/generated_cases.c.h" + #line 3844 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3815,7 +3849,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2675 "Python/bytecodes.c" + #line 2707 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3841,7 +3875,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3845 "Python/generated_cases.c.h" + #line 3879 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3849,7 +3883,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2703 "Python/bytecodes.c" + #line 2735 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3885,7 +3919,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3889 "Python/generated_cases.c.h" + #line 3923 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3893,7 +3927,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2741 "Python/bytecodes.c" + #line 2773 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3903,7 +3937,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3907 "Python/generated_cases.c.h" + #line 3941 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3916,7 +3950,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2753 "Python/bytecodes.c" + #line 2785 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3927,7 +3961,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3931 "Python/generated_cases.c.h" + #line 3965 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3941,7 +3975,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2767 "Python/bytecodes.c" + #line 2799 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3952,7 +3986,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3956 "Python/generated_cases.c.h" + #line 3990 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3966,7 +4000,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2781 "Python/bytecodes.c" + #line 2813 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3988,7 +4022,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3992 "Python/generated_cases.c.h" + #line 4026 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4002,7 +4036,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2806 "Python/bytecodes.c" + #line 2838 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4030,7 +4064,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4034 "Python/generated_cases.c.h" + #line 4068 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4044,7 +4078,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2837 "Python/bytecodes.c" + #line 2869 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4076,7 +4110,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4080 "Python/generated_cases.c.h" + #line 4114 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4090,7 +4124,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2872 "Python/bytecodes.c" + #line 2904 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4122,7 +4156,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4126 "Python/generated_cases.c.h" + #line 4160 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4136,7 +4170,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2907 "Python/bytecodes.c" + #line 2939 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4161,7 +4195,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4165 "Python/generated_cases.c.h" + #line 4199 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4174,7 +4208,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2934 "Python/bytecodes.c" + #line 2966 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4201,7 +4235,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4205 "Python/generated_cases.c.h" + #line 4239 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4213,7 +4247,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2964 "Python/bytecodes.c" + #line 2996 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4231,14 +4265,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4235 "Python/generated_cases.c.h" + #line 4269 "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 2984 "Python/bytecodes.c" + #line 3016 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4269,7 +4303,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4273 "Python/generated_cases.c.h" + #line 4307 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4282,7 +4316,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3018 "Python/bytecodes.c" + #line 3050 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4311,7 +4345,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4315 "Python/generated_cases.c.h" + #line 4349 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4324,7 +4358,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3050 "Python/bytecodes.c" + #line 3082 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4353,7 +4387,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4357 "Python/generated_cases.c.h" + #line 4391 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4366,7 +4400,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3082 "Python/bytecodes.c" + #line 3114 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4394,7 +4428,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4398 "Python/generated_cases.c.h" + #line 4432 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4404,9 +4438,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3113 "Python/bytecodes.c" + #line 3145 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4410 "Python/generated_cases.c.h" + #line 4444 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4415,7 +4449,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3117 "Python/bytecodes.c" + #line 3149 "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)); @@ -4477,14 +4511,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4481 "Python/generated_cases.c.h" + #line 4515 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3179 "Python/bytecodes.c" + #line 3211 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4488 "Python/generated_cases.c.h" + #line 4522 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4499,7 +4533,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 3189 "Python/bytecodes.c" + #line 3221 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4528,14 +4562,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4532 "Python/generated_cases.c.h" + #line 4566 "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 3220 "Python/bytecodes.c" + #line 3252 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4556,7 +4590,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4560 "Python/generated_cases.c.h" + #line 4594 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4564,15 +4598,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3243 "Python/bytecodes.c" + #line 3275 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4570 "Python/generated_cases.c.h" + #line 4604 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3245 "Python/bytecodes.c" + #line 3277 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4576 "Python/generated_cases.c.h" + #line 4610 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4583,7 +4617,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 3249 "Python/bytecodes.c" + #line 3281 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4618,7 +4652,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 4622 "Python/generated_cases.c.h" + #line 4656 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4627,10 +4661,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3286 "Python/bytecodes.c" + #line 3318 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4634 "Python/generated_cases.c.h" + #line 4668 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4642,7 +4676,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3291 "Python/bytecodes.c" + #line 3323 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4657,12 +4691,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4661 "Python/generated_cases.c.h" + #line 4695 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3306 "Python/bytecodes.c" + #line 3338 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4666 "Python/generated_cases.c.h" + #line 4700 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4672,16 +4706,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3311 "Python/bytecodes.c" + #line 3343 "Python/bytecodes.c" assert(oparg >= 2); - #line 4678 "Python/generated_cases.c.h" + #line 4712 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3315 "Python/bytecodes.c" + #line 3347 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4693,26 +4727,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4697 "Python/generated_cases.c.h" + #line 4731 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3329 "Python/bytecodes.c" + #line 3361 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4703 "Python/generated_cases.c.h" + #line 4737 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3333 "Python/bytecodes.c" + #line 3365 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4710 "Python/generated_cases.c.h" + #line 4744 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3338 "Python/bytecodes.c" + #line 3370 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4721,12 +4755,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4725 "Python/generated_cases.c.h" + #line 4759 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3349 "Python/bytecodes.c" + #line 3381 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4735,12 +4769,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4739 "Python/generated_cases.c.h" + #line 4773 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3360 "Python/bytecodes.c" + #line 3392 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4753,12 +4787,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4757 "Python/generated_cases.c.h" + #line 4791 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3375 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4771,30 +4805,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4775 "Python/generated_cases.c.h" + #line 4809 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3390 "Python/bytecodes.c" + #line 3422 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4786 "Python/generated_cases.c.h" + #line 4820 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3398 "Python/bytecodes.c" + #line 3430 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4793 "Python/generated_cases.c.h" + #line 4827 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3403 "Python/bytecodes.c" + #line 3435 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4800 "Python/generated_cases.c.h" + #line 4834 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 9152744d7c2c..c70668e8295a 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -35,6 +35,8 @@ static const int8_t EVENT_FOR_OPCODE[256] = { [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL, [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, + [LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, + [INSTRUMENTED_LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, [RESUME] = -1, [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, @@ -74,6 +76,7 @@ static const uint8_t DE_INSTRUMENT[256] = { [INSTRUMENTED_FOR_ITER] = FOR_ITER, [INSTRUMENTED_END_FOR] = END_FOR, [INSTRUMENTED_END_SEND] = END_SEND, + [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, }; static const uint8_t INSTRUMENTED_OPCODES[256] = { @@ -107,6 +110,8 @@ static const uint8_t INSTRUMENTED_OPCODES[256] = { [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, [FOR_ITER] = INSTRUMENTED_FOR_ITER, [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, + [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, + [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 601ad3874b79..53fbaa3e317e 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -211,6 +211,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case MAP_ADD: return 2; + case INSTRUMENTED_LOAD_SUPER_ATTR: + return 3; case LOAD_SUPER_ATTR: return 3; case LOAD_SUPER_ATTR_ATTR: @@ -605,6 +607,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case MAP_ADD: return 0; + case INSTRUMENTED_LOAD_SUPER_ATTR: + return ((oparg & 1) ? 1 : 0) + 1; case LOAD_SUPER_ATTR: return ((oparg & 1) ? 1 : 0) + 1; case LOAD_SUPER_ATTR_ATTR: @@ -902,6 +906,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [DICT_UPDATE] = { true, INSTR_FMT_IB }, [DICT_MERGE] = { true, INSTR_FMT_IB }, [MAP_ADD] = { true, INSTR_FMT_IB }, + [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 }, [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC }, [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC }, [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index af05a33058f3..3add06362711 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -236,7 +236,7 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE, &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE, &&TARGET_INSTRUMENTED_RESUME, From webhook-mailer at python.org Tue May 16 12:38:23 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 16 May 2023 16:38:23 -0000 Subject: [Python-checkins] gh-104555: Fix isinstance() and issubclass() for runtime-checkable protocols that use PEP 695 (#104556) Message-ID: <mailman.392.1684255103.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1163782868454287ca9ac170aaebca4beeb83192 commit: 1163782868454287ca9ac170aaebca4beeb83192 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-16T16:38:10Z summary: gh-104555: Fix isinstance() and issubclass() for runtime-checkable protocols that use PEP 695 (#104556) Fixes #104555 files: 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 71aff87dcaa3..0cd67c51e508 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3134,6 +3134,24 @@ def bar(self, x: str) -> str: self.assertIsInstance(Test(), PSub) + def test_pep695_generic_protocol_callable_members(self): + @runtime_checkable + class Foo[T](Protocol): + def meth(self, x: T) -> None: ... + + class Bar[T]: + def meth(self, x: T) -> None: ... + + self.assertIsInstance(Bar(), Foo) + self.assertIsSubclass(Bar, Foo) + + @runtime_checkable + class SupportsTrunc[T](Protocol): + def __trunc__(self) -> T: ... + + self.assertIsInstance(0.0, SupportsTrunc) + self.assertIsSubclass(float, SupportsTrunc) + def test_init_called(self): T = TypeVar('T') diff --git a/Lib/typing.py b/Lib/typing.py index 8d132e2cbf87..50a8f5159458 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1663,7 +1663,7 @@ class _TypingEllipsis: _TYPING_INTERNALS = frozenset({ '__parameters__', '__orig_bases__', '__orig_class__', '_is_protocol', '_is_runtime_protocol', '__protocol_attrs__', - '__callable_proto_members_only__', + '__callable_proto_members_only__', '__type_params__', }) _SPECIAL_NAMES = frozenset({ From webhook-mailer at python.org Tue May 16 13:18:36 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 16 May 2023 17:18:36 -0000 Subject: [Python-checkins] gh-104050: Add more annotations to `Tools/clinic.py` (#104544) Message-ID: <mailman.393.1684257517.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a454a6651ba26ed623377dd01ed62a0a22afa8c7 commit: a454a6651ba26ed623377dd01ed62a0a22afa8c7 branch: main author: Nikita Sobolev <mail at sobolevn.me> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-16T17:18:28Z summary: gh-104050: Add more annotations to `Tools/clinic.py` (#104544) files: M Tools/clinic/clinic.py M Tools/clinic/cpp.py M Tools/clinic/mypy.ini diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 0ef5deb586d6..dfe43c80ef32 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -28,7 +28,7 @@ from collections.abc import Callable from types import FunctionType, NoneType -from typing import Any, NamedTuple +from typing import Any, NamedTuple, NoReturn, Literal, overload # TODO: # @@ -59,21 +59,21 @@ } class Unspecified: - def __repr__(self): + def __repr__(self) -> str: return '<Unspecified>' unspecified = Unspecified() class Null: - def __repr__(self): + def __repr__(self) -> str: return '<Null>' NULL = Null() class Unknown: - def __repr__(self): + def __repr__(self) -> str: return '<Unknown>' unknown = Unknown() @@ -81,15 +81,15 @@ def __repr__(self): sig_end_marker = '--' Appender = Callable[[str], None] -Outputter = Callable[[None], str] +Outputter = Callable[[], str] class _TextAccumulator(NamedTuple): text: list[str] append: Appender output: Outputter -def _text_accumulator(): - text = [] +def _text_accumulator() -> _TextAccumulator: + text: list[str] = [] def output(): s = ''.join(text) text.clear() @@ -98,10 +98,10 @@ def output(): class TextAccumulator(NamedTuple): - text: list[str] append: Appender + output: Outputter -def text_accumulator(): +def text_accumulator() -> TextAccumulator: """ Creates a simple text accumulator / joiner. @@ -115,8 +115,28 @@ def text_accumulator(): text, append, output = _text_accumulator() return TextAccumulator(append, output) - -def warn_or_fail(fail=False, *args, filename=None, line_number=None): + at overload +def warn_or_fail( + *args: object, + fail: Literal[True], + filename: str | None = None, + line_number: int | None = None, +) -> NoReturn: ... + + at overload +def warn_or_fail( + *args: object, + fail: Literal[False] = False, + filename: str | None = None, + line_number: int | None = None, +) -> None: ... + +def warn_or_fail( + *args: object, + fail: bool = False, + filename: str | None = None, + line_number: int | None = None, +) -> None: joined = " ".join([str(a) for a in args]) add, output = text_accumulator() if fail: @@ -139,14 +159,22 @@ def warn_or_fail(fail=False, *args, filename=None, line_number=None): sys.exit(-1) -def warn(*args, filename=None, line_number=None): - return warn_or_fail(False, *args, filename=filename, line_number=line_number) +def warn( + *args: object, + filename: str | None = None, + line_number: int | None = None, +) -> None: + return warn_or_fail(*args, filename=filename, line_number=line_number, fail=False) -def fail(*args, filename=None, line_number=None): - return warn_or_fail(True, *args, filename=filename, line_number=line_number) +def fail( + *args: object, + filename: str | None = None, + line_number: int | None = None, +) -> NoReturn: + warn_or_fail(*args, filename=filename, line_number=line_number, fail=True) -def quoted_for_c_string(s): +def quoted_for_c_string(s: str) -> str: for old, new in ( ('\\', '\\\\'), # must be first! ('"', '\\"'), @@ -155,13 +183,13 @@ def quoted_for_c_string(s): s = s.replace(old, new) return s -def c_repr(s): +def c_repr(s: str) -> str: return '"' + s + '"' is_legal_c_identifier = re.compile('^[A-Za-z_][A-Za-z0-9_]*$').match -def is_legal_py_identifier(s): +def is_legal_py_identifier(s: str) -> bool: return all(is_legal_c_identifier(field) for field in s.split('.')) # identifiers that are okay in Python but aren't a good idea in C. @@ -174,7 +202,7 @@ def is_legal_py_identifier(s): typedef typeof union unsigned void volatile while """.strip().split()) -def ensure_legal_c_identifier(s): +def ensure_legal_c_identifier(s: str) -> str: # for now, just complain if what we're given isn't legal if not is_legal_c_identifier(s): fail("Illegal C identifier: {}".format(s)) @@ -183,7 +211,7 @@ def ensure_legal_c_identifier(s): return s + "_value" return s -def rstrip_lines(s): +def rstrip_lines(s: str) -> str: text, add, output = _text_accumulator() for line in s.split('\n'): add(line.rstrip()) @@ -191,14 +219,14 @@ def rstrip_lines(s): text.pop() return output() -def format_escape(s): +def format_escape(s: str) -> str: # double up curly-braces, this string will be used # as part of a format_map() template later s = s.replace('{', '{{') s = s.replace('}', '}}') return s -def linear_format(s, **kwargs): +def linear_format(s: str, **kwargs: str) -> str: """ Perform str.format-like substitution, except: * The strings substituted must be on lines by @@ -242,7 +270,7 @@ def linear_format(s, **kwargs): return output()[:-1] -def indent_all_lines(s, prefix): +def indent_all_lines(s: str, prefix: str) -> str: """ Returns 's', with 'prefix' prepended to all lines. @@ -263,7 +291,7 @@ def indent_all_lines(s, prefix): final.append(last) return ''.join(final) -def suffix_all_lines(s, suffix): +def suffix_all_lines(s: str, suffix: str) -> str: """ Returns 's', with 'suffix' appended to all lines. @@ -283,7 +311,7 @@ def suffix_all_lines(s, suffix): return ''.join(final) -def version_splitter(s): +def version_splitter(s: str) -> tuple[int, ...]: """Splits a version string into a tuple of integers. The following ASCII characters are allowed, and employ @@ -294,7 +322,7 @@ def version_splitter(s): (This permits Python-style version strings such as "1.4b3".) """ version = [] - accumulator = [] + accumulator: list[str] = [] def flush(): if not accumulator: raise ValueError('Unsupported version string: ' + repr(s)) @@ -314,7 +342,7 @@ def flush(): flush() return tuple(version) -def version_comparitor(version1, version2): +def version_comparitor(version1: str, version2: str) -> Literal[-1, 0, 1]: iterator = itertools.zip_longest(version_splitter(version1), version_splitter(version2), fillvalue=0) for i, (a, b) in enumerate(iterator): if a < b: diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index bc2cc713aac3..a3546f570c5a 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,6 +1,7 @@ import re import sys from collections.abc import Callable +from typing import NoReturn TokenAndCondition = tuple[str, str] @@ -30,7 +31,7 @@ class Monitor: is_a_simple_defined: Callable[[str], re.Match[str] | None] is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match - def __init__(self, filename=None, *, verbose: bool = False): + def __init__(self, filename: str | None = None, *, verbose: bool = False) -> None: self.stack: TokenStack = [] self.in_comment = False self.continuation: str | None = None @@ -55,7 +56,7 @@ def condition(self) -> str: """ return " && ".join(condition for token, condition in self.stack) - def fail(self, *a): + def fail(self, *a: object) -> NoReturn: if self.filename: filename = " " + self.filename else: @@ -64,7 +65,7 @@ def fail(self, *a): print(" ", ' '.join(str(x) for x in a)) sys.exit(-1) - def close(self): + def close(self) -> None: if self.stack: self.fail("Ended file while still in a preprocessor conditional block!") diff --git a/Tools/clinic/mypy.ini b/Tools/clinic/mypy.ini index 3c5643e789be..672911dc19ab 100644 --- a/Tools/clinic/mypy.ini +++ b/Tools/clinic/mypy.ini @@ -8,4 +8,5 @@ strict_concatenate = True warn_redundant_casts = True warn_unused_ignores = True warn_unused_configs = True +warn_unreachable = True files = Tools/clinic/ From webhook-mailer at python.org Tue May 16 13:34:51 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 16 May 2023 17:34:51 -0000 Subject: [Python-checkins] gh-75367: Fix data descriptor detection in inspect.getattr_static (#104517) Message-ID: <mailman.394.1684258492.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5e9f471e7db30893fb3f42681f17fdcdb70069ee commit: 5e9f471e7db30893fb3f42681f17fdcdb70069ee branch: main author: Furkan Onder <furkanonder at protonmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-16T17:34:44Z summary: gh-75367: Fix data descriptor detection in inspect.getattr_static (#104517) Co-authored-by: Carl Meyer <carl at oddbird.net> files: A Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index a64e85e4fd67..63f5aa91d270 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1835,8 +1835,10 @@ def getattr_static(obj, attr, default=_sentinel): klass_result = _check_class(klass, attr) if instance_result is not _sentinel and klass_result is not _sentinel: - if (_check_class(type(klass_result), '__get__') is not _sentinel and - _check_class(type(klass_result), '__set__') is not _sentinel): + if _check_class(type(klass_result), "__get__") is not _sentinel and ( + _check_class(type(klass_result), "__set__") is not _sentinel + or _check_class(type(klass_result), "__delete__") is not _sentinel + ): return klass_result if instance_result is not _sentinel: diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 364f75db908b..0590e49d0e1a 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2052,6 +2052,9 @@ class Foo(object): descriptor.__set__ = lambda s, i, v: None self.assertEqual(inspect.getattr_static(foo, 'd'), Foo.__dict__['d']) + del descriptor.__set__ + descriptor.__delete__ = lambda s, i, o: None + self.assertEqual(inspect.getattr_static(foo, 'd'), Foo.__dict__['d']) def test_metaclass_with_descriptor(self): class descriptor(object): diff --git a/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst b/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst new file mode 100644 index 000000000000..554c425e6a78 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst @@ -0,0 +1 @@ +Fix data descriptor detection in :func:`inspect.getattr_static`. From webhook-mailer at python.org Tue May 16 13:57:41 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 16 May 2023 17:57:41 -0000 Subject: [Python-checkins] [3.11] gh-75367: Fix data descriptor detection in inspect.getattr_static (GH-104517) (#104557) Message-ID: <mailman.395.1684259862.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f748fc9f44519336cb33539d01be4e5377eabb92 commit: f748fc9f44519336cb33539d01be4e5377eabb92 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-16T17:57:34Z summary: [3.11] gh-75367: Fix data descriptor detection in inspect.getattr_static (GH-104517) (#104557) gh-75367: Fix data descriptor detection in inspect.getattr_static (GH-104517) (cherry picked from commit 5e9f471e7db30893fb3f42681f17fdcdb70069ee) Co-authored-by: Furkan Onder <furkanonder at protonmail.com> Co-authored-by: Carl Meyer <carl at oddbird.net> files: A Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 75d33f2ce7e7..14569a510a05 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1829,8 +1829,10 @@ def getattr_static(obj, attr, default=_sentinel): klass_result = _check_class(klass, attr) if instance_result is not _sentinel and klass_result is not _sentinel: - if (_check_class(type(klass_result), '__get__') is not _sentinel and - _check_class(type(klass_result), '__set__') is not _sentinel): + if _check_class(type(klass_result), "__get__") is not _sentinel and ( + _check_class(type(klass_result), "__set__") is not _sentinel + or _check_class(type(klass_result), "__delete__") is not _sentinel + ): return klass_result if instance_result is not _sentinel: diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index c44eed027e94..2783f7f8a08e 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1993,6 +1993,9 @@ class Foo(object): descriptor.__set__ = lambda s, i, v: None self.assertEqual(inspect.getattr_static(foo, 'd'), Foo.__dict__['d']) + del descriptor.__set__ + descriptor.__delete__ = lambda s, i, o: None + self.assertEqual(inspect.getattr_static(foo, 'd'), Foo.__dict__['d']) def test_metaclass_with_descriptor(self): class descriptor(object): diff --git a/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst b/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst new file mode 100644 index 000000000000..554c425e6a78 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst @@ -0,0 +1 @@ +Fix data descriptor detection in :func:`inspect.getattr_static`. From webhook-mailer at python.org Tue May 16 16:03:10 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 16 May 2023 20:03:10 -0000 Subject: [Python-checkins] GH-103092: isolate `pyexpat` (#104506) Message-ID: <mailman.396.1684267391.13550.python-checkins@python.org> https://github.com/python/cpython/commit/20e994c535fea33b827e69323f80fec056a76250 commit: 20e994c535fea33b827e69323f80fec056a76250 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-16T20:03:01Z summary: GH-103092: isolate `pyexpat` (#104506) files: M Modules/pyexpat.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index c0fbd4d39f00..92f594ab63ea 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1076,13 +1076,31 @@ static struct PyMethodDef xmlparse_methods[] = { Make it as simple as possible. */ +static const unsigned char template_buffer[256] = + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, + 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, + 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255}; + + static int PyUnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info) { - static unsigned char template_buffer[256] = {0}; - PyObject* u; + PyObject *u; int i; const void *data; int kind; @@ -1090,12 +1108,7 @@ PyUnknownEncodingHandler(void *encodingHandlerData, if (PyErr_Occurred()) return XML_STATUS_ERROR; - if (template_buffer[1] == 0) { - for (i = 0; i < 256; i++) - template_buffer[i] = i; - } - - u = PyUnicode_Decode((char*) template_buffer, 256, name, "replace"); + u = PyUnicode_Decode((const char*) template_buffer, 256, name, "replace"); if (u == NULL || PyUnicode_READY(u)) { Py_XDECREF(u); return XML_STATUS_ERROR; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 9863acdade30..e2b93a3a2ec2 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -458,7 +458,6 @@ Modules/_tkinter.c - trbInCmd - ## pre-allocated buffer Modules/nismodule.c nisproc_maplist_2 res - -Modules/pyexpat.c PyUnknownEncodingHandler template_buffer - ## other Include/datetime.h - PyDateTimeAPI - From webhook-mailer at python.org Tue May 16 16:24:02 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 16 May 2023 20:24:02 -0000 Subject: [Python-checkins] gh-87474: Fix file descriptor leaks in subprocess.Popen (#96351) Message-ID: <mailman.397.1684268643.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3a4c44bb1e92802db64deec59cf8a68ad3973219 commit: 3a4c44bb1e92802db64deec59cf8a68ad3973219 branch: main author: cptpcrd <31829097+cptpcrd at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-16T20:23:53Z summary: gh-87474: Fix file descriptor leaks in subprocess.Popen (#96351) This fixes several ways file descriptors could be leaked from `subprocess.Popen` constructor during error conditions by opening them later and using a context manager "fds to close" registration scheme to ensure they get closed before returning. --------- Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst M Lib/subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 1f203bd00d35..fbc76b8d0f14 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -872,37 +872,6 @@ def __init__(self, args, bufsize=-1, executable=None, 'and universal_newlines are supplied but ' 'different. Pass one or the other.') - # Input and output objects. The general principle is like - # this: - # - # Parent Child - # ------ ----- - # p2cwrite ---stdin---> p2cread - # c2pread <--stdout--- c2pwrite - # errread <--stderr--- errwrite - # - # On POSIX, the child objects are file descriptors. On - # Windows, these are Windows file handles. The parent objects - # are file descriptors on both platforms. The parent objects - # are -1 when not using PIPEs. The child objects are -1 - # when not redirecting. - - (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) = self._get_handles(stdin, stdout, stderr) - - # We wrap OS handles *before* launching the child, otherwise a - # quickly terminating child could make our fds unwrappable - # (see #8458). - - if _mswindows: - if p2cwrite != -1: - p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) - if c2pread != -1: - c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) - if errread != -1: - errread = msvcrt.open_osfhandle(errread.Detach(), 0) - self.text_mode = encoding or errors or text or universal_newlines if self.text_mode and encoding is None: self.encoding = encoding = _text_encoding() @@ -1003,6 +972,39 @@ def __init__(self, args, bufsize=-1, executable=None, if uid < 0: raise ValueError(f"User ID cannot be negative, got {uid}") + # Input and output objects. The general principle is like + # this: + # + # Parent Child + # ------ ----- + # p2cwrite ---stdin---> p2cread + # c2pread <--stdout--- c2pwrite + # errread <--stderr--- errwrite + # + # On POSIX, the child objects are file descriptors. On + # Windows, these are Windows file handles. The parent objects + # are file descriptors on both platforms. The parent objects + # are -1 when not using PIPEs. The child objects are -1 + # when not redirecting. + + (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) = self._get_handles(stdin, stdout, stderr) + + # From here on, raising exceptions may cause file descriptor leakage + + # We wrap OS handles *before* launching the child, otherwise a + # quickly terminating child could make our fds unwrappable + # (see #8458). + + if _mswindows: + if p2cwrite != -1: + p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) + if c2pread != -1: + c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) + if errread != -1: + errread = msvcrt.open_osfhandle(errread.Detach(), 0) + try: if p2cwrite != -1: self.stdin = io.open(p2cwrite, 'wb', bufsize) @@ -1306,6 +1308,26 @@ def _close_pipe_fds(self, # Prevent a double close of these handles/fds from __init__ on error. self._closed_child_pipe_fds = True + @contextlib.contextmanager + def _on_error_fd_closer(self): + """Helper to ensure file descriptors opened in _get_handles are closed""" + to_close = [] + try: + yield to_close + except: + if hasattr(self, '_devnull'): + to_close.append(self._devnull) + del self._devnull + for fd in to_close: + try: + if _mswindows and isinstance(fd, Handle): + fd.Close() + else: + os.close(fd) + except OSError: + pass + raise + if _mswindows: # # Windows methods @@ -1321,61 +1343,68 @@ def _get_handles(self, stdin, stdout, stderr): c2pread, c2pwrite = -1, -1 errread, errwrite = -1, -1 - if stdin is None: - p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE) - if p2cread is None: - p2cread, _ = _winapi.CreatePipe(None, 0) - p2cread = Handle(p2cread) - _winapi.CloseHandle(_) - elif stdin == PIPE: - p2cread, p2cwrite = _winapi.CreatePipe(None, 0) - p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite) - elif stdin == DEVNULL: - p2cread = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stdin, int): - p2cread = msvcrt.get_osfhandle(stdin) - else: - # Assuming file-like object - p2cread = msvcrt.get_osfhandle(stdin.fileno()) - p2cread = self._make_inheritable(p2cread) - - if stdout is None: - c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE) - if c2pwrite is None: - _, c2pwrite = _winapi.CreatePipe(None, 0) - c2pwrite = Handle(c2pwrite) - _winapi.CloseHandle(_) - elif stdout == PIPE: - c2pread, c2pwrite = _winapi.CreatePipe(None, 0) - c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite) - elif stdout == DEVNULL: - c2pwrite = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stdout, int): - c2pwrite = msvcrt.get_osfhandle(stdout) - else: - # Assuming file-like object - c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) - c2pwrite = self._make_inheritable(c2pwrite) - - if stderr is None: - errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE) - if errwrite is None: - _, errwrite = _winapi.CreatePipe(None, 0) - errwrite = Handle(errwrite) - _winapi.CloseHandle(_) - elif stderr == PIPE: - errread, errwrite = _winapi.CreatePipe(None, 0) - errread, errwrite = Handle(errread), Handle(errwrite) - elif stderr == STDOUT: - errwrite = c2pwrite - elif stderr == DEVNULL: - errwrite = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stderr, int): - errwrite = msvcrt.get_osfhandle(stderr) - else: - # Assuming file-like object - errwrite = msvcrt.get_osfhandle(stderr.fileno()) - errwrite = self._make_inheritable(errwrite) + with self._on_error_fd_closer() as err_close_fds: + if stdin is None: + p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE) + if p2cread is None: + p2cread, _ = _winapi.CreatePipe(None, 0) + p2cread = Handle(p2cread) + err_close_fds.append(p2cread) + _winapi.CloseHandle(_) + elif stdin == PIPE: + p2cread, p2cwrite = _winapi.CreatePipe(None, 0) + p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite) + err_close_fds.extend((p2cread, p2cwrite)) + elif stdin == DEVNULL: + p2cread = msvcrt.get_osfhandle(self._get_devnull()) + elif isinstance(stdin, int): + p2cread = msvcrt.get_osfhandle(stdin) + else: + # Assuming file-like object + p2cread = msvcrt.get_osfhandle(stdin.fileno()) + p2cread = self._make_inheritable(p2cread) + + if stdout is None: + c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE) + if c2pwrite is None: + _, c2pwrite = _winapi.CreatePipe(None, 0) + c2pwrite = Handle(c2pwrite) + err_close_fds.append(c2pwrite) + _winapi.CloseHandle(_) + elif stdout == PIPE: + c2pread, c2pwrite = _winapi.CreatePipe(None, 0) + c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite) + err_close_fds.extend((c2pread, c2pwrite)) + elif stdout == DEVNULL: + c2pwrite = msvcrt.get_osfhandle(self._get_devnull()) + elif isinstance(stdout, int): + c2pwrite = msvcrt.get_osfhandle(stdout) + else: + # Assuming file-like object + c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) + c2pwrite = self._make_inheritable(c2pwrite) + + if stderr is None: + errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE) + if errwrite is None: + _, errwrite = _winapi.CreatePipe(None, 0) + errwrite = Handle(errwrite) + err_close_fds.append(errwrite) + _winapi.CloseHandle(_) + elif stderr == PIPE: + errread, errwrite = _winapi.CreatePipe(None, 0) + errread, errwrite = Handle(errread), Handle(errwrite) + err_close_fds.extend((errread, errwrite)) + elif stderr == STDOUT: + errwrite = c2pwrite + elif stderr == DEVNULL: + errwrite = msvcrt.get_osfhandle(self._get_devnull()) + elif isinstance(stderr, int): + errwrite = msvcrt.get_osfhandle(stderr) + else: + # Assuming file-like object + errwrite = msvcrt.get_osfhandle(stderr.fileno()) + errwrite = self._make_inheritable(errwrite) return (p2cread, p2cwrite, c2pread, c2pwrite, @@ -1662,52 +1691,56 @@ def _get_handles(self, stdin, stdout, stderr): c2pread, c2pwrite = -1, -1 errread, errwrite = -1, -1 - if stdin is None: - pass - elif stdin == PIPE: - p2cread, p2cwrite = os.pipe() - if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): - fcntl.fcntl(p2cwrite, fcntl.F_SETPIPE_SZ, self.pipesize) - elif stdin == DEVNULL: - p2cread = self._get_devnull() - elif isinstance(stdin, int): - p2cread = stdin - else: - # Assuming file-like object - p2cread = stdin.fileno() + with self._on_error_fd_closer() as err_close_fds: + if stdin is None: + pass + elif stdin == PIPE: + p2cread, p2cwrite = os.pipe() + err_close_fds.extend((p2cread, p2cwrite)) + if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): + fcntl.fcntl(p2cwrite, fcntl.F_SETPIPE_SZ, self.pipesize) + elif stdin == DEVNULL: + p2cread = self._get_devnull() + elif isinstance(stdin, int): + p2cread = stdin + else: + # Assuming file-like object + p2cread = stdin.fileno() - if stdout is None: - pass - elif stdout == PIPE: - c2pread, c2pwrite = os.pipe() - if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): - fcntl.fcntl(c2pwrite, fcntl.F_SETPIPE_SZ, self.pipesize) - elif stdout == DEVNULL: - c2pwrite = self._get_devnull() - elif isinstance(stdout, int): - c2pwrite = stdout - else: - # Assuming file-like object - c2pwrite = stdout.fileno() + if stdout is None: + pass + elif stdout == PIPE: + c2pread, c2pwrite = os.pipe() + err_close_fds.extend((c2pread, c2pwrite)) + if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): + fcntl.fcntl(c2pwrite, fcntl.F_SETPIPE_SZ, self.pipesize) + elif stdout == DEVNULL: + c2pwrite = self._get_devnull() + elif isinstance(stdout, int): + c2pwrite = stdout + else: + # Assuming file-like object + c2pwrite = stdout.fileno() - if stderr is None: - pass - elif stderr == PIPE: - errread, errwrite = os.pipe() - if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): - fcntl.fcntl(errwrite, fcntl.F_SETPIPE_SZ, self.pipesize) - elif stderr == STDOUT: - if c2pwrite != -1: - errwrite = c2pwrite - else: # child's stdout is not set, use parent's stdout - errwrite = sys.__stdout__.fileno() - elif stderr == DEVNULL: - errwrite = self._get_devnull() - elif isinstance(stderr, int): - errwrite = stderr - else: - # Assuming file-like object - errwrite = stderr.fileno() + if stderr is None: + pass + elif stderr == PIPE: + errread, errwrite = os.pipe() + err_close_fds.extend((errread, errwrite)) + if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): + fcntl.fcntl(errwrite, fcntl.F_SETPIPE_SZ, self.pipesize) + elif stderr == STDOUT: + if c2pwrite != -1: + errwrite = c2pwrite + else: # child's stdout is not set, use parent's stdout + errwrite = sys.__stdout__.fileno() + elif stderr == DEVNULL: + errwrite = self._get_devnull() + elif isinstance(stderr, int): + errwrite = stderr + else: + # Assuming file-like object + errwrite = stderr.fileno() return (p2cread, p2cwrite, c2pread, c2pwrite, diff --git a/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst b/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst new file mode 100644 index 000000000000..eeb5308680e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst @@ -0,0 +1 @@ +Fix potential file descriptor leaks in :class:`subprocess.Popen`. From webhook-mailer at python.org Tue May 16 17:36:10 2023 From: webhook-mailer at python.org (brandtbucher) Date: Tue, 16 May 2023 21:36:10 -0000 Subject: [Python-checkins] GH-103906: Remove immortal refcounting in the interpreter (GH-103909) Message-ID: <mailman.398.1684272972.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b4a974792355cb0f525211b2962679e68949f02e commit: b4a974792355cb0f525211b2962679e68949f02e branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-16T14:36:02-07:00 summary: GH-103906: Remove immortal refcounting in the interpreter (GH-103909) files: A Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst M Objects/boolobject.c M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst new file mode 100644 index 000000000000..cb2aaffed9ff --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst @@ -0,0 +1,2 @@ +Don't modify the refcounts of known immortal objects (:const:`True`, +:const:`False`, and :const:`None`) in the main interpreter loop. diff --git a/Objects/boolobject.c b/Objects/boolobject.c index 0300f7bb4e3d..f43e26f3f24e 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -20,13 +20,7 @@ bool_repr(PyObject *self) PyObject *PyBool_FromLong(long ok) { - PyObject *result; - - if (ok) - result = Py_True; - else - result = Py_False; - return Py_NewRef(result); + return ok ? Py_True : Py_False; } /* We define bool_new to always return either Py_True or Py_False */ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b38d37a7773b..e92c5d8b6f3b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -270,7 +270,6 @@ dummy_func( else { res = Py_False; } - Py_INCREF(res); } inst(UNARY_INVERT, (value -- res)) { @@ -967,7 +966,7 @@ dummy_func( if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); DECREF_INPUTS(); - none = Py_NewRef(Py_None); + none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); @@ -1452,7 +1451,7 @@ dummy_func( DECREF_INPUTS(); ERROR_IF(true, error); } - Py_DECREF(none_val); + assert(Py_IsNone(none_val)); DECREF_INPUTS(); } @@ -1993,7 +1992,6 @@ dummy_func( _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - Py_INCREF(res); } // Similar to COMPARE_OP_FLOAT @@ -2012,7 +2010,6 @@ dummy_func( _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - Py_INCREF(res); } // Similar to COMPARE_OP_FLOAT, but for ==, != only @@ -2028,20 +2025,19 @@ dummy_func( assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - Py_INCREF(res); } inst(IS_OP, (left, right -- b)) { int res = Py_Is(left, right) ^ oparg; DECREF_INPUTS(); - b = Py_NewRef(res ? Py_True : Py_False); + b = res ? Py_True : Py_False; } inst(CONTAINS_OP, (left, right -- b)) { int res = PySequence_Contains(right, left); DECREF_INPUTS(); ERROR_IF(res < 0, error); - b = Py_NewRef((res^oparg) ? Py_True : Py_False); + b = (res ^ oparg) ? Py_True : Py_False; } inst(CHECK_EG_MATCH, (exc_value, match_type -- rest, match)) { @@ -2074,7 +2070,7 @@ dummy_func( int res = PyErr_GivenExceptionMatches(left, right); DECREF_INPUTS(); - b = Py_NewRef(res ? Py_True : Py_False); + b = res ? Py_True : Py_False; } inst(IMPORT_NAME, (level, fromlist -- res)) { @@ -2101,14 +2097,10 @@ dummy_func( } inst(POP_JUMP_IF_FALSE, (cond -- )) { - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); + if (Py_IsFalse(cond)) { JUMPBY(oparg); } - else { + else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); DECREF_INPUTS(); if (err == 0) { @@ -2121,14 +2113,10 @@ dummy_func( } inst(POP_JUMP_IF_TRUE, (cond -- )) { - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); + if (Py_IsTrue(cond)) { JUMPBY(oparg); } - else { + else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); DECREF_INPUTS(); if (err > 0) { @@ -2145,14 +2133,10 @@ dummy_func( DECREF_INPUTS(); JUMPBY(oparg); } - else { - _Py_DECREF_NO_DEALLOC(value); - } } inst(POP_JUMP_IF_NONE, (value -- )) { if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { @@ -2188,19 +2172,19 @@ dummy_func( } else { ERROR_IF(_PyErr_Occurred(tstate), error); // Error! - attrs = Py_NewRef(Py_None); // Failure! + attrs = Py_None; // Failure! } } inst(MATCH_MAPPING, (subject -- subject, res)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; - res = Py_NewRef(match ? Py_True : Py_False); + res = match ? Py_True : Py_False; PREDICT(POP_JUMP_IF_FALSE); } inst(MATCH_SEQUENCE, (subject -- subject, res)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; - res = Py_NewRef(match ? Py_True : Py_False); + res = match ? Py_True : Py_False; PREDICT(POP_JUMP_IF_FALSE); } @@ -2392,7 +2376,7 @@ dummy_func( STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; - _PyFrame_StackPush(gen_frame, Py_NewRef(Py_None)); + _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; @@ -2499,7 +2483,7 @@ dummy_func( prev_exc = exc_info->exc_value; } else { - prev_exc = Py_NewRef(Py_None); + prev_exc = Py_None; } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); @@ -3393,7 +3377,6 @@ dummy_func( _Py_CODEUNIT *here = next_instr-1; int offset; if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); offset = oparg; } else { @@ -3408,7 +3391,6 @@ dummy_func( _Py_CODEUNIT *here = next_instr-1; int offset; if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); offset = 0; } else { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index bd1f2988e2f1..32fe7bcef428 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -365,8 +365,7 @@ else { res = Py_False; } - Py_INCREF(res); - #line 370 "Python/generated_cases.c.h" + #line 369 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -374,13 +373,13 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 277 "Python/bytecodes.c" + #line 276 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 380 "Python/generated_cases.c.h" + #line 379 "Python/generated_cases.c.h" Py_DECREF(value); - #line 279 "Python/bytecodes.c" + #line 278 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 384 "Python/generated_cases.c.h" + #line 383 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -389,7 +388,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 296 "Python/bytecodes.c" + #line 295 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -397,7 +396,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) goto pop_2_error; - #line 401 "Python/generated_cases.c.h" + #line 400 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -408,14 +407,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 306 "Python/bytecodes.c" + #line 305 "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 419 "Python/generated_cases.c.h" + #line 418 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -426,7 +425,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 315 "Python/bytecodes.c" + #line 314 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -434,7 +433,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sub == NULL) goto pop_2_error; - #line 438 "Python/generated_cases.c.h" + #line 437 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -445,13 +444,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 325 "Python/bytecodes.c" + #line 324 "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 455 "Python/generated_cases.c.h" + #line 454 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -462,7 +461,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 333 "Python/bytecodes.c" + #line 332 "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); @@ -470,7 +469,7 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 474 "Python/generated_cases.c.h" + #line 473 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -480,7 +479,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 349 "Python/bytecodes.c" + #line 348 "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]; @@ -507,7 +506,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - #line 511 "Python/generated_cases.c.h" + #line 510 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -516,14 +515,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 378 "Python/bytecodes.c" + #line 377 "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 527 "Python/generated_cases.c.h" + #line 526 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -534,7 +533,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 387 "Python/bytecodes.c" + #line 386 "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); @@ -542,7 +541,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sum == NULL) goto pop_2_error; - #line 546 "Python/generated_cases.c.h" + #line 545 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -555,7 +554,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 405 "Python/bytecodes.c" + #line 404 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -567,12 +566,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 571 "Python/generated_cases.c.h" + #line 570 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 417 "Python/bytecodes.c" + #line 416 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 576 "Python/generated_cases.c.h" + #line 575 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -584,7 +583,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 421 "Python/bytecodes.c" + #line 420 "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. @@ -597,7 +596,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 601 "Python/generated_cases.c.h" + #line 600 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -608,7 +607,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 436 "Python/bytecodes.c" + #line 435 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -621,7 +620,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 625 "Python/generated_cases.c.h" + #line 624 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -630,7 +629,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 451 "Python/bytecodes.c" + #line 450 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -644,7 +643,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 648 "Python/generated_cases.c.h" + #line 647 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -655,7 +654,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 467 "Python/bytecodes.c" + #line 466 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -669,7 +668,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 673 "Python/generated_cases.c.h" + #line 672 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -680,7 +679,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 483 "Python/bytecodes.c" + #line 482 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -688,14 +687,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 692 "Python/generated_cases.c.h" + #line 691 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 491 "Python/bytecodes.c" + #line 490 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 699 "Python/generated_cases.c.h" + #line 698 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -707,7 +706,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 498 "Python/bytecodes.c" + #line 497 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -730,15 +729,15 @@ JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 734 "Python/generated_cases.c.h" + #line 733 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 523 "Python/bytecodes.c" + #line 522 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 742 "Python/generated_cases.c.h" + #line 741 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -747,13 +746,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 528 "Python/bytecodes.c" + #line 527 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 753 "Python/generated_cases.c.h" + #line 752 "Python/generated_cases.c.h" Py_DECREF(v); - #line 530 "Python/bytecodes.c" + #line 529 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 757 "Python/generated_cases.c.h" + #line 756 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -766,7 +765,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 541 "Python/bytecodes.c" + #line 540 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -781,13 +780,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 785 "Python/generated_cases.c.h" + #line 784 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 556 "Python/bytecodes.c" + #line 555 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 791 "Python/generated_cases.c.h" + #line 790 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -797,7 +796,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 560 "Python/bytecodes.c" + #line 559 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -814,7 +813,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 818 "Python/generated_cases.c.h" + #line 817 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -824,13 +823,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 579 "Python/bytecodes.c" + #line 578 "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 834 "Python/generated_cases.c.h" + #line 833 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -839,15 +838,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 587 "Python/bytecodes.c" + #line 586 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 846 "Python/generated_cases.c.h" + #line 845 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 590 "Python/bytecodes.c" + #line 589 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 851 "Python/generated_cases.c.h" + #line 850 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -855,14 +854,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 594 "Python/bytecodes.c" + #line 593 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 862 "Python/generated_cases.c.h" + #line 861 "Python/generated_cases.c.h" Py_DECREF(value); - #line 597 "Python/bytecodes.c" + #line 596 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 866 "Python/generated_cases.c.h" + #line 865 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -871,15 +870,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 601 "Python/bytecodes.c" + #line 600 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 878 "Python/generated_cases.c.h" + #line 877 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 604 "Python/bytecodes.c" + #line 603 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 883 "Python/generated_cases.c.h" + #line 882 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -887,7 +886,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 608 "Python/bytecodes.c" + #line 607 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -905,12 +904,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 909 "Python/generated_cases.c.h" + #line 908 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 628 "Python/bytecodes.c" + #line 627 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -921,12 +920,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 925 "Python/generated_cases.c.h" + #line 924 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 641 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -939,12 +938,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 943 "Python/generated_cases.c.h" + #line 942 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 656 "Python/bytecodes.c" + #line 655 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -961,11 +960,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 965 "Python/generated_cases.c.h" + #line 964 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 675 "Python/bytecodes.c" + #line 674 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -979,11 +978,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 983 "Python/generated_cases.c.h" + #line 982 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 691 "Python/bytecodes.c" + #line 690 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1001,13 +1000,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1005 "Python/generated_cases.c.h" + #line 1004 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 711 "Python/bytecodes.c" + #line 710 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1020,16 +1019,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1024 "Python/generated_cases.c.h" + #line 1023 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 724 "Python/bytecodes.c" + #line 723 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1031 "Python/generated_cases.c.h" + #line 1030 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 729 "Python/bytecodes.c" + #line 728 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1042,7 +1041,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1046 "Python/generated_cases.c.h" + #line 1045 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1050,7 +1049,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 744 "Python/bytecodes.c" + #line 743 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1094,7 +1093,7 @@ } } - #line 1098 "Python/generated_cases.c.h" + #line 1097 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -1105,16 +1104,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 791 "Python/bytecodes.c" + #line 790 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1116 "Python/generated_cases.c.h" + #line 1115 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 798 "Python/bytecodes.c" + #line 797 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1132,7 +1131,7 @@ if (iter == NULL) goto pop_1_error; - #line 1136 "Python/generated_cases.c.h" + #line 1135 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1144,7 +1143,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 824 "Python/bytecodes.c" + #line 823 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1191,7 +1190,7 @@ } } Py_DECREF(v); - #line 1195 "Python/generated_cases.c.h" + #line 1194 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1200,7 +1199,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 873 "Python/bytecodes.c" + #line 872 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1216,12 +1215,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1220 "Python/generated_cases.c.h" + #line 1219 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 891 "Python/bytecodes.c" + #line 890 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1238,12 +1237,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1242 "Python/generated_cases.c.h" + #line 1241 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 910 "Python/bytecodes.c" + #line 909 "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. @@ -1259,15 +1258,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1263 "Python/generated_cases.c.h" + #line 1262 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 928 "Python/bytecodes.c" + #line 927 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1271 "Python/generated_cases.c.h" + #line 1270 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1275,7 +1274,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 933 "Python/bytecodes.c" + #line 932 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1293,26 +1292,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1297 "Python/generated_cases.c.h" + #line 1296 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 953 "Python/bytecodes.c" + #line 952 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1306 "Python/generated_cases.c.h" + #line 1305 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 956 "Python/bytecodes.c" + #line 955 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1316 "Python/generated_cases.c.h" + #line 1315 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1323,23 +1322,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 965 "Python/bytecodes.c" + #line 964 "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 1332 "Python/generated_cases.c.h" + #line 1331 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 970 "Python/bytecodes.c" - none = Py_NewRef(Py_None); + #line 969 "Python/bytecodes.c" + none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1343 "Python/generated_cases.c.h" + #line 1342 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1348,9 +1347,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 979 "Python/bytecodes.c" + #line 978 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1354 "Python/generated_cases.c.h" + #line 1353 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1358,7 +1357,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 983 "Python/bytecodes.c" + #line 982 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1380,7 +1379,7 @@ if (true) goto error; } } - #line 1384 "Python/generated_cases.c.h" + #line 1383 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1388,33 +1387,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1008 "Python/bytecodes.c" + #line 1007 "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 1399 "Python/generated_cases.c.h" + #line 1398 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1015 "Python/bytecodes.c" + #line 1014 "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 1408 "Python/generated_cases.c.h" + #line 1407 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1022 "Python/bytecodes.c" + #line 1021 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1412 "Python/generated_cases.c.h" + #line 1411 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1026 "Python/bytecodes.c" + #line 1025 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1431,7 +1430,7 @@ name); goto error; } - #line 1435 "Python/generated_cases.c.h" + #line 1434 "Python/generated_cases.c.h" DISPATCH(); } @@ -1439,7 +1438,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1052 "Python/bytecodes.c" + #line 1051 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1452,11 +1451,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1456 "Python/generated_cases.c.h" + #line 1455 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1065 "Python/bytecodes.c" + #line 1064 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1460 "Python/generated_cases.c.h" + #line 1459 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1466,14 +1465,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1069 "Python/bytecodes.c" + #line 1068 "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 1477 "Python/generated_cases.c.h" + #line 1476 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1484,7 +1483,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1079 "Python/bytecodes.c" + #line 1078 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1492,7 +1491,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1496 "Python/generated_cases.c.h" + #line 1495 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1503,7 +1502,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1090 "Python/bytecodes.c" + #line 1089 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1511,7 +1510,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1515 "Python/generated_cases.c.h" + #line 1514 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1521,15 +1520,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1101 "Python/bytecodes.c" + #line 1100 "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 1529 "Python/generated_cases.c.h" + #line 1528 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1105 "Python/bytecodes.c" + #line 1104 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1533 "Python/generated_cases.c.h" + #line 1532 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1540,7 +1539,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1116 "Python/bytecodes.c" + #line 1115 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1556,12 +1555,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1560 "Python/generated_cases.c.h" + #line 1559 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1132 "Python/bytecodes.c" + #line 1131 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1565 "Python/generated_cases.c.h" + #line 1564 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1569,34 +1568,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1136 "Python/bytecodes.c" + #line 1135 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1576 "Python/generated_cases.c.h" + #line 1575 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1139 "Python/bytecodes.c" + #line 1138 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1580 "Python/generated_cases.c.h" + #line 1579 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1143 "Python/bytecodes.c" + #line 1142 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1590 "Python/generated_cases.c.h" + #line 1589 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1146 "Python/bytecodes.c" + #line 1145 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1594 "Python/generated_cases.c.h" + #line 1593 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1150 "Python/bytecodes.c" + #line 1149 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1608,7 +1607,7 @@ } goto error; } - #line 1612 "Python/generated_cases.c.h" + #line 1611 "Python/generated_cases.c.h" DISPATCH(); } @@ -1616,7 +1615,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1164 "Python/bytecodes.c" + #line 1163 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1624,7 +1623,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1628 "Python/generated_cases.c.h" + #line 1627 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1636,7 +1635,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1164 "Python/bytecodes.c" + #line 1163 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1644,13 +1643,13 @@ if (true) goto error; } Py_INCREF(locals); - #line 1648 "Python/generated_cases.c.h" + #line 1647 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1176 "Python/bytecodes.c" + #line 1175 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1707,7 +1706,7 @@ } } } - #line 1711 "Python/generated_cases.c.h" + #line 1710 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1720,7 +1719,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1176 "Python/bytecodes.c" + #line 1175 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1777,7 +1776,7 @@ } } } - #line 1781 "Python/generated_cases.c.h" + #line 1780 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1789,7 +1788,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1245 "Python/bytecodes.c" + #line 1244 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1841,7 +1840,7 @@ } } null = NULL; - #line 1845 "Python/generated_cases.c.h" + #line 1844 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1855,7 +1854,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1299 "Python/bytecodes.c" + #line 1298 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1866,7 +1865,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1870 "Python/generated_cases.c.h" + #line 1869 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1881,7 +1880,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 1312 "Python/bytecodes.c" + #line 1311 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1896,7 +1895,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1900 "Python/generated_cases.c.h" + #line 1899 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1906,16 +1905,16 @@ } TARGET(DELETE_FAST) { - #line 1329 "Python/bytecodes.c" + #line 1328 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1914 "Python/generated_cases.c.h" + #line 1913 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1335 "Python/bytecodes.c" + #line 1334 "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); @@ -1924,12 +1923,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1928 "Python/generated_cases.c.h" + #line 1927 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1346 "Python/bytecodes.c" + #line 1345 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1940,14 +1939,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1944 "Python/generated_cases.c.h" + #line 1943 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1359 "Python/bytecodes.c" + #line 1358 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1982,14 +1981,14 @@ } Py_INCREF(value); } - #line 1986 "Python/generated_cases.c.h" + #line 1985 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1396 "Python/bytecodes.c" + #line 1395 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1997,7 +1996,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2001 "Python/generated_cases.c.h" + #line 2000 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2005,18 +2004,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1406 "Python/bytecodes.c" + #line 1405 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2014 "Python/generated_cases.c.h" + #line 2013 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1413 "Python/bytecodes.c" + #line 1412 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2027,22 +2026,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2031 "Python/generated_cases.c.h" + #line 2030 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1426 "Python/bytecodes.c" + #line 1425 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2040 "Python/generated_cases.c.h" + #line 2039 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1428 "Python/bytecodes.c" + #line 1427 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2046 "Python/generated_cases.c.h" + #line 2045 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2052,10 +2051,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1432 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2059 "Python/generated_cases.c.h" + #line 2058 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2065,10 +2064,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1437 "Python/bytecodes.c" + #line 1436 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2072 "Python/generated_cases.c.h" + #line 2071 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2078,7 +2077,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1442 "Python/bytecodes.c" + #line 1441 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2089,13 +2088,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2093 "Python/generated_cases.c.h" + #line 2092 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1453 "Python/bytecodes.c" + #line 1452 "Python/bytecodes.c" if (true) goto pop_1_error; } - Py_DECREF(none_val); - #line 2099 "Python/generated_cases.c.h" + assert(Py_IsNone(none_val)); + #line 2098 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2104,13 +2103,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1460 "Python/bytecodes.c" + #line 1459 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2110 "Python/generated_cases.c.h" + #line 2109 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1462 "Python/bytecodes.c" + #line 1461 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2114 "Python/generated_cases.c.h" + #line 2113 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2118,7 +2117,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1466 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2133,7 +2132,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2137 "Python/generated_cases.c.h" + #line 2136 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2143,7 +2142,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1483 "Python/bytecodes.c" + #line 1482 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2151,13 +2150,13 @@ if (map == NULL) goto error; - #line 2155 "Python/generated_cases.c.h" + #line 2154 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1491 "Python/bytecodes.c" + #line 1490 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2161 "Python/generated_cases.c.h" + #line 2160 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2165,7 +2164,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1495 "Python/bytecodes.c" + #line 1494 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2205,7 +2204,7 @@ Py_DECREF(ann_dict); } } - #line 2209 "Python/generated_cases.c.h" + #line 2208 "Python/generated_cases.c.h" DISPATCH(); } @@ -2213,7 +2212,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1537 "Python/bytecodes.c" + #line 1536 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2223,14 +2222,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2227 "Python/generated_cases.c.h" + #line 2226 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1547 "Python/bytecodes.c" + #line 1546 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2234 "Python/generated_cases.c.h" + #line 2233 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2238,7 +2237,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1551 "Python/bytecodes.c" + #line 1550 "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)) { @@ -2246,12 +2245,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2250 "Python/generated_cases.c.h" + #line 2249 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1559 "Python/bytecodes.c" + #line 1558 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2255 "Python/generated_cases.c.h" + #line 2254 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2259,17 +2258,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1565 "Python/bytecodes.c" + #line 1564 "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 2268 "Python/generated_cases.c.h" + #line 2267 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1570 "Python/bytecodes.c" + #line 1569 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2273 "Python/generated_cases.c.h" + #line 2272 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2279,26 +2278,26 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1577 "Python/bytecodes.c" + #line 1576 "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 2289 "Python/generated_cases.c.h" + #line 2288 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1586 "Python/bytecodes.c" + #line 1585 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2302 "Python/generated_cases.c.h" + #line 2301 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2309,7 +2308,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1600 "Python/bytecodes.c" + #line 1599 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2351,16 +2350,16 @@ } } } - #line 2355 "Python/generated_cases.c.h" + #line 2354 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1642 "Python/bytecodes.c" + #line 1641 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2364 "Python/generated_cases.c.h" + #line 2363 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2375,20 +2374,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1649 "Python/bytecodes.c" + #line 1648 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2386 "Python/generated_cases.c.h" + #line 2385 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1656 "Python/bytecodes.c" + #line 1655 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2392 "Python/generated_cases.c.h" + #line 2391 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2403,7 +2402,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1660 "Python/bytecodes.c" + #line 1659 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2424,7 +2423,7 @@ res = res2; res2 = NULL; } - #line 2428 "Python/generated_cases.c.h" + #line 2427 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2438,7 +2437,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1697 "Python/bytecodes.c" + #line 1696 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2472,9 +2471,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2476 "Python/generated_cases.c.h" + #line 2475 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1731 "Python/bytecodes.c" + #line 1730 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2483,12 +2482,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2487 "Python/generated_cases.c.h" + #line 2486 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1740 "Python/bytecodes.c" + #line 1739 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2492 "Python/generated_cases.c.h" + #line 2491 "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; } @@ -2502,7 +2501,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1745 "Python/bytecodes.c" + #line 1744 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2515,7 +2514,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2519 "Python/generated_cases.c.h" + #line 2518 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2530,7 +2529,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1761 "Python/bytecodes.c" + #line 1760 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2543,7 +2542,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2547 "Python/generated_cases.c.h" + #line 2546 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2558,7 +2557,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1777 "Python/bytecodes.c" + #line 1776 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2585,7 +2584,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2589 "Python/generated_cases.c.h" + #line 2588 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2600,7 +2599,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1807 "Python/bytecodes.c" + #line 1806 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2610,7 +2609,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2614 "Python/generated_cases.c.h" + #line 2613 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2625,7 +2624,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1820 "Python/bytecodes.c" + #line 1819 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2637,7 +2636,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2641 "Python/generated_cases.c.h" + #line 2640 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2651,7 +2650,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 1835 "Python/bytecodes.c" + #line 1834 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2675,7 +2674,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2679 "Python/generated_cases.c.h" + #line 2678 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2683,7 +2682,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 1861 "Python/bytecodes.c" + #line 1860 "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); @@ -2709,7 +2708,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2713 "Python/generated_cases.c.h" + #line 2712 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2717,7 +2716,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 1889 "Python/bytecodes.c" + #line 1888 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2735,7 +2734,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2739 "Python/generated_cases.c.h" + #line 2738 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2746,7 +2745,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 1909 "Python/bytecodes.c" + #line 1908 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2785,7 +2784,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2789 "Python/generated_cases.c.h" + #line 2788 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2796,7 +2795,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 1950 "Python/bytecodes.c" + #line 1949 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2806,7 +2805,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2810 "Python/generated_cases.c.h" + #line 2809 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2818,7 +2817,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1969 "Python/bytecodes.c" + #line 1968 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2831,12 +2830,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2835 "Python/generated_cases.c.h" + #line 2834 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1982 "Python/bytecodes.c" + #line 1981 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2840 "Python/generated_cases.c.h" + #line 2839 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2847,7 +2846,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1986 "Python/bytecodes.c" + #line 1985 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2858,8 +2857,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - Py_INCREF(res); - #line 2863 "Python/generated_cases.c.h" + #line 2861 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2870,7 +2868,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2001 "Python/bytecodes.c" + #line 1999 "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); @@ -2885,8 +2883,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - Py_INCREF(res); - #line 2890 "Python/generated_cases.c.h" + #line 2887 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2897,7 +2894,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2020 "Python/bytecodes.c" + #line 2017 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2909,8 +2906,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - Py_INCREF(res); - #line 2914 "Python/generated_cases.c.h" + #line 2910 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2921,14 +2917,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2035 "Python/bytecodes.c" + #line 2031 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2927 "Python/generated_cases.c.h" + #line 2923 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2037 "Python/bytecodes.c" - b = Py_NewRef(res ? Py_True : Py_False); - #line 2932 "Python/generated_cases.c.h" + #line 2033 "Python/bytecodes.c" + b = res ? Py_True : Py_False; + #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2938,15 +2934,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2041 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2944 "Python/generated_cases.c.h" + #line 2940 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2043 "Python/bytecodes.c" + #line 2039 "Python/bytecodes.c" if (res < 0) goto pop_2_error; - b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2950 "Python/generated_cases.c.h" + b = (res ^ oparg) ? Py_True : Py_False; + #line 2946 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2957,12 +2953,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2048 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2963 "Python/generated_cases.c.h" + #line 2959 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2050 "Python/bytecodes.c" + #line 2046 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2970,10 +2966,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2974 "Python/generated_cases.c.h" + #line 2970 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2058 "Python/bytecodes.c" + #line 2054 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2982,7 +2978,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2986 "Python/generated_cases.c.h" + #line 2982 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2992,21 +2988,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2069 "Python/bytecodes.c" + #line 2065 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2999 "Python/generated_cases.c.h" + #line 2995 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2072 "Python/bytecodes.c" + #line 2068 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3006 "Python/generated_cases.c.h" + #line 3002 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2077 "Python/bytecodes.c" - b = Py_NewRef(res ? Py_True : Py_False); - #line 3010 "Python/generated_cases.c.h" + #line 2073 "Python/bytecodes.c" + b = res ? Py_True : Py_False; + #line 3006 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3015,15 +3011,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2081 "Python/bytecodes.c" + #line 2077 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3022 "Python/generated_cases.c.h" + #line 3018 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2084 "Python/bytecodes.c" + #line 2080 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3027 "Python/generated_cases.c.h" + #line 3023 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3032,29 +3028,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2088 "Python/bytecodes.c" + #line 2084 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3040 "Python/generated_cases.c.h" + #line 3036 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2094 "Python/bytecodes.c" + #line 2090 "Python/bytecodes.c" JUMPBY(oparg); - #line 3049 "Python/generated_cases.c.h" + #line 3045 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2098 "Python/bytecodes.c" + #line 2094 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 3058 "Python/generated_cases.c.h" + #line 3054 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -3062,19 +3058,15 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2104 "Python/bytecodes.c" - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); + #line 2100 "Python/bytecodes.c" + if (Py_IsFalse(cond)) { JUMPBY(oparg); } - else { + else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3076 "Python/generated_cases.c.h" + #line 3068 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2114 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3082,26 +3074,22 @@ if (err < 0) goto pop_1_error; } } - #line 3086 "Python/generated_cases.c.h" + #line 3078 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2124 "Python/bytecodes.c" - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); + #line 2116 "Python/bytecodes.c" + if (Py_IsTrue(cond)) { JUMPBY(oparg); } - else { + else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3103 "Python/generated_cases.c.h" + #line 3091 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2134 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3109,67 +3097,63 @@ if (err < 0) goto pop_1_error; } } - #line 3113 "Python/generated_cases.c.h" + #line 3101 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2144 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3122 "Python/generated_cases.c.h" + #line 3110 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2146 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" JUMPBY(oparg); } - else { - _Py_DECREF_NO_DEALLOC(value); - } - #line 3130 "Python/generated_cases.c.h" + #line 3115 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2154 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 3143 "Python/generated_cases.c.h" + #line 3127 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2160 "Python/bytecodes.c" + #line 2144 "Python/bytecodes.c" } - #line 3147 "Python/generated_cases.c.h" + #line 3131 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2164 "Python/bytecodes.c" + #line 2148 "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 3160 "Python/generated_cases.c.h" + #line 3144 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2173 "Python/bytecodes.c" + #line 2157 "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 3173 "Python/generated_cases.c.h" + #line 3157 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3180,24 +3164,24 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2181 "Python/bytecodes.c" + #line 2165 "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 3189 "Python/generated_cases.c.h" + #line 3173 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2186 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } else { if (_PyErr_Occurred(tstate)) goto pop_3_error; - attrs = Py_NewRef(Py_None); // Failure! + attrs = Py_None; // Failure! } - #line 3201 "Python/generated_cases.c.h" + #line 3185 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3206,10 +3190,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2196 "Python/bytecodes.c" + #line 2180 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; - res = Py_NewRef(match ? Py_True : Py_False); - #line 3213 "Python/generated_cases.c.h" + res = match ? Py_True : Py_False; + #line 3197 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3219,10 +3203,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2202 "Python/bytecodes.c" + #line 2186 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; - res = Py_NewRef(match ? Py_True : Py_False); - #line 3226 "Python/generated_cases.c.h" + res = match ? Py_True : Py_False; + #line 3210 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -3233,11 +3217,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2208 "Python/bytecodes.c" + #line 2192 "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 3241 "Python/generated_cases.c.h" + #line 3225 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3246,14 +3230,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2214 "Python/bytecodes.c" + #line 2198 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3253 "Python/generated_cases.c.h" + #line 3237 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2217 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3257 "Python/generated_cases.c.h" + #line 3241 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3261,7 +3245,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2221 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3284,11 +3268,11 @@ if (iter == NULL) { goto error; } - #line 3288 "Python/generated_cases.c.h" + #line 3272 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2244 "Python/bytecodes.c" + #line 2228 "Python/bytecodes.c" } - #line 3292 "Python/generated_cases.c.h" + #line 3276 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3299,7 +3283,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2263 "Python/bytecodes.c" + #line 2247 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3330,7 +3314,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3334 "Python/generated_cases.c.h" + #line 3318 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3338,7 +3322,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2296 "Python/bytecodes.c" + #line 2280 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3364,14 +3348,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3368 "Python/generated_cases.c.h" + #line 3352 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2324 "Python/bytecodes.c" + #line 2308 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3391,7 +3375,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3395 "Python/generated_cases.c.h" + #line 3379 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3401,7 +3385,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2346 "Python/bytecodes.c" + #line 2330 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3421,7 +3405,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3425 "Python/generated_cases.c.h" + #line 3409 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3431,7 +3415,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2368 "Python/bytecodes.c" + #line 2352 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3449,7 +3433,7 @@ if (next == NULL) { goto error; } - #line 3453 "Python/generated_cases.c.h" + #line 3437 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3458,7 +3442,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2388 "Python/bytecodes.c" + #line 2372 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3466,7 +3450,7 @@ STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; frame->return_offset = oparg; - _PyFrame_StackPush(gen_frame, Py_NewRef(Py_None)); + _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; @@ -3474,14 +3458,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3478 "Python/generated_cases.c.h" + #line 3462 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2406 "Python/bytecodes.c" + #line 2390 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3504,16 +3488,16 @@ Py_DECREF(enter); goto error; } - #line 3508 "Python/generated_cases.c.h" + #line 3492 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2429 "Python/bytecodes.c" + #line 2413 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3517 "Python/generated_cases.c.h" + #line 3501 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3525,7 +3509,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2439 "Python/bytecodes.c" + #line 2423 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3551,16 +3535,16 @@ Py_DECREF(enter); goto error; } - #line 3555 "Python/generated_cases.c.h" + #line 3539 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2465 "Python/bytecodes.c" + #line 2449 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3564 "Python/generated_cases.c.h" + #line 3548 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3572,7 +3556,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2474 "Python/bytecodes.c" + #line 2458 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3593,7 +3577,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3597 "Python/generated_cases.c.h" + #line 3581 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3602,17 +3586,17 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2497 "Python/bytecodes.c" + #line 2481 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; } else { - prev_exc = Py_NewRef(Py_None); + prev_exc = Py_None; } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3616 "Python/generated_cases.c.h" + #line 3600 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3626,7 +3610,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 2509 "Python/bytecodes.c" + #line 2493 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3643,7 +3627,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3647 "Python/generated_cases.c.h" + #line 3631 "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; } @@ -3657,7 +3641,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2528 "Python/bytecodes.c" + #line 2512 "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); @@ -3667,7 +3651,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3671 "Python/generated_cases.c.h" + #line 3655 "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; } @@ -3681,7 +3665,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2540 "Python/bytecodes.c" + #line 2524 "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; @@ -3695,7 +3679,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3699 "Python/generated_cases.c.h" + #line 3683 "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; } @@ -3704,16 +3688,16 @@ } TARGET(KW_NAMES) { - #line 2556 "Python/bytecodes.c" + #line 2540 "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 3712 "Python/generated_cases.c.h" + #line 3696 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2562 "Python/bytecodes.c" + #line 2546 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3726,7 +3710,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3730 "Python/generated_cases.c.h" + #line 3714 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3736,7 +3720,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2607 "Python/bytecodes.c" + #line 2591 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3818,7 +3802,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3822 "Python/generated_cases.c.h" + #line 3806 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3830,7 +3814,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2695 "Python/bytecodes.c" + #line 2679 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3840,7 +3824,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3844 "Python/generated_cases.c.h" + #line 3828 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3849,7 +3833,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2707 "Python/bytecodes.c" + #line 2691 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3875,7 +3859,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3879 "Python/generated_cases.c.h" + #line 3863 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3883,7 +3867,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2735 "Python/bytecodes.c" + #line 2719 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3919,7 +3903,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3923 "Python/generated_cases.c.h" + #line 3907 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3927,7 +3911,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2773 "Python/bytecodes.c" + #line 2757 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3937,7 +3921,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3941 "Python/generated_cases.c.h" + #line 3925 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3950,7 +3934,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2785 "Python/bytecodes.c" + #line 2769 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3961,7 +3945,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3965 "Python/generated_cases.c.h" + #line 3949 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3975,7 +3959,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2799 "Python/bytecodes.c" + #line 2783 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3986,7 +3970,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3990 "Python/generated_cases.c.h" + #line 3974 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4000,7 +3984,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2813 "Python/bytecodes.c" + #line 2797 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4022,7 +4006,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4026 "Python/generated_cases.c.h" + #line 4010 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4036,7 +4020,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2838 "Python/bytecodes.c" + #line 2822 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4064,7 +4048,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4068 "Python/generated_cases.c.h" + #line 4052 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4078,7 +4062,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2869 "Python/bytecodes.c" + #line 2853 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4110,7 +4094,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4114 "Python/generated_cases.c.h" + #line 4098 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4124,7 +4108,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2904 "Python/bytecodes.c" + #line 2888 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4156,7 +4140,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4160 "Python/generated_cases.c.h" + #line 4144 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4170,7 +4154,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2939 "Python/bytecodes.c" + #line 2923 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4195,7 +4179,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4199 "Python/generated_cases.c.h" + #line 4183 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4208,7 +4192,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2966 "Python/bytecodes.c" + #line 2950 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4235,7 +4219,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4239 "Python/generated_cases.c.h" + #line 4223 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4247,7 +4231,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2996 "Python/bytecodes.c" + #line 2980 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4265,14 +4249,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4269 "Python/generated_cases.c.h" + #line 4253 "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 3016 "Python/bytecodes.c" + #line 3000 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4303,7 +4287,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4307 "Python/generated_cases.c.h" + #line 4291 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4316,7 +4300,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3050 "Python/bytecodes.c" + #line 3034 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4345,7 +4329,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4349 "Python/generated_cases.c.h" + #line 4333 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4358,7 +4342,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3082 "Python/bytecodes.c" + #line 3066 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4387,7 +4371,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4391 "Python/generated_cases.c.h" + #line 4375 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4400,7 +4384,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3114 "Python/bytecodes.c" + #line 3098 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4428,7 +4412,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4432 "Python/generated_cases.c.h" + #line 4416 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4438,9 +4422,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3145 "Python/bytecodes.c" + #line 3129 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4444 "Python/generated_cases.c.h" + #line 4428 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4449,7 +4433,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3149 "Python/bytecodes.c" + #line 3133 "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)); @@ -4511,14 +4495,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4515 "Python/generated_cases.c.h" + #line 4499 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3211 "Python/bytecodes.c" + #line 3195 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4522 "Python/generated_cases.c.h" + #line 4506 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4533,7 +4517,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 3221 "Python/bytecodes.c" + #line 3205 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4562,14 +4546,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4566 "Python/generated_cases.c.h" + #line 4550 "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 3252 "Python/bytecodes.c" + #line 3236 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4590,7 +4574,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4594 "Python/generated_cases.c.h" + #line 4578 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4598,15 +4582,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3275 "Python/bytecodes.c" + #line 3259 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4604 "Python/generated_cases.c.h" + #line 4588 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3277 "Python/bytecodes.c" + #line 3261 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4610 "Python/generated_cases.c.h" + #line 4594 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4617,7 +4601,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 3281 "Python/bytecodes.c" + #line 3265 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4652,7 +4636,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 4656 "Python/generated_cases.c.h" + #line 4640 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4661,10 +4645,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3318 "Python/bytecodes.c" + #line 3302 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4668 "Python/generated_cases.c.h" + #line 4652 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4676,7 +4660,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3323 "Python/bytecodes.c" + #line 3307 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4691,12 +4675,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4695 "Python/generated_cases.c.h" + #line 4679 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3338 "Python/bytecodes.c" + #line 3322 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4700 "Python/generated_cases.c.h" + #line 4684 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4706,16 +4690,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3343 "Python/bytecodes.c" + #line 3327 "Python/bytecodes.c" assert(oparg >= 2); - #line 4712 "Python/generated_cases.c.h" + #line 4696 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3347 "Python/bytecodes.c" + #line 3331 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4727,26 +4711,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4731 "Python/generated_cases.c.h" + #line 4715 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3361 "Python/bytecodes.c" + #line 3345 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4737 "Python/generated_cases.c.h" + #line 4721 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3365 "Python/bytecodes.c" + #line 3349 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); - #line 4744 "Python/generated_cases.c.h" + #line 4728 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3370 "Python/bytecodes.c" + #line 3354 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4755,12 +4739,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4759 "Python/generated_cases.c.h" + #line 4743 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3381 "Python/bytecodes.c" + #line 3365 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4769,17 +4753,16 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4773 "Python/generated_cases.c.h" + #line 4757 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3392 "Python/bytecodes.c" + #line 3376 "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 { @@ -4787,17 +4770,16 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4791 "Python/generated_cases.c.h" + #line 4774 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3407 "Python/bytecodes.c" + #line 3390 "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 { @@ -4805,30 +4787,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4809 "Python/generated_cases.c.h" + #line 4791 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3422 "Python/bytecodes.c" + #line 3404 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4820 "Python/generated_cases.c.h" + #line 4802 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3430 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4827 "Python/generated_cases.c.h" + #line 4809 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3435 "Python/bytecodes.c" + #line 3417 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4834 "Python/generated_cases.c.h" + #line 4816 "Python/generated_cases.c.h" } From webhook-mailer at python.org Tue May 16 18:32:20 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Tue, 16 May 2023 22:32:20 -0000 Subject: [Python-checkins] gh-104050: Add typing to Argument Clinic converters (#104547) Message-ID: <mailman.399.1684276341.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0afc473f500955b85c71725d8ae7d65787db5dd1 commit: 0afc473f500955b85c71725d8ae7d65787db5dd1 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-16T22:32:11Z summary: gh-104050: Add typing to Argument Clinic converters (#104547) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index dfe43c80ef32..3e54ba03d7a5 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -82,6 +82,7 @@ def __repr__(self) -> str: Appender = Callable[[str], None] Outputter = Callable[[], str] +TemplateDict = dict[str, str] class _TextAccumulator(NamedTuple): text: list[str] @@ -1969,20 +1970,6 @@ def dump(self): extensions['py'] = PythonLanguage -# maps strings to callables. -# these callables must be of the form: -# def foo(name, default, *, ...) -# The callable may have any number of keyword-only parameters. -# The callable must return a CConverter object. -# The callable should not call builtins.print. -converters = {} - -# maps strings to callables. -# these callables follow the same rules as those for "converters" above. -# note however that they will never be called with keyword-only parameters. -legacy_converters = {} - - # maps strings to callables. # these callables must be of the form: # def foo(*, ...) @@ -2956,7 +2943,7 @@ def parse_arg(self, argname, displayname): """.format(argname=argname, paramname=self.parser_name, cast=cast) return None - def set_template_dict(self, template_dict: dict[str, str]): + def set_template_dict(self, template_dict: TemplateDict) -> None: pass @property @@ -2979,6 +2966,23 @@ def parser_name(self): } +ConverterType = Callable[..., CConverter] +ConverterDict = dict[str, ConverterType] + +# maps strings to callables. +# these callables must be of the form: +# def foo(name, default, *, ...) +# The callable may have any number of keyword-only parameters. +# The callable must return a CConverter object. +# The callable should not call builtins.print. +converters: ConverterDict = {} + +# maps strings to callables. +# these callables follow the same rules as those for "converters" above. +# note however that they will never be called with keyword-only parameters. +legacy_converters: ConverterDict = {} + + class bool_converter(CConverter): type = 'int' default_type = bool @@ -2994,7 +2998,7 @@ def converter_init(self, *, accept={object}): self.default = bool(self.default) self.c_default = str(int(self.default)) - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'i': return """ {paramname} = _PyLong_AsInt({argname}); @@ -3020,10 +3024,10 @@ class defining_class_converter(CConverter): format_unit = '' show_in_signature = False - def converter_init(self, *, type=None): + def converter_init(self, *, type=None) -> None: self.specified_type = type - def render(self, parameter, data): + def render(self, parameter, data) -> None: self._render_self(parameter, data) def set_template_dict(self, template_dict): @@ -3036,7 +3040,7 @@ class char_converter(CConverter): format_unit = 'c' c_ignored_default = "'\0'" - def converter_init(self): + def converter_init(self) -> None: if isinstance(self.default, self.default_type): if len(self.default) != 1: fail("char_converter: illegal default value " + repr(self.default)) @@ -3045,7 +3049,7 @@ def converter_init(self): if self.c_default == '"\'"': self.c_default = r"'\''" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'c': return """ if (PyBytes_Check({argname}) && PyBytes_GET_SIZE({argname}) == 1) {{{{ @@ -3070,11 +3074,11 @@ class unsigned_char_converter(CConverter): format_unit = 'b' c_ignored_default = "'\0'" - def converter_init(self, *, bitwise=False): + def converter_init(self, *, bitwise: bool = False) -> None: if bitwise: self.format_unit = 'B' - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'b': return """ {{{{ @@ -3119,7 +3123,7 @@ class short_converter(CConverter): format_unit = 'h' c_ignored_default = "0" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'h': return """ {{{{ @@ -3149,13 +3153,13 @@ class unsigned_short_converter(CConverter): default_type = int c_ignored_default = "0" - def converter_init(self, *, bitwise=False): + def converter_init(self, *, bitwise: bool = False) -> None: if bitwise: self.format_unit = 'H' else: self.converter = '_PyLong_UnsignedShort_Converter' - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'H': return """ {paramname} = (unsigned short)PyLong_AsUnsignedLongMask({argname}); @@ -3172,7 +3176,7 @@ class int_converter(CConverter): format_unit = 'i' c_ignored_default = "0" - def converter_init(self, *, accept={int}, type=None): + def converter_init(self, *, accept={int}, type=None) -> None: if accept == {str}: self.format_unit = 'C' elif accept != {int}: @@ -3180,7 +3184,7 @@ def converter_init(self, *, accept={int}, type=None): if type is not None: self.type = type - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'i': return """ {paramname} = _PyLong_AsInt({argname}); @@ -3211,13 +3215,13 @@ class unsigned_int_converter(CConverter): default_type = int c_ignored_default = "0" - def converter_init(self, *, bitwise=False): + def converter_init(self, *, bitwise: bool = False) -> None: if bitwise: self.format_unit = 'I' else: self.converter = '_PyLong_UnsignedInt_Converter' - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'I': return """ {paramname} = (unsigned int)PyLong_AsUnsignedLongMask({argname}); @@ -3233,7 +3237,7 @@ class long_converter(CConverter): format_unit = 'l' c_ignored_default = "0" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'l': return """ {paramname} = PyLong_AsLong({argname}); @@ -3248,13 +3252,13 @@ class unsigned_long_converter(CConverter): default_type = int c_ignored_default = "0" - def converter_init(self, *, bitwise=False): + def converter_init(self, *, bitwise: bool = False) -> None: if bitwise: self.format_unit = 'k' else: self.converter = '_PyLong_UnsignedLong_Converter' - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'k': return """ if (!PyLong_Check({argname})) {{{{ @@ -3272,7 +3276,7 @@ class long_long_converter(CConverter): format_unit = 'L' c_ignored_default = "0" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'L': return """ {paramname} = PyLong_AsLongLong({argname}); @@ -3287,13 +3291,13 @@ class unsigned_long_long_converter(CConverter): default_type = int c_ignored_default = "0" - def converter_init(self, *, bitwise=False): + def converter_init(self, *, bitwise: bool = False) -> None: if bitwise: self.format_unit = 'K' else: self.converter = '_PyLong_UnsignedLongLong_Converter' - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'K': return """ if (!PyLong_Check({argname})) {{{{ @@ -3309,7 +3313,7 @@ class Py_ssize_t_converter(CConverter): type = 'Py_ssize_t' c_ignored_default = "0" - def converter_init(self, *, accept={int}): + def converter_init(self, *, accept={int}) -> None: if accept == {int}: self.format_unit = 'n' self.default_type = int @@ -3318,7 +3322,7 @@ def converter_init(self, *, accept={int}): else: fail("Py_ssize_t_converter: illegal 'accept' argument " + repr(accept)) - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'n': return """ {{{{ @@ -3340,7 +3344,7 @@ def parse_arg(self, argname, displayname): class slice_index_converter(CConverter): type = 'Py_ssize_t' - def converter_init(self, *, accept={int, NoneType}): + def converter_init(self, *, accept={int, NoneType}) -> None: if accept == {int}: self.converter = '_PyEval_SliceIndexNotNone' elif accept == {int, NoneType}: @@ -3353,7 +3357,7 @@ class size_t_converter(CConverter): converter = '_PyLong_Size_t_Converter' c_ignored_default = "0" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'n': return """ {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError); @@ -3368,7 +3372,7 @@ class fildes_converter(CConverter): type = 'int' converter = '_PyLong_FileDescriptor_Converter' - def _parse_arg(self, argname, displayname): + def _parse_arg(self, argname: str, displayname: str) -> str: return """ {paramname} = PyObject_AsFileDescriptor({argname}); if ({paramname} == -1) {{{{ @@ -3383,7 +3387,7 @@ class float_converter(CConverter): format_unit = 'f' c_ignored_default = "0.0" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'f': return """ if (PyFloat_CheckExact({argname})) {{{{ @@ -3405,7 +3409,7 @@ class double_converter(CConverter): format_unit = 'd' c_ignored_default = "0.0" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'd': return """ if (PyFloat_CheckExact({argname})) {{{{ @@ -3428,7 +3432,7 @@ class Py_complex_converter(CConverter): format_unit = 'D' c_ignored_default = "{0.0, 0.0}" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'D': return """ {paramname} = PyComplex_AsCComplex({argname}); @@ -3504,7 +3508,7 @@ def post_parsing(self): name = self.name return f"PyMem_FREE({name});\n" - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 's': return """ if (!PyUnicode_Check({argname})) {{{{ @@ -3599,7 +3603,7 @@ class PyBytesObject_converter(CConverter): format_unit = 'S' # accept = {bytes} - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'S': return """ if (!PyBytes_Check({argname})) {{{{ @@ -3616,7 +3620,7 @@ class PyByteArrayObject_converter(CConverter): format_unit = 'Y' # accept = {bytearray} - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'Y': return """ if (!PyByteArray_Check({argname})) {{{{ @@ -3633,7 +3637,7 @@ class unicode_converter(CConverter): default_type = (str, Null, NoneType) format_unit = 'U' - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'U': return """ if (!PyUnicode_Check({argname})) {{{{ @@ -3656,7 +3660,7 @@ class Py_UNICODE_converter(CConverter): type = 'const Py_UNICODE *' default_type = (str, Null, NoneType) - def converter_init(self, *, accept={str}, zeroes=False): + def converter_init(self, *, accept={str}, zeroes: bool = False) -> None: format_unit = 'Z' if accept=={str, NoneType} else 'u' if zeroes: format_unit += '#' @@ -3678,7 +3682,7 @@ def cleanup(self): PyMem_Free((void *){name}); """.format(name=self.name) - def parse_arg(self, argname, argnum): + def parse_arg(self, argname: str, argnum: str) -> str: if not self.length: if self.accept == {str}: return """ @@ -3718,7 +3722,7 @@ class Py_buffer_converter(CConverter): impl_by_reference = True c_ignored_default = "{NULL, NULL}" - def converter_init(self, *, accept={buffer}): + def converter_init(self, *, accept={buffer}) -> None: if self.default not in (unspecified, None): fail("The only legal default value for Py_buffer is None.") @@ -3741,7 +3745,7 @@ def cleanup(self): name = self.name return "".join(["if (", name, ".obj) {\n PyBuffer_Release(&", name, ");\n}\n"]) - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str) -> str: if self.format_unit == 'y*': return """ if (PyObject_GetBuffer({argname}, &{paramname}, PyBUF_SIMPLE) != 0) {{{{ @@ -3790,7 +3794,7 @@ def parse_arg(self, argname, displayname): return super().parse_arg(argname, displayname) -def correct_name_for_self(f): +def correct_name_for_self(f) -> tuple[str, str]: if f.kind in (CALLABLE, METHOD_INIT): if f.cls: return "PyObject *", "self" @@ -3816,7 +3820,7 @@ class self_converter(CConverter): type = None format_unit = '' - def converter_init(self, *, type=None): + def converter_init(self, *, type=None) -> None: self.specified_type = type def pre_render(self): From webhook-mailer at python.org Tue May 16 19:35:14 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 16 May 2023 23:35:14 -0000 Subject: [Python-checkins] GH-103092: isolate `_elementtree` (#104561) Message-ID: <mailman.400.1684280115.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1b5a2b085c28d230c9ef9bd9b472afc85e087ced commit: 1b5a2b085c28d230c9ef9bd9b472afc85e087ced branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-17T05:05:07+05:30 summary: GH-103092: isolate `_elementtree` (#104561) files: M Modules/_elementtree.c diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 42de3c675c2e..00d9f647ccfd 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -15,6 +15,8 @@ #include "Python.h" #include "structmember.h" // PyMemberDef +#include "expat.h" +#include "pyexpat.h" /* -------------------------------------------------------------------- */ /* configuration */ @@ -90,6 +92,8 @@ typedef struct { PyTypeObject *ElementIter_Type; PyTypeObject *TreeBuilder_Type; PyTypeObject *XMLParser_Type; + + struct PyExpat_CAPI *expat_capi; } elementtreestate; static struct PyModuleDef elementtreemodule; @@ -146,6 +150,8 @@ elementtree_clear(PyObject *m) Py_CLEAR(st->ElementIter_Type); Py_CLEAR(st->TreeBuilder_Type); Py_CLEAR(st->XMLParser_Type); + + st->expat_capi = NULL; return 0; } @@ -3031,14 +3037,7 @@ _elementtree_TreeBuilder_start_impl(TreeBuilderObject *self, PyObject *tag, /* ==================================================================== */ /* the expat interface */ -#include "expat.h" -#include "pyexpat.h" - -/* The PyExpat_CAPI structure is an immutable dispatch table, so it can be - * cached globally without being in per-module state. - */ -static struct PyExpat_CAPI *expat_capi; -#define EXPAT(func) (expat_capi->func) +#define EXPAT(st, func) ((st)->expat_capi->func) static XML_Memory_Handling_Suite ExpatMemoryHandler = { PyObject_Malloc, PyObject_Realloc, PyObject_Free}; @@ -3147,7 +3146,7 @@ expat_set_error(elementtreestate *st, enum XML_Error error_code, PyObject *errmsg, *error, *position, *code; errmsg = PyUnicode_FromFormat("%s: line %zd, column %zd", - message ? message : EXPAT(ErrorString)(error_code), + message ? message : EXPAT(st, ErrorString)(error_code), line, column); if (errmsg == NULL) return; @@ -3227,8 +3226,8 @@ expat_default_handler(XMLParserObject* self, const XML_Char* data_in, expat_set_error( st, XML_ERROR_UNDEFINED_ENTITY, - EXPAT(GetErrorLineNumber)(self->parser), - EXPAT(GetErrorColumnNumber)(self->parser), + EXPAT(st, GetErrorLineNumber)(self->parser), + EXPAT(st, GetErrorColumnNumber)(self->parser), message ); } @@ -3648,8 +3647,8 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, Py_CLEAR(self->entity); return -1; } - - self->parser = EXPAT(ParserCreate_MM)(encoding, &ExpatMemoryHandler, "}"); + elementtreestate *st = self->state; + self->parser = EXPAT(st, ParserCreate_MM)(encoding, &ExpatMemoryHandler, "}"); if (!self->parser) { Py_CLEAR(self->entity); Py_CLEAR(self->names); @@ -3657,15 +3656,14 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, return -1; } /* expat < 2.1.0 has no XML_SetHashSalt() */ - if (EXPAT(SetHashSalt) != NULL) { - EXPAT(SetHashSalt)(self->parser, + if (EXPAT(st, SetHashSalt) != NULL) { + EXPAT(st, SetHashSalt)(self->parser, (unsigned long)_Py_HashSecret.expat.hashsalt); } if (target != Py_None) { Py_INCREF(target); } else { - elementtreestate *st = self->state; target = treebuilder_new(st->TreeBuilder_Type, NULL, NULL); if (!target) { Py_CLEAR(self->entity); @@ -3713,43 +3711,43 @@ _elementtree_XMLParser___init___impl(XMLParserObject *self, PyObject *target, } /* configure parser */ - EXPAT(SetUserData)(self->parser, self); + EXPAT(st, SetUserData)(self->parser, self); if (self->handle_start_ns || self->handle_end_ns) - EXPAT(SetNamespaceDeclHandler)( + EXPAT(st, SetNamespaceDeclHandler)( self->parser, (XML_StartNamespaceDeclHandler) expat_start_ns_handler, (XML_EndNamespaceDeclHandler) expat_end_ns_handler ); - EXPAT(SetElementHandler)( + EXPAT(st, SetElementHandler)( self->parser, (XML_StartElementHandler) expat_start_handler, (XML_EndElementHandler) expat_end_handler ); - EXPAT(SetDefaultHandlerExpand)( + EXPAT(st, SetDefaultHandlerExpand)( self->parser, (XML_DefaultHandler) expat_default_handler ); - EXPAT(SetCharacterDataHandler)( + EXPAT(st, SetCharacterDataHandler)( self->parser, (XML_CharacterDataHandler) expat_data_handler ); if (self->handle_comment) - EXPAT(SetCommentHandler)( + EXPAT(st, SetCommentHandler)( self->parser, (XML_CommentHandler) expat_comment_handler ); if (self->handle_pi) - EXPAT(SetProcessingInstructionHandler)( + EXPAT(st, SetProcessingInstructionHandler)( self->parser, (XML_ProcessingInstructionHandler) expat_pi_handler ); - EXPAT(SetStartDoctypeDeclHandler)( + EXPAT(st, SetStartDoctypeDeclHandler)( self->parser, (XML_StartDoctypeDeclHandler) expat_start_doctype_handler ); - EXPAT(SetUnknownEncodingHandler)( + EXPAT(st, SetUnknownEncodingHandler)( self->parser, - EXPAT(DefaultUnknownEncodingHandler), NULL + EXPAT(st, DefaultUnknownEncodingHandler), NULL ); return 0; @@ -3779,10 +3777,11 @@ xmlparser_gc_traverse(XMLParserObject *self, visitproc visit, void *arg) static int xmlparser_gc_clear(XMLParserObject *self) { + elementtreestate *st = self->state; if (self->parser != NULL) { XML_Parser parser = self->parser; self->parser = NULL; - EXPAT(ParserFree)(parser); + EXPAT(st, ParserFree)(parser); } Py_CLEAR(self->handle_close); @@ -3830,7 +3829,7 @@ expat_parse(elementtreestate *st, XMLParserObject *self, const char *data, int ok; assert(!PyErr_Occurred()); - ok = EXPAT(Parse)(self->parser, data, data_len, final); + ok = EXPAT(st, Parse)(self->parser, data, data_len, final); if (PyErr_Occurred()) return NULL; @@ -3838,9 +3837,9 @@ expat_parse(elementtreestate *st, XMLParserObject *self, const char *data, if (!ok) { expat_set_error( st, - EXPAT(GetErrorCode)(self->parser), - EXPAT(GetErrorLineNumber)(self->parser), - EXPAT(GetErrorColumnNumber)(self->parser), + EXPAT(st, GetErrorCode)(self->parser), + EXPAT(st, GetErrorLineNumber)(self->parser), + EXPAT(st, GetErrorColumnNumber)(self->parser), NULL ); return NULL; @@ -3911,7 +3910,7 @@ _elementtree_XMLParser_feed(XMLParserObject *self, PyObject *data) return NULL; } /* Explicitly set UTF-8 encoding. Return code ignored. */ - (void)EXPAT(SetEncoding)(self->parser, "utf-8"); + (void)EXPAT(st, SetEncoding)(self->parser, "utf-8"); return expat_parse(st, self, data_ptr, (int)data_len, 0); } @@ -4099,27 +4098,27 @@ _elementtree_XMLParser__setevents_impl(XMLParserObject *self, Py_XSETREF(target->end_event_obj, Py_NewRef(event_name_obj)); } else if (strcmp(event_name, "start-ns") == 0) { Py_XSETREF(target->start_ns_event_obj, Py_NewRef(event_name_obj)); - EXPAT(SetNamespaceDeclHandler)( + EXPAT(st, SetNamespaceDeclHandler)( self->parser, (XML_StartNamespaceDeclHandler) expat_start_ns_handler, (XML_EndNamespaceDeclHandler) expat_end_ns_handler ); } else if (strcmp(event_name, "end-ns") == 0) { Py_XSETREF(target->end_ns_event_obj, Py_NewRef(event_name_obj)); - EXPAT(SetNamespaceDeclHandler)( + EXPAT(st, SetNamespaceDeclHandler)( self->parser, (XML_StartNamespaceDeclHandler) expat_start_ns_handler, (XML_EndNamespaceDeclHandler) expat_end_ns_handler ); } else if (strcmp(event_name, "comment") == 0) { Py_XSETREF(target->comment_event_obj, Py_NewRef(event_name_obj)); - EXPAT(SetCommentHandler)( + EXPAT(st, SetCommentHandler)( self->parser, (XML_CommentHandler) expat_comment_handler ); } else if (strcmp(event_name, "pi") == 0) { Py_XSETREF(target->pi_event_obj, Py_NewRef(event_name_obj)); - EXPAT(SetProcessingInstructionHandler)( + EXPAT(st, SetProcessingInstructionHandler)( self->parser, (XML_ProcessingInstructionHandler) expat_pi_handler ); @@ -4344,14 +4343,14 @@ module_exec(PyObject *m) goto error; /* link against pyexpat */ - expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0); - if (expat_capi) { + st->expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0); + if (st->expat_capi) { /* check that it's usable */ - if (strcmp(expat_capi->magic, PyExpat_CAPI_MAGIC) != 0 || - (size_t)expat_capi->size < sizeof(struct PyExpat_CAPI) || - expat_capi->MAJOR_VERSION != XML_MAJOR_VERSION || - expat_capi->MINOR_VERSION != XML_MINOR_VERSION || - expat_capi->MICRO_VERSION != XML_MICRO_VERSION) { + if (strcmp(st->expat_capi->magic, PyExpat_CAPI_MAGIC) != 0 || + (size_t)st->expat_capi->size < sizeof(struct PyExpat_CAPI) || + st->expat_capi->MAJOR_VERSION != XML_MAJOR_VERSION || + st->expat_capi->MINOR_VERSION != XML_MINOR_VERSION || + st->expat_capi->MICRO_VERSION != XML_MICRO_VERSION) { PyErr_SetString(PyExc_ImportError, "pyexpat version is incompatible"); goto error; From webhook-mailer at python.org Tue May 16 20:04:14 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 17 May 2023 00:04:14 -0000 Subject: [Python-checkins] [3.11] gh-104494: Update certain Tkinter pack/place tests for Tk 8.7 errors (GH-104495) (#104569) Message-ID: <mailman.401.1684281856.13550.python-checkins@python.org> https://github.com/python/cpython/commit/dece9c06bb0aff150e018ed7975d43e4648bb72e commit: dece9c06bb0aff150e018ed7975d43e4648bb72e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-16T20:03:51-04:00 summary: [3.11] gh-104494: Update certain Tkinter pack/place tests for Tk 8.7 errors (GH-104495) (#104569) gh-104494: Update certain Tkinter pack/place tests for Tk 8.7 errors (GH-104495) (cherry picked from commit 3cba61f111db9b5e8ef35632915309f81fff8c6c) Co-authored-by: Christopher Chavez <chrischavez at gmx.us> Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst M Lib/tkinter/test/test_tkinter/test_geometry_managers.py diff --git a/Lib/tkinter/test/test_tkinter/test_geometry_managers.py b/Lib/tkinter/test/test_tkinter/test_geometry_managers.py index c89bc8dbf857..0c31e3661269 100644 --- a/Lib/tkinter/test/test_tkinter/test_geometry_managers.py +++ b/Lib/tkinter/test/test_tkinter/test_geometry_managers.py @@ -108,8 +108,8 @@ def test_pack_configure_in(self): a.pack_configure(in_=c) self.assertEqual(pack.pack_slaves(), [b, c, d]) self.assertEqual(c.pack_slaves(), [a]) - with self.assertRaisesRegex(TclError, - 'can\'t pack %s inside itself' % (a,)): + with self.assertRaisesRegex( + TclError, """can't pack "?%s"? inside itself""" % (a,)): a.pack_configure(in_=a) with self.assertRaisesRegex(TclError, 'bad window path name ".foo"'): a.pack_configure(in_='.foo') @@ -292,8 +292,10 @@ def create2(self): def test_place_configure_in(self): t, f, f2 = self.create2() self.assertEqual(f2.winfo_manager(), '') - with self.assertRaisesRegex(TclError, "can't place %s relative to " - "itself" % re.escape(str(f2))): + with self.assertRaisesRegex( + TclError, + """can't place "?%s"? relative to itself""" + % re.escape(str(f2))): f2.place_configure(in_=f2) self.assertEqual(f2.winfo_manager(), '') with self.assertRaisesRegex(TclError, 'bad window path name'): diff --git a/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst b/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst new file mode 100644 index 000000000000..a320c48428b5 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst @@ -0,0 +1,2 @@ +Update ``test_pack_configure_in`` and ``test_place_configure_in`` +for changes to error message formatting in Tk 8.7. From webhook-mailer at python.org Tue May 16 23:56:58 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 17 May 2023 03:56:58 -0000 Subject: [Python-checkins] gh-104469: Update README.txt for _testcapi (gh-104529) Message-ID: <mailman.402.1684295819.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b58bc8c2a9a316891a5ea1a0487aebfc86c2793a commit: b58bc8c2a9a316891a5ea1a0487aebfc86c2793a branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-17T12:56:20+09:00 summary: gh-104469: Update README.txt for _testcapi (gh-104529) * gh-104469: Update README.txt for _testcapi Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> Co-authored-by: Kirill Podoprigora <kirill.bast9 at mail.ru> files: M Modules/_testcapi/README.txt diff --git a/Modules/_testcapi/README.txt b/Modules/_testcapi/README.txt index 134b6efc6380..8a65e7abf770 100644 --- a/Modules/_testcapi/README.txt +++ b/Modules/_testcapi/README.txt @@ -1,3 +1,10 @@ Tests in this directory are compiled into the _testcapi extension. The main file for the extension is Modules/_testcapimodule.c, which calls `_PyTestCapi_Init_*` from these functions. + +General guideline when writing test code for C API. +* Use Argument Clinic to minimise the amount of boilerplate code. +* Add a newline between the argument spec and the docstring. +* If a test description is needed, make sure the added docstring clearly and succinctly describes purpose of the function. +* DRY, use the clone feature of Argument Clinic. +* Try to avoid adding new interned strings; reuse existing parameter names if possible. Use the `as` feature of Argument Clinic to override the C variable name, if needed. From webhook-mailer at python.org Wed May 17 03:48:27 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 17 May 2023 07:48:27 -0000 Subject: [Python-checkins] [3.11] gh-87474: Fix file descriptor leaks in subprocess.Popen (GH-96351) (#104563) Message-ID: <mailman.403.1684309708.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3ce7d57c8aef98f599bb55d67585a8150ce6d775 commit: 3ce7d57c8aef98f599bb55d67585a8150ce6d775 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-17T00:48:10-07:00 summary: [3.11] gh-87474: Fix file descriptor leaks in subprocess.Popen (GH-96351) (#104563) gh-87474: Fix file descriptor leaks in subprocess.Popen (GH-96351) This fixes several ways file descriptors could be leaked from `subprocess.Popen` constructor during error conditions by opening them later and using a context manager "fds to close" registration scheme to ensure they get closed before returning. --------- (cherry picked from commit 3a4c44bb1e92802db64deec59cf8a68ad3973219) Co-authored-by: cptpcrd <31829097+cptpcrd at users.noreply.github.com> Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst M Lib/subprocess.py diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 1f203bd00d35..fbc76b8d0f14 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -872,37 +872,6 @@ def __init__(self, args, bufsize=-1, executable=None, 'and universal_newlines are supplied but ' 'different. Pass one or the other.') - # Input and output objects. The general principle is like - # this: - # - # Parent Child - # ------ ----- - # p2cwrite ---stdin---> p2cread - # c2pread <--stdout--- c2pwrite - # errread <--stderr--- errwrite - # - # On POSIX, the child objects are file descriptors. On - # Windows, these are Windows file handles. The parent objects - # are file descriptors on both platforms. The parent objects - # are -1 when not using PIPEs. The child objects are -1 - # when not redirecting. - - (p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite) = self._get_handles(stdin, stdout, stderr) - - # We wrap OS handles *before* launching the child, otherwise a - # quickly terminating child could make our fds unwrappable - # (see #8458). - - if _mswindows: - if p2cwrite != -1: - p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) - if c2pread != -1: - c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) - if errread != -1: - errread = msvcrt.open_osfhandle(errread.Detach(), 0) - self.text_mode = encoding or errors or text or universal_newlines if self.text_mode and encoding is None: self.encoding = encoding = _text_encoding() @@ -1003,6 +972,39 @@ def __init__(self, args, bufsize=-1, executable=None, if uid < 0: raise ValueError(f"User ID cannot be negative, got {uid}") + # Input and output objects. The general principle is like + # this: + # + # Parent Child + # ------ ----- + # p2cwrite ---stdin---> p2cread + # c2pread <--stdout--- c2pwrite + # errread <--stderr--- errwrite + # + # On POSIX, the child objects are file descriptors. On + # Windows, these are Windows file handles. The parent objects + # are file descriptors on both platforms. The parent objects + # are -1 when not using PIPEs. The child objects are -1 + # when not redirecting. + + (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) = self._get_handles(stdin, stdout, stderr) + + # From here on, raising exceptions may cause file descriptor leakage + + # We wrap OS handles *before* launching the child, otherwise a + # quickly terminating child could make our fds unwrappable + # (see #8458). + + if _mswindows: + if p2cwrite != -1: + p2cwrite = msvcrt.open_osfhandle(p2cwrite.Detach(), 0) + if c2pread != -1: + c2pread = msvcrt.open_osfhandle(c2pread.Detach(), 0) + if errread != -1: + errread = msvcrt.open_osfhandle(errread.Detach(), 0) + try: if p2cwrite != -1: self.stdin = io.open(p2cwrite, 'wb', bufsize) @@ -1306,6 +1308,26 @@ def _close_pipe_fds(self, # Prevent a double close of these handles/fds from __init__ on error. self._closed_child_pipe_fds = True + @contextlib.contextmanager + def _on_error_fd_closer(self): + """Helper to ensure file descriptors opened in _get_handles are closed""" + to_close = [] + try: + yield to_close + except: + if hasattr(self, '_devnull'): + to_close.append(self._devnull) + del self._devnull + for fd in to_close: + try: + if _mswindows and isinstance(fd, Handle): + fd.Close() + else: + os.close(fd) + except OSError: + pass + raise + if _mswindows: # # Windows methods @@ -1321,61 +1343,68 @@ def _get_handles(self, stdin, stdout, stderr): c2pread, c2pwrite = -1, -1 errread, errwrite = -1, -1 - if stdin is None: - p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE) - if p2cread is None: - p2cread, _ = _winapi.CreatePipe(None, 0) - p2cread = Handle(p2cread) - _winapi.CloseHandle(_) - elif stdin == PIPE: - p2cread, p2cwrite = _winapi.CreatePipe(None, 0) - p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite) - elif stdin == DEVNULL: - p2cread = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stdin, int): - p2cread = msvcrt.get_osfhandle(stdin) - else: - # Assuming file-like object - p2cread = msvcrt.get_osfhandle(stdin.fileno()) - p2cread = self._make_inheritable(p2cread) - - if stdout is None: - c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE) - if c2pwrite is None: - _, c2pwrite = _winapi.CreatePipe(None, 0) - c2pwrite = Handle(c2pwrite) - _winapi.CloseHandle(_) - elif stdout == PIPE: - c2pread, c2pwrite = _winapi.CreatePipe(None, 0) - c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite) - elif stdout == DEVNULL: - c2pwrite = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stdout, int): - c2pwrite = msvcrt.get_osfhandle(stdout) - else: - # Assuming file-like object - c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) - c2pwrite = self._make_inheritable(c2pwrite) - - if stderr is None: - errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE) - if errwrite is None: - _, errwrite = _winapi.CreatePipe(None, 0) - errwrite = Handle(errwrite) - _winapi.CloseHandle(_) - elif stderr == PIPE: - errread, errwrite = _winapi.CreatePipe(None, 0) - errread, errwrite = Handle(errread), Handle(errwrite) - elif stderr == STDOUT: - errwrite = c2pwrite - elif stderr == DEVNULL: - errwrite = msvcrt.get_osfhandle(self._get_devnull()) - elif isinstance(stderr, int): - errwrite = msvcrt.get_osfhandle(stderr) - else: - # Assuming file-like object - errwrite = msvcrt.get_osfhandle(stderr.fileno()) - errwrite = self._make_inheritable(errwrite) + with self._on_error_fd_closer() as err_close_fds: + if stdin is None: + p2cread = _winapi.GetStdHandle(_winapi.STD_INPUT_HANDLE) + if p2cread is None: + p2cread, _ = _winapi.CreatePipe(None, 0) + p2cread = Handle(p2cread) + err_close_fds.append(p2cread) + _winapi.CloseHandle(_) + elif stdin == PIPE: + p2cread, p2cwrite = _winapi.CreatePipe(None, 0) + p2cread, p2cwrite = Handle(p2cread), Handle(p2cwrite) + err_close_fds.extend((p2cread, p2cwrite)) + elif stdin == DEVNULL: + p2cread = msvcrt.get_osfhandle(self._get_devnull()) + elif isinstance(stdin, int): + p2cread = msvcrt.get_osfhandle(stdin) + else: + # Assuming file-like object + p2cread = msvcrt.get_osfhandle(stdin.fileno()) + p2cread = self._make_inheritable(p2cread) + + if stdout is None: + c2pwrite = _winapi.GetStdHandle(_winapi.STD_OUTPUT_HANDLE) + if c2pwrite is None: + _, c2pwrite = _winapi.CreatePipe(None, 0) + c2pwrite = Handle(c2pwrite) + err_close_fds.append(c2pwrite) + _winapi.CloseHandle(_) + elif stdout == PIPE: + c2pread, c2pwrite = _winapi.CreatePipe(None, 0) + c2pread, c2pwrite = Handle(c2pread), Handle(c2pwrite) + err_close_fds.extend((c2pread, c2pwrite)) + elif stdout == DEVNULL: + c2pwrite = msvcrt.get_osfhandle(self._get_devnull()) + elif isinstance(stdout, int): + c2pwrite = msvcrt.get_osfhandle(stdout) + else: + # Assuming file-like object + c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) + c2pwrite = self._make_inheritable(c2pwrite) + + if stderr is None: + errwrite = _winapi.GetStdHandle(_winapi.STD_ERROR_HANDLE) + if errwrite is None: + _, errwrite = _winapi.CreatePipe(None, 0) + errwrite = Handle(errwrite) + err_close_fds.append(errwrite) + _winapi.CloseHandle(_) + elif stderr == PIPE: + errread, errwrite = _winapi.CreatePipe(None, 0) + errread, errwrite = Handle(errread), Handle(errwrite) + err_close_fds.extend((errread, errwrite)) + elif stderr == STDOUT: + errwrite = c2pwrite + elif stderr == DEVNULL: + errwrite = msvcrt.get_osfhandle(self._get_devnull()) + elif isinstance(stderr, int): + errwrite = msvcrt.get_osfhandle(stderr) + else: + # Assuming file-like object + errwrite = msvcrt.get_osfhandle(stderr.fileno()) + errwrite = self._make_inheritable(errwrite) return (p2cread, p2cwrite, c2pread, c2pwrite, @@ -1662,52 +1691,56 @@ def _get_handles(self, stdin, stdout, stderr): c2pread, c2pwrite = -1, -1 errread, errwrite = -1, -1 - if stdin is None: - pass - elif stdin == PIPE: - p2cread, p2cwrite = os.pipe() - if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): - fcntl.fcntl(p2cwrite, fcntl.F_SETPIPE_SZ, self.pipesize) - elif stdin == DEVNULL: - p2cread = self._get_devnull() - elif isinstance(stdin, int): - p2cread = stdin - else: - # Assuming file-like object - p2cread = stdin.fileno() + with self._on_error_fd_closer() as err_close_fds: + if stdin is None: + pass + elif stdin == PIPE: + p2cread, p2cwrite = os.pipe() + err_close_fds.extend((p2cread, p2cwrite)) + if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): + fcntl.fcntl(p2cwrite, fcntl.F_SETPIPE_SZ, self.pipesize) + elif stdin == DEVNULL: + p2cread = self._get_devnull() + elif isinstance(stdin, int): + p2cread = stdin + else: + # Assuming file-like object + p2cread = stdin.fileno() - if stdout is None: - pass - elif stdout == PIPE: - c2pread, c2pwrite = os.pipe() - if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): - fcntl.fcntl(c2pwrite, fcntl.F_SETPIPE_SZ, self.pipesize) - elif stdout == DEVNULL: - c2pwrite = self._get_devnull() - elif isinstance(stdout, int): - c2pwrite = stdout - else: - # Assuming file-like object - c2pwrite = stdout.fileno() + if stdout is None: + pass + elif stdout == PIPE: + c2pread, c2pwrite = os.pipe() + err_close_fds.extend((c2pread, c2pwrite)) + if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): + fcntl.fcntl(c2pwrite, fcntl.F_SETPIPE_SZ, self.pipesize) + elif stdout == DEVNULL: + c2pwrite = self._get_devnull() + elif isinstance(stdout, int): + c2pwrite = stdout + else: + # Assuming file-like object + c2pwrite = stdout.fileno() - if stderr is None: - pass - elif stderr == PIPE: - errread, errwrite = os.pipe() - if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): - fcntl.fcntl(errwrite, fcntl.F_SETPIPE_SZ, self.pipesize) - elif stderr == STDOUT: - if c2pwrite != -1: - errwrite = c2pwrite - else: # child's stdout is not set, use parent's stdout - errwrite = sys.__stdout__.fileno() - elif stderr == DEVNULL: - errwrite = self._get_devnull() - elif isinstance(stderr, int): - errwrite = stderr - else: - # Assuming file-like object - errwrite = stderr.fileno() + if stderr is None: + pass + elif stderr == PIPE: + errread, errwrite = os.pipe() + err_close_fds.extend((errread, errwrite)) + if self.pipesize > 0 and hasattr(fcntl, "F_SETPIPE_SZ"): + fcntl.fcntl(errwrite, fcntl.F_SETPIPE_SZ, self.pipesize) + elif stderr == STDOUT: + if c2pwrite != -1: + errwrite = c2pwrite + else: # child's stdout is not set, use parent's stdout + errwrite = sys.__stdout__.fileno() + elif stderr == DEVNULL: + errwrite = self._get_devnull() + elif isinstance(stderr, int): + errwrite = stderr + else: + # Assuming file-like object + errwrite = stderr.fileno() return (p2cread, p2cwrite, c2pread, c2pwrite, diff --git a/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst b/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst new file mode 100644 index 000000000000..eeb5308680e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst @@ -0,0 +1 @@ +Fix potential file descriptor leaks in :class:`subprocess.Popen`. From webhook-mailer at python.org Wed May 17 04:07:18 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 17 May 2023 08:07:18 -0000 Subject: [Python-checkins] [3.11] gh-103861: Fix Zip64 extensions not being properly applied in some cases (GH-103863) (#104534) Message-ID: <mailman.404.1684310838.13550.python-checkins@python.org> https://github.com/python/cpython/commit/133bf0927e9cb07d4a5a3ca31791ce18da22707b commit: 133bf0927e9cb07d4a5a3ca31791ce18da22707b branch: 3.11 author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-17T01:07:10-07:00 summary: [3.11] gh-103861: Fix Zip64 extensions not being properly applied in some cases (GH-103863) (#104534) Fix Zip64 extensions not being properly applied in some cases: Fixes an issue where adding a small file to a `ZipFile` object while forcing zip64 extensions causes an extra Zip64 record to be added to the zip, but doesn't update the `min_version` or file sizes in the primary central directory header. Also fixed an edge case in checking if zip64 extensions are required: This fixes an issue where if data requiring zip64 extensions was added to an unseekable stream without specifying `force_zip64=True`, zip64 extensions would not be used and a RuntimeError would not be raised when closing the file (even though the size would be known at that point). This would result in successfully writing corrupt zip files. Deciding if zip64 extensions are required outside of the `FileHeader` function means that both `FileHeader` and `_ZipWriteFile` will always be in sync. Previously, the `FileHeader` function could enable zip64 extensions without propagating that decision to the `_ZipWriteFile` class, which would then not correctly write the data descriptor record or check for errors on close. If anyone is actually using `ZipInfo.FileHeader` as a public API without explicitly passing True or False in for zip64, their own code may still be susceptible to that kind of bug unless they make a similar change to where the zip64 decision happens. Fixes GH-103861 --------- . (cherry picked from commit 798bcaa1eb01de7db9ff1881a3088603ad09b096) Co-authored-by: Carey Metcalfe <carey at cmetcalfe.ca> files: A Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst M Lib/test/test_zipfile.py M Lib/zipfile.py diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index ffb954659e42..bb2c24c8c50c 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -1082,6 +1082,159 @@ def test_generated_valid_zip64_extra(self): self.assertEqual(zinfo.header_offset, expected_header_offset) self.assertEqual(zf.read(zinfo), expected_content) + def test_force_zip64(self): + """Test that forcing zip64 extensions correctly notes this in the zip file""" + + # GH-103861 describes an issue where forcing a small file to use zip64 + # extensions would add a zip64 extra record, but not change the data + # sizes to 0xFFFFFFFF to indicate to the extractor that the zip64 + # record should be read. Additionally, it would not set the required + # version to indicate that zip64 extensions are required to extract it. + # This test replicates the situation and reads the raw data to specifically ensure: + # - The required extract version is always >= ZIP64_VERSION + # - The compressed and uncompressed size in the file headers are both + # 0xFFFFFFFF (ie. point to zip64 record) + # - The zip64 record is provided and has the correct sizes in it + # Other aspects of the zip are checked as well, but verifying the above is the main goal. + # Because this is hard to verify by parsing the data as a zip, the raw + # bytes are checked to ensure that they line up with the zip spec. + # The spec for this can be found at: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + # The relevent sections for this test are: + # - 4.3.7 for local file header + # - 4.5.3 for zip64 extra field + + data = io.BytesIO() + with zipfile.ZipFile(data, mode="w", allowZip64=True) as zf: + with zf.open("text.txt", mode="w", force_zip64=True) as zi: + zi.write(b"_") + + zipdata = data.getvalue() + + # pull out and check zip information + ( + header, vers, os, flags, comp, csize, usize, fn_len, + ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize, cd_sig + ) = struct.unpack("<4sBBHH8xIIHH8shhQQx4s", zipdata[:63]) + + self.assertEqual(header, b"PK\x03\x04") # local file header + self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract + self.assertEqual(os, 0) # compatible with MS-DOS + self.assertEqual(flags, 0) # no flags + self.assertEqual(comp, 0) # compression method = stored + self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra + self.assertEqual(usize, 0xFFFFFFFF) + self.assertEqual(fn_len, 8) # filename len + self.assertEqual(ex_total_len, 20) # size of extra records + self.assertEqual(ex_id, 1) # Zip64 extra record + self.assertEqual(ex_len, 16) # 16 bytes of data + self.assertEqual(ex_usize, 1) # uncompressed size + self.assertEqual(ex_csize, 1) # compressed size + self.assertEqual(cd_sig, b"PK\x01\x02") # ensure the central directory header is next + + z = zipfile.ZipFile(io.BytesIO(zipdata)) + zinfos = z.infolist() + self.assertEqual(len(zinfos), 1) + self.assertGreaterEqual(zinfos[0].extract_version, zipfile.ZIP64_VERSION) # requires zip64 to extract + + def test_unseekable_zip_unknown_filesize(self): + """Test that creating a zip with/without seeking will raise a RuntimeError if zip64 was required but not used""" + + def make_zip(fp): + with zipfile.ZipFile(fp, mode="w", allowZip64=True) as zf: + with zf.open("text.txt", mode="w", force_zip64=False) as zi: + zi.write(b"_" * (zipfile.ZIP64_LIMIT + 1)) + + self.assertRaises(RuntimeError, make_zip, io.BytesIO()) + self.assertRaises(RuntimeError, make_zip, Unseekable(io.BytesIO())) + + def test_zip64_required_not_allowed_fail(self): + """Test that trying to add a large file to a zip that doesn't allow zip64 extensions fails on add""" + def make_zip(fp): + with zipfile.ZipFile(fp, mode="w", allowZip64=False) as zf: + # pretend zipfile.ZipInfo.from_file was used to get the name and filesize + info = zipfile.ZipInfo("text.txt") + info.file_size = zipfile.ZIP64_LIMIT + 1 + zf.open(info, mode="w") + + self.assertRaises(zipfile.LargeZipFile, make_zip, io.BytesIO()) + self.assertRaises(zipfile.LargeZipFile, make_zip, Unseekable(io.BytesIO())) + + def test_unseekable_zip_known_filesize(self): + """Test that creating a zip without seeking will use zip64 extensions if the file size is provided up-front""" + + # This test ensures that the zip will use a zip64 data descriptor (same + # as a regular data descriptor except the sizes are 8 bytes instead of + # 4) record to communicate the size of a file if the zip is being + # written to an unseekable stream. + # Because this sort of thing is hard to verify by parsing the data back + # in as a zip, this test looks at the raw bytes created to ensure that + # the correct data has been generated. + # The spec for this can be found at: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + # The relevent sections for this test are: + # - 4.3.7 for local file header + # - 4.3.9 for the data descriptor + # - 4.5.3 for zip64 extra field + + file_size = zipfile.ZIP64_LIMIT + 1 + + def make_zip(fp): + with zipfile.ZipFile(fp, mode="w", allowZip64=True) as zf: + # pretend zipfile.ZipInfo.from_file was used to get the name and filesize + info = zipfile.ZipInfo("text.txt") + info.file_size = file_size + with zf.open(info, mode="w", force_zip64=False) as zi: + zi.write(b"_" * file_size) + return fp + + # check seekable file information + seekable_data = make_zip(io.BytesIO()).getvalue() + ( + header, vers, os, flags, comp, csize, usize, fn_len, + ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize, + cd_sig + ) = struct.unpack("<4sBBHH8xIIHH8shhQQ{}x4s".format(file_size), seekable_data[:62 + file_size]) + + self.assertEqual(header, b"PK\x03\x04") # local file header + self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract + self.assertEqual(os, 0) # compatible with MS-DOS + self.assertEqual(flags, 0) # no flags set + self.assertEqual(comp, 0) # compression method = stored + self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra + self.assertEqual(usize, 0xFFFFFFFF) + self.assertEqual(fn_len, 8) # filename len + self.assertEqual(ex_total_len, 20) # size of extra records + self.assertEqual(ex_id, 1) # Zip64 extra record + self.assertEqual(ex_len, 16) # 16 bytes of data + self.assertEqual(ex_usize, file_size) # uncompressed size + self.assertEqual(ex_csize, file_size) # compressed size + self.assertEqual(cd_sig, b"PK\x01\x02") # ensure the central directory header is next + + # check unseekable file information + unseekable_data = make_zip(Unseekable(io.BytesIO())).fp.getvalue() + ( + header, vers, os, flags, comp, csize, usize, fn_len, + ex_total_len, filename, ex_id, ex_len, ex_usize, ex_csize, + dd_header, dd_usize, dd_csize, cd_sig + ) = struct.unpack("<4sBBHH8xIIHH8shhQQ{}x4s4xQQ4s".format(file_size), unseekable_data[:86 + file_size]) + + self.assertEqual(header, b"PK\x03\x04") # local file header + self.assertGreaterEqual(vers, zipfile.ZIP64_VERSION) # requires zip64 to extract + self.assertEqual(os, 0) # compatible with MS-DOS + self.assertEqual("{:b}".format(flags), "1000") # streaming flag set + self.assertEqual(comp, 0) # compression method = stored + self.assertEqual(csize, 0xFFFFFFFF) # sizes are in zip64 extra + self.assertEqual(usize, 0xFFFFFFFF) + self.assertEqual(fn_len, 8) # filename len + self.assertEqual(ex_total_len, 20) # size of extra records + self.assertEqual(ex_id, 1) # Zip64 extra record + self.assertEqual(ex_len, 16) # 16 bytes of data + self.assertEqual(ex_usize, 0) # uncompressed size - 0 to defer to data descriptor + self.assertEqual(ex_csize, 0) # compressed size - 0 to defer to data descriptor + self.assertEqual(dd_header, b"PK\07\x08") # data descriptor + self.assertEqual(dd_usize, file_size) # file size (8 bytes because zip64) + self.assertEqual(dd_csize, file_size) # compressed size (8 bytes because zip64) + self.assertEqual(cd_sig, b"PK\x01\x02") # ensure the central directory header is next + @requires_zlib() class DeflateTestZip64InSmallFiles(AbstractTestZip64InSmallFiles, diff --git a/Lib/zipfile.py b/Lib/zipfile.py index f14a638d40c5..1dec6a8b97bc 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -435,7 +435,12 @@ def __repr__(self): return ''.join(result) def FileHeader(self, zip64=None): - """Return the per-file header as a bytes object.""" + """Return the per-file header as a bytes object. + + When the optional zip64 arg is None rather than a bool, we will + decide based upon the file_size and compress_size, if known, + False otherwise. + """ dt = self.date_time dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2) @@ -451,16 +456,13 @@ def FileHeader(self, zip64=None): min_version = 0 if zip64 is None: + # We always explicitly pass zip64 within this module.... This + # remains for anyone using ZipInfo.FileHeader as a public API. zip64 = file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT if zip64: fmt = '<HHQQ' extra = extra + struct.pack(fmt, 1, struct.calcsize(fmt)-4, file_size, compress_size) - if file_size > ZIP64_LIMIT or compress_size > ZIP64_LIMIT: - if not zip64: - raise LargeZipFile("Filesize would require ZIP64 extensions") - # File is larger than what fits into a 4 byte integer, - # fall back to the ZIP64 extension file_size = 0xffffffff compress_size = 0xffffffff min_version = ZIP64_VERSION @@ -1183,6 +1185,12 @@ def close(self): self._zinfo.CRC = self._crc self._zinfo.file_size = self._file_size + if not self._zip64: + if self._file_size > ZIP64_LIMIT: + raise RuntimeError("File size too large, try using force_zip64") + if self._compress_size > ZIP64_LIMIT: + raise RuntimeError("Compressed size too large, try using force_zip64") + # Write updated header info if self._zinfo.flag_bits & _MASK_USE_DATA_DESCRIPTOR: # Write CRC and file sizes after the file data @@ -1191,13 +1199,6 @@ def close(self): self._zinfo.compress_size, self._zinfo.file_size)) self._zipfile.start_dir = self._fileobj.tell() else: - if not self._zip64: - if self._file_size > ZIP64_LIMIT: - raise RuntimeError( - 'File size unexpectedly exceeded ZIP64 limit') - if self._compress_size > ZIP64_LIMIT: - raise RuntimeError( - 'Compressed size unexpectedly exceeded ZIP64 limit') # Seek backwards and write file header (which will now include # correct CRC and file sizes) @@ -1633,8 +1634,9 @@ def _open_to_write(self, zinfo, force_zip64=False): zinfo.external_attr = 0o600 << 16 # permissions: ?rw------- # Compressed size can be larger than uncompressed size - zip64 = self._allowZip64 and \ - (force_zip64 or zinfo.file_size * 1.05 > ZIP64_LIMIT) + zip64 = force_zip64 or (zinfo.file_size * 1.05 > ZIP64_LIMIT) + if not self._allowZip64 and zip64: + raise LargeZipFile("Filesize would require ZIP64 extensions") if self._seekable: self.fp.seek(self.start_dir) diff --git a/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst b/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst new file mode 100644 index 000000000000..cc1c444449fe --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst @@ -0,0 +1,2 @@ +Fix ``zipfile.Zipfile`` creating invalid zip files when ``force_zip64`` was +used to add files to them. Patch by Carey Metcalfe. From webhook-mailer at python.org Wed May 17 04:49:28 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 17 May 2023 08:49:28 -0000 Subject: [Python-checkins] gh-102153: Start stripping C0 control and space chars in `urlsplit` (#102508) Message-ID: <mailman.405.1684313369.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2f630e1ce18ad2e07428296532a68b11dc66ad10 commit: 2f630e1ce18ad2e07428296532a68b11dc66ad10 branch: main author: Illia Volochii <illia.volochii at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-17T01:49:20-07:00 summary: gh-102153: Start stripping C0 control and space chars in `urlsplit` (#102508) `urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit #25595. This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/#url-parsing:~:text=Remove%20any%20leading%20and%20trailing%20C0%20control%20or%20space%20from%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). --------- Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst M Doc/library/urllib.parse.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 96b396510794..5a9a53f83dac 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -159,6 +159,10 @@ or on combining URL components into a URL string. ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html', params='', query='', fragment='') + .. warning:: + + :func:`urlparse` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.2 Added IPv6 URL parsing capabilities. @@ -324,8 +328,14 @@ or on combining URL components into a URL string. ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is decomposed before parsing, no error will be raised. - Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline - ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL. + Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0 + control and space characters are stripped from the URL. ``\n``, + ``\r`` and tab ``\t`` characters are removed from the URL at any position. + + .. warning:: + + :func:`urlsplit` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of @@ -338,6 +348,9 @@ or on combining URL components into a URL string. .. versionchanged:: 3.10 ASCII newline and tab characters are stripped from the URL. + .. versionchanged:: 3.12 + Leading WHATWG C0 control and space characters are stripped from the URL. + .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser .. function:: urlunsplit(parts) @@ -414,6 +427,35 @@ or on combining URL components into a URL string. or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned without changes. +.. _url-parsing-security: + +URL parsing security +-------------------- + +The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of +inputs. They may not raise errors on inputs that other applications consider +invalid. They may also succeed on some inputs that might not be considered +URLs elsewhere. Their purpose is for practical functionality rather than +purity. + +Instead of raising an exception on unusual input, they may instead return some +component parts as empty strings. Or components may contain more than perhaps +they should. + +We recommend that users of these APIs where the values may be used anywhere +with security implications code defensively. Do some verification within your +code before trusting a returned component part. Does that ``scheme`` make +sense? Is that a sensible ``path``? Is there anything strange about that +``hostname``? etc. + +What constitutes a URL is not universally well defined. Different applications +have different needs and desired constraints. For instance the living `WHATWG +spec`_ describes what user facing web clients such as a web browser require. +While :rfc:`3986` is more general. These functions incorporate some aspects of +both, but cannot be claimed compliant with either. The APIs and existing user +code with expectations on specific behaviors predate both standards leading us +to be very cautious about making API behavior changes. + .. _parsing-ascii-encoded-bytes: Parsing ASCII Encoded Bytes diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index e324babdd5ed..625c6dc88796 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -654,6 +654,65 @@ def test_urlsplit_remove_unsafe_bytes(self): self.assertEqual(p.scheme, "http") self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment") + def test_urlsplit_strip_url(self): + noise = bytes(range(0, 0x20 + 1)) + base_url = "http://User:Pass at www.python.org:080/doc/?query=yes#frag" + + url = noise.decode("utf-8") + base_url + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, "http") + self.assertEqual(p.netloc, "User:Pass at www.python.org:080") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query=yes") + self.assertEqual(p.fragment, "frag") + self.assertEqual(p.username, "User") + self.assertEqual(p.password, "Pass") + self.assertEqual(p.hostname, "www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url) + + url = noise + base_url.encode("utf-8") + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"User:Pass at www.python.org:080") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"query=yes") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, b"User") + self.assertEqual(p.password, b"Pass") + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url.encode("utf-8")) + + # Test that trailing space is preserved as some applications rely on + # this within query strings. + query_spaces_url = "https://www.python.org:88/doc/?query= " + p = urllib.parse.urlsplit(noise.decode("utf-8") + query_spaces_url) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.netloc, "www.python.org:88") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query= ") + self.assertEqual(p.port, 88) + self.assertEqual(p.geturl(), query_spaces_url) + + p = urllib.parse.urlsplit("www.pypi.org ") + # That "hostname" gets considered a "path" due to the + # trailing space and our existing logic... YUCK... + # and re-assembles via geturl aka unurlsplit into the original. + # django.core.validators.URLValidator (at least through v3.2) relies on + # this, for better or worse, to catch it in a ValidationError via its + # regular expressions. + # Here we test the basic round trip concept of such a trailing space. + self.assertEqual(urllib.parse.urlunsplit(p), "www.pypi.org ") + + # with scheme as cache-key + url = "//www.python.org/" + scheme = noise.decode("utf-8") + "https" + noise.decode("utf-8") + for _ in range(2): + p = urllib.parse.urlsplit(url, scheme=scheme) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.geturl(), "https://www.python.org/") + def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): @@ -661,7 +720,7 @@ def test_attributes_bad_port(self): for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "?"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port - url = "http://" + netloc + url = "http://" + netloc + "/" if bytes: if netloc.isascii() and port.isascii(): netloc = netloc.encode("ascii") diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index da0073969bff..b73b34428764 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -25,6 +25,10 @@ scenarios for parsing, and for backward compatibility purposes, some parsing quirks from older RFCs are retained. The testcases in test_urlparse.py provides a good indicator of parsing behavior. + +The WHATWG URL Parser spec should also be considered. We are not compliant with +it either due to existing user code API behavior expectations (Hyrum's Law). +It serves as a useful guide when making changes. """ from collections import namedtuple @@ -80,6 +84,10 @@ '0123456789' '+-.') +# Leading and trailing C0 control and space to be stripped per WHATWG spec. +# == "".join([chr(i) for i in range(0, 0x20 + 1)]) +_WHATWG_C0_CONTROL_OR_SPACE = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' + # Unsafe bytes to be removed per WHATWG spec _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] @@ -464,6 +472,10 @@ def urlsplit(url, scheme='', allow_fragments=True): """ url, scheme, _coerce_result = _coerce_args(url, scheme) + # Only lstrip url as some applications rely on preserving trailing space. + # (https://url.spec.whatwg.org/#concept-basic-url-parser would strip both) + url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) + scheme = scheme.strip(_WHATWG_C0_CONTROL_OR_SPACE) for b in _UNSAFE_URL_BYTES_TO_REMOVE: url = url.replace(b, "") diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst new file mode 100644 index 000000000000..e57ac4ed3ac5 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst @@ -0,0 +1,3 @@ +:func:`urllib.parse.urlsplit` now strips leading C0 control and space +characters following the specification for URLs defined by WHATWG in +response to CVE-2023-24329. Patch by Illia Volochii. From webhook-mailer at python.org Wed May 17 08:24:05 2023 From: webhook-mailer at python.org (ambv) Date: Wed, 17 May 2023 12:24:05 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E8=5D_gh-102950=3A_Implement_P?= =?utf-8?q?EP_706_=E2=80=93_Filter_for_tarfile=2Eextractall_=28GH-102953?= =?utf-8?b?KSAoIzEwNDU0OCk=?= Message-ID: <mailman.406.1684326246.13550.python-checkins@python.org> https://github.com/python/cpython/commit/79e63e528795c700a8bd198c15f3322ee25ea786 commit: 79e63e528795c700a8bd198c15f3322ee25ea786 branch: 3.8 author: Petr Viktorin <encukou at gmail.com> committer: ambv <lukasz at langa.pl> date: 2023-05-17T14:23:56+02:00 summary: [3.8] gh-102950: Implement PEP 706 ? Filter for tarfile.extractall (GH-102953) (#104548) Backport of c8c3956d905e019101038b018129a4c90c9c9b8f files: A Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst M Doc/library/shutil.rst M Doc/library/tarfile.rst M Doc/whatsnew/3.8.rst M Lib/shutil.py M Lib/tarfile.py M Lib/test/test_shutil.py M Lib/test/test_tarfile.py diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index cd32a0a6e0c1..c424c823ef62 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -640,7 +640,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. Remove the archive format *name* from the list of supported formats. -.. function:: unpack_archive(filename[, extract_dir[, format]]) +.. function:: unpack_archive(filename[, extract_dir[, format[, filter]]]) Unpack an archive. *filename* is the full path of the archive. @@ -654,11 +654,29 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. registered for that extension. In case none is found, a :exc:`ValueError` is raised. + The keyword-only *filter* argument, which was added in Python 3.8.17, + is passed to the underlying unpacking function. + For zip files, *filter* is not accepted. + For tar files, it is recommended to set it to ``'data'``, + unless using features specific to tar and UNIX-like filesystems. + (See :ref:`tarfile-extraction-filter` for details.) + The ``'data'`` filter will become the default for tar files + in Python 3.14. + .. audit-event:: shutil.unpack_archive filename,extract_dir,format shutil.unpack_archive + .. warning:: + + Never extract archives from untrusted sources without prior inspection. + It is possible that files are created outside of the path specified in + the *extract_dir* argument, e.g. members that have absolute filenames + starting with "/" or filenames with two dots "..". + .. versionchanged:: 3.7 Accepts a :term:`path-like object` for *filename* and *extract_dir*. + .. versionchanged:: 3.8.17 + Added the *filter* argument. .. function:: register_unpack_format(name, extensions, function[, extra_args[, description]]) @@ -667,11 +685,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. ``.zip`` for Zip files. *function* is the callable that will be used to unpack archives. The - callable will receive the path of the archive, followed by the directory - the archive must be extracted to. - - When provided, *extra_args* is a sequence of ``(name, value)`` tuples that - will be passed as keywords arguments to the callable. + callable will receive: + + - the path of the archive, as a positional argument; + - the directory the archive must be extracted to, as a positional argument; + - possibly a *filter* keyword argument, if it was given to + :func:`unpack_archive`; + - additional keyword arguments, specified by *extra_args* as a sequence + of ``(name, value)`` tuples. *description* can be provided to describe the format, and will be returned by the :func:`get_unpack_formats` function. diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 811f74f0e4d4..85d07ffd75fa 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -200,6 +200,38 @@ The :mod:`tarfile` module defines the following exceptions: Is raised by :meth:`TarInfo.frombuf` if the buffer it gets is invalid. +.. exception:: FilterError + + Base class for members :ref:`refused <tarfile-extraction-refuse>` by + filters. + + .. attribute:: tarinfo + + Information about the member that the filter refused to extract, + as :ref:`TarInfo <tarinfo-objects>`. + +.. exception:: AbsolutePathError + + Raised to refuse extracting a member with an absolute path. + +.. exception:: OutsideDestinationError + + Raised to refuse extracting a member outside the destination directory. + +.. exception:: SpecialFileError + + Raised to refuse extracting a special file (e.g. a device or pipe). + +.. exception:: AbsoluteLinkError + + Raised to refuse extracting a symbolic link with an absolute path. + +.. exception:: LinkOutsideDestinationError + + Raised to refuse extracting a symbolic link pointing outside the destination + directory. + + The following constants are available at the module level: .. data:: ENCODING @@ -310,11 +342,8 @@ be finalized; only the internally used file object will be closed. See the *debug* can be set from ``0`` (no debug messages) up to ``3`` (all debug messages). The messages are written to ``sys.stderr``. - If *errorlevel* is ``0``, all errors are ignored when using :meth:`TarFile.extract`. - Nevertheless, they appear as error messages in the debug output, when debugging - is enabled. If ``1``, all *fatal* errors are raised as :exc:`OSError` - exceptions. If ``2``, all *non-fatal* errors are raised as :exc:`TarError` - exceptions as well. + *errorlevel* controls how extraction errors are handled, + see :attr:`the corresponding attribute <~TarFile.errorlevel>`. The *encoding* and *errors* arguments define the character encoding to be used for reading or writing the archive and how conversion errors are going @@ -381,7 +410,7 @@ be finalized; only the internally used file object will be closed. See the available. -.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False) +.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False, filter=None) Extract all members from the archive to the current working directory or directory *path*. If optional *members* is given, it must be a subset of the @@ -395,6 +424,12 @@ be finalized; only the internally used file object will be closed. See the are used to set the owner/group for the extracted files. Otherwise, the named values from the tarfile are used. + The *filter* argument, which was added in Python 3.8.17, specifies how + ``members`` are modified or rejected before extraction. + See :ref:`tarfile-extraction-filter` for details. + It is recommended to set this explicitly depending on which *tar* features + you need to support. + .. warning:: Never extract archives from untrusted sources without prior inspection. @@ -402,14 +437,20 @@ be finalized; only the internally used file object will be closed. See the that have absolute filenames starting with ``"/"`` or filenames with two dots ``".."``. + Set ``filter='data'`` to prevent the most dangerous security issues, + and read the :ref:`tarfile-extraction-filter` section for details. + .. versionchanged:: 3.5 Added the *numeric_owner* parameter. .. versionchanged:: 3.6 The *path* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.8.17 + Added the *filter* parameter. + -.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False) +.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False, filter=None) Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. *member* @@ -417,9 +458,8 @@ be finalized; only the internally used file object will be closed. See the directory using *path*. *path* may be a :term:`path-like object`. File attributes (owner, mtime, mode) are set unless *set_attrs* is false. - If *numeric_owner* is :const:`True`, the uid and gid numbers from the tarfile - are used to set the owner/group for the extracted files. Otherwise, the named - values from the tarfile are used. + The *numeric_owner* and *filter* arguments are the same as + for :meth:`extractall`. .. note:: @@ -430,6 +470,9 @@ be finalized; only the internally used file object will be closed. See the See the warning for :meth:`extractall`. + Set ``filter='data'`` to prevent the most dangerous security issues, + and read the :ref:`tarfile-extraction-filter` section for details. + .. versionchanged:: 3.2 Added the *set_attrs* parameter. @@ -439,6 +482,9 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.6 The *path* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.8.17 + Added the *filter* parameter. + .. method:: TarFile.extractfile(member) @@ -450,6 +496,57 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.3 Return an :class:`io.BufferedReader` object. +.. attribute:: TarFile.errorlevel + :type: int + + If *errorlevel* is ``0``, errors are ignored when using :meth:`TarFile.extract` + and :meth:`TarFile.extractall`. + Nevertheless, they appear as error messages in the debug output when + *debug* is greater than 0. + If ``1`` (the default), all *fatal* errors are raised as :exc:`OSError` or + :exc:`FilterError` exceptions. If ``2``, all *non-fatal* errors are raised + as :exc:`TarError` exceptions as well. + + Some exceptions, e.g. ones caused by wrong argument types or data + corruption, are always raised. + + Custom :ref:`extraction filters <tarfile-extraction-filter>` + should raise :exc:`FilterError` for *fatal* errors + and :exc:`ExtractError` for *non-fatal* ones. + + Note that when an exception is raised, the archive may be partially + extracted. It is the user?s responsibility to clean up. + +.. attribute:: TarFile.extraction_filter + + .. versionadded:: 3.8.17 + + The :ref:`extraction filter <tarfile-extraction-filter>` used + as a default for the *filter* argument of :meth:`~TarFile.extract` + and :meth:`~TarFile.extractall`. + + The attribute may be ``None`` or a callable. + String names are not allowed for this attribute, unlike the *filter* + argument to :meth:`~TarFile.extract`. + + If ``extraction_filter`` is ``None`` (the default), + calling an extraction method without a *filter* argument will + use the :func:`fully_trusted <fully_trusted_filter>` filter for + compatibility with previous Python versions. + + In Python 3.12+, leaving ``extraction_filter=None`` will emit a + ``DeprecationWarning``. + + In Python 3.14+, leaving ``extraction_filter=None`` will cause + extraction methods to use the :func:`data <data_filter>` filter by default. + + The attribute may be set on instances or overridden in subclasses. + It also is possible to set it on the ``TarFile`` class itself to set a + global default, although, since it affects all uses of *tarfile*, + it is best practice to only do so in top-level applications or + :mod:`site configuration <site>`. + To set a global default this way, a filter function needs to be wrapped in + :func:`staticmethod()` to prevent injection of a ``self`` argument. .. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None) @@ -525,7 +622,27 @@ permissions, owner etc.), it provides some useful methods to determine its type. It does *not* contain the file's data itself. :class:`TarInfo` objects are returned by :class:`TarFile`'s methods -:meth:`getmember`, :meth:`getmembers` and :meth:`gettarinfo`. +:meth:`~TarFile.getmember`, :meth:`~TarFile.getmembers` and +:meth:`~TarFile.gettarinfo`. + +Modifying the objects returned by :meth:`~!TarFile.getmember` or +:meth:`~!TarFile.getmembers` will affect all subsequent +operations on the archive. +For cases where this is unwanted, you can use :mod:`copy.copy() <copy>` or +call the :meth:`~TarInfo.replace` method to create a modified copy in one step. + +Several attributes can be set to ``None`` to indicate that a piece of metadata +is unused or unknown. +Different :class:`TarInfo` methods handle ``None`` differently: + +- The :meth:`~TarFile.extract` or :meth:`~TarFile.extractall` methods will + ignore the corresponding metadata, leaving it set to a default. +- :meth:`~TarFile.addfile` will fail. +- :meth:`~TarFile.list` will print a placeholder string. + + +.. versionchanged:: 3.8.17 + Added :meth:`~TarInfo.replace` and handling of ``None``. .. class:: TarInfo(name="") @@ -559,24 +676,39 @@ A ``TarInfo`` object has the following public data attributes: .. attribute:: TarInfo.name + :type: str Name of the archive member. .. attribute:: TarInfo.size + :type: int Size in bytes. .. attribute:: TarInfo.mtime + :type: int | float + + Time of last modification in seconds since the :ref:`epoch <epoch>`, + as in :attr:`os.stat_result.st_mtime`. - Time of last modification. + .. versionchanged:: 3.8.17 + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.mode + :type: int - Permission bits. + Permission bits, as for :func:`os.chmod`. + .. versionchanged:: 3.8.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.type @@ -588,35 +720,76 @@ A ``TarInfo`` object has the following public data attributes: .. attribute:: TarInfo.linkname + :type: str Name of the target file name, which is only present in :class:`TarInfo` objects of type :const:`LNKTYPE` and :const:`SYMTYPE`. .. attribute:: TarInfo.uid + :type: int User ID of the user who originally stored this member. + .. versionchanged:: 3.8.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.gid + :type: int Group ID of the user who originally stored this member. + .. versionchanged:: 3.8.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.uname + :type: str User name. + .. versionchanged:: 3.8.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.gname + :type: str Group name. + .. versionchanged:: 3.8.17 + + Can be set to ``None`` for :meth:`~TarFile.extract` and + :meth:`~TarFile.extractall`, causing extraction to skip applying this + attribute. .. attribute:: TarInfo.pax_headers + :type: dict A dictionary containing key-value pairs of an associated pax extended header. +.. method:: TarInfo.replace(name=..., mtime=..., mode=..., linkname=..., + uid=..., gid=..., uname=..., gname=..., + deep=True) + + .. versionadded:: 3.8.17 + + Return a *new* copy of the :class:`!TarInfo` object with the given attributes + changed. For example, to return a ``TarInfo`` with the group name set to + ``'staff'``, use:: + + new_tarinfo = old_tarinfo.replace(gname='staff') + + By default, a deep copy is made. + If *deep* is false, the copy is shallow, i.e. ``pax_headers`` + and any custom attributes are shared with the original ``TarInfo`` object. A :class:`TarInfo` object also provides some convenient query methods: @@ -666,9 +839,259 @@ A :class:`TarInfo` object also provides some convenient query methods: Return :const:`True` if it is one of character device, block device or FIFO. +.. _tarfile-extraction-filter: + +Extraction filters +------------------ + +.. versionadded:: 3.8.17 + +The *tar* format is designed to capture all details of a UNIX-like filesystem, +which makes it very powerful. +Unfortunately, the features make it easy to create tar files that have +unintended -- and possibly malicious -- effects when extracted. +For example, extracting a tar file can overwrite arbitrary files in various +ways (e.g. by using absolute paths, ``..`` path components, or symlinks that +affect later members). + +In most cases, the full functionality is not needed. +Therefore, *tarfile* supports extraction filters: a mechanism to limit +functionality, and thus mitigate some of the security issues. + +.. seealso:: + + :pep:`706` + Contains further motivation and rationale behind the design. + +The *filter* argument to :meth:`TarFile.extract` or :meth:`~TarFile.extractall` +can be: + +* the string ``'fully_trusted'``: Honor all metadata as specified in the + archive. + Should be used if the user trusts the archive completely, or implements + their own complex verification. + +* the string ``'tar'``: Honor most *tar*-specific features (i.e. features of + UNIX-like filesystems), but block features that are very likely to be + surprising or malicious. See :func:`tar_filter` for details. + +* the string ``'data'``: Ignore or block most features specific to UNIX-like + filesystems. Intended for extracting cross-platform data archives. + See :func:`data_filter` for details. + +* ``None`` (default): Use :attr:`TarFile.extraction_filter`. + + If that is also ``None`` (the default), the ``'fully_trusted'`` + filter will be used (for compatibility with earlier versions of Python). + + In Python 3.12, the default will emit a ``DeprecationWarning``. + + In Python 3.14, the ``'data'`` filter will become the default instead. + It's possible to switch earlier; see :attr:`TarFile.extraction_filter`. + +* A callable which will be called for each extracted member with a + :ref:`TarInfo <tarinfo-objects>` describing the member and the destination + path to where the archive is extracted (i.e. the same path is used for all + members):: + + filter(/, member: TarInfo, path: str) -> TarInfo | None + + The callable is called just before each member is extracted, so it can + take the current state of the disk into account. + It can: + + - return a :class:`TarInfo` object which will be used instead of the metadata + in the archive, or + - return ``None``, in which case the member will be skipped, or + - raise an exception to abort the operation or skip the member, + depending on :attr:`~TarFile.errorlevel`. + Note that when extraction is aborted, :meth:`~TarFile.extractall` may leave + the archive partially extracted. It does not attempt to clean up. + +Default named filters +~~~~~~~~~~~~~~~~~~~~~ + +The pre-defined, named filters are available as functions, so they can be +reused in custom filters: + +.. function:: fully_trusted_filter(/, member, path) + + Return *member* unchanged. + + This implements the ``'fully_trusted'`` filter. + +.. function:: tar_filter(/, member, path) + + Implements the ``'tar'`` filter. + + - Strip leading slashes (``/`` and :attr:`os.sep`) from filenames. + - :ref:`Refuse <tarfile-extraction-refuse>` to extract files with absolute + paths (in case the name is absolute + even after stripping slashes, e.g. ``C:/foo`` on Windows). + This raises :class:`~tarfile.AbsolutePathError`. + - :ref:`Refuse <tarfile-extraction-refuse>` to extract files whose absolute + path (after following symlinks) would end up outside the destination. + This raises :class:`~tarfile.OutsideDestinationError`. + - Clear high mode bits (setuid, setgid, sticky) and group/other write bits + (:attr:`~stat.S_IWGRP`|:attr:`~stat.S_IWOTH`). + + Return the modified ``TarInfo`` member. + +.. function:: data_filter(/, member, path) + + Implements the ``'data'`` filter. + In addition to what ``tar_filter`` does: + + - :ref:`Refuse <tarfile-extraction-refuse>` to extract links (hard or soft) + that link to absolute paths, or ones that link outside the destination. + + This raises :class:`~tarfile.AbsoluteLinkError` or + :class:`~tarfile.LinkOutsideDestinationError`. + + Note that such files are refused even on platforms that do not support + symbolic links. + + - :ref:`Refuse <tarfile-extraction-refuse>` to extract device files + (including pipes). + This raises :class:`~tarfile.SpecialFileError`. + + - For regular files, including hard links: + + - Set the owner read and write permissions + (:attr:`~stat.S_IRUSR`|:attr:`~stat.S_IWUSR`). + - Remove the group & other executable permission + (:attr:`~stat.S_IXGRP`|:attr:`~stat.S_IXOTH`) + if the owner doesn?t have it (:attr:`~stat.S_IXUSR`). + + - For other files (directories), set ``mode`` to ``None``, so + that extraction methods skip applying permission bits. + - Set user and group info (``uid``, ``gid``, ``uname``, ``gname``) + to ``None``, so that extraction methods skip setting it. + + Return the modified ``TarInfo`` member. + + +.. _tarfile-extraction-refuse: + +Filter errors +~~~~~~~~~~~~~ + +When a filter refuses to extract a file, it will raise an appropriate exception, +a subclass of :class:`~tarfile.FilterError`. +This will abort the extraction if :attr:`TarFile.errorlevel` is 1 or more. +With ``errorlevel=0`` the error will be logged and the member will be skipped, +but extraction will continue. + + +Hints for further verification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Even with ``filter='data'``, *tarfile* is not suited for extracting untrusted +files without prior inspection. +Among other issues, the pre-defined filters do not prevent denial-of-service +attacks. Users should do additional checks. + +Here is an incomplete list of things to consider: + +* Extract to a :func:`new temporary directory <tempfile.mkdtemp>` + to prevent e.g. exploiting pre-existing links, and to make it easier to + clean up after a failed extraction. +* When working with untrusted data, use external (e.g. OS-level) limits on + disk, memory and CPU usage. +* Check filenames against an allow-list of characters + (to filter out control characters, confusables, foreign path separators, + etc.). +* Check that filenames have expected extensions (discouraging files that + execute when you ?click on them?, or extension-less files like Windows special device names). +* Limit the number of extracted files, total size of extracted data, + filename length (including symlink length), and size of individual files. +* Check for files that would be shadowed on case-insensitive filesystems. + +Also note that: + +* Tar files may contain multiple versions of the same file. + Later ones are expected to overwrite any earlier ones. + This feature is crucial to allow updating tape archives, but can be abused + maliciously. +* *tarfile* does not protect against issues with ?live? data, + e.g. an attacker tinkering with the destination (or source) directory while + extraction (or archiving) is in progress. + + +Supporting older Python versions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extraction filters were added to Python 3.12, and are backported to older +versions as security updates. +To check whether the feature is available, use e.g. +``hasattr(tarfile, 'data_filter')`` rather than checking the Python version. + +The following examples show how to support Python versions with and without +the feature. +Note that setting ``extraction_filter`` will affect any subsequent operations. + +* Fully trusted archive:: + + my_tarfile.extraction_filter = (lambda member, path: member) + my_tarfile.extractall() + +* Use the ``'data'`` filter if available, but revert to Python 3.11 behavior + (``'fully_trusted'``) if this feature is not available:: + + my_tarfile.extraction_filter = getattr(tarfile, 'data_filter', + (lambda member, path: member)) + my_tarfile.extractall() + +* Use the ``'data'`` filter; *fail* if it is not available:: + + my_tarfile.extractall(filter=tarfile.data_filter) + + or:: + + my_tarfile.extraction_filter = tarfile.data_filter + my_tarfile.extractall() + +* Use the ``'data'`` filter; *warn* if it is not available:: + + if hasattr(tarfile, 'data_filter'): + my_tarfile.extractall(filter='data') + else: + # remove this when no longer needed + warn_the_user('Extracting may be unsafe; consider updating Python') + my_tarfile.extractall() + + +Stateful extraction filter example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While *tarfile*'s extraction methods take a simple *filter* callable, +custom filters may be more complex objects with an internal state. +It may be useful to write these as context managers, to be used like this:: + + with StatefulFilter() as filter_func: + tar.extractall(path, filter=filter_func) + +Such a filter can be written as, for example:: + + class StatefulFilter: + def __init__(self): + self.file_count = 0 + + def __enter__(self): + return self + + def __call__(self, member, path): + self.file_count += 1 + return member + + def __exit__(self, *exc_info): + print(f'{self.file_count} files extracted') + + .. _tarfile-commandline: .. program:: tarfile + Command-Line Interface ---------------------- @@ -738,6 +1161,15 @@ Command-line options Verbose output. +.. cmdoption:: --filter <filtername> + + Specifies the *filter* for ``--extract``. + See :ref:`tarfile-extraction-filter` for details. + Only string names are accepted (that is, ``fully_trusted``, ``tar``, + and ``data``). + + .. versionadded:: 3.8.17 + .. _tar-examples: Examples diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 630e060cb07a..e5278da3f6a5 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -2339,3 +2339,19 @@ This limit can be configured or disabled by environment variable, command line flag, or :mod:`sys` APIs. See the :ref:`integer string conversion length limitation <int_max_str_digits>` documentation. The default limit is 4300 digits in string form. + +Notable Changes in 3.8.17 +========================= + +tarfile +------- + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile-extraction-filter` for details. + In Python 3.12, use without the *filter* argument will show a + :exc:`DeprecationWarning`. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) diff --git a/Lib/shutil.py b/Lib/shutil.py index fdadb838000c..acb0eb18714f 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -1161,7 +1161,7 @@ def _unpack_zipfile(filename, extract_dir): finally: zip.close() -def _unpack_tarfile(filename, extract_dir): +def _unpack_tarfile(filename, extract_dir, *, filter=None): """Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir` """ import tarfile # late import for breaking circular dependency @@ -1171,7 +1171,7 @@ def _unpack_tarfile(filename, extract_dir): raise ReadError( "%s is not a compressed or uncompressed tar file" % filename) try: - tarobj.extractall(extract_dir) + tarobj.extractall(extract_dir, filter=filter) finally: tarobj.close() @@ -1199,7 +1199,7 @@ def _find_unpack_format(filename): return name return None -def unpack_archive(filename, extract_dir=None, format=None): +def unpack_archive(filename, extract_dir=None, format=None, *, filter=None): """Unpack an archive. `filename` is the name of the archive. @@ -1213,6 +1213,9 @@ def unpack_archive(filename, extract_dir=None, format=None): was registered for that extension. In case none is found, a ValueError is raised. + + If `filter` is given, it is passed to the underlying + extraction function. """ sys.audit("shutil.unpack_archive", filename, extract_dir, format) @@ -1222,6 +1225,10 @@ def unpack_archive(filename, extract_dir=None, format=None): extract_dir = os.fspath(extract_dir) filename = os.fspath(filename) + if filter is None: + filter_kwargs = {} + else: + filter_kwargs = {'filter': filter} if format is not None: try: format_info = _UNPACK_FORMATS[format] @@ -1229,7 +1236,7 @@ def unpack_archive(filename, extract_dir=None, format=None): raise ValueError("Unknown unpack format '{0}'".format(format)) from None func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) + func(filename, extract_dir, **dict(format_info[2]), **filter_kwargs) else: # we need to look at the registered unpackers supported extensions format = _find_unpack_format(filename) @@ -1238,6 +1245,7 @@ def unpack_archive(filename, extract_dir=None, format=None): func = _UNPACK_FORMATS[format][1] kwargs = dict(_UNPACK_FORMATS[format][2]) + kwargs.update(filter_kwargs) func(filename, extract_dir, **kwargs) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 30150ec6cca6..5291622ab8e9 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -46,6 +46,7 @@ import struct import copy import re +import warnings try: import pwd @@ -71,6 +72,7 @@ "ENCODING", "USTAR_FORMAT", "GNU_FORMAT", "PAX_FORMAT", "DEFAULT_FORMAT", "open"] + #--------------------------------------------------------- # tar constants #--------------------------------------------------------- @@ -158,6 +160,8 @@ def stn(s, length, encoding, errors): """Convert a string to a null-terminated bytes object. """ + if s is None: + raise ValueError("metadata cannot contain None") s = s.encode(encoding, errors) return s[:length] + (length - len(s)) * NUL @@ -708,9 +712,127 @@ def __init__(self, tarfile, tarinfo): super().__init__(fileobj) #class ExFileObject + +#----------------------------- +# extraction filters (PEP 706) +#----------------------------- + +class FilterError(TarError): + pass + +class AbsolutePathError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'member {tarinfo.name!r} has an absolute path') + +class OutsideDestinationError(FilterError): + def __init__(self, tarinfo, path): + self.tarinfo = tarinfo + self._path = path + super().__init__(f'{tarinfo.name!r} would be extracted to {path!r}, ' + + 'which is outside the destination') + +class SpecialFileError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'{tarinfo.name!r} is a special file') + +class AbsoluteLinkError(FilterError): + def __init__(self, tarinfo): + self.tarinfo = tarinfo + super().__init__(f'{tarinfo.name!r} is a symlink to an absolute path') + +class LinkOutsideDestinationError(FilterError): + def __init__(self, tarinfo, path): + self.tarinfo = tarinfo + self._path = path + super().__init__(f'{tarinfo.name!r} would link to {path!r}, ' + + 'which is outside the destination') + +def _get_filtered_attrs(member, dest_path, for_data=True): + new_attrs = {} + name = member.name + dest_path = os.path.realpath(dest_path) + # Strip leading / (tar's directory separator) from filenames. + # Include os.sep (target OS directory separator) as well. + if name.startswith(('/', os.sep)): + name = new_attrs['name'] = member.path.lstrip('/' + os.sep) + if os.path.isabs(name): + # Path is absolute even after stripping. + # For example, 'C:/foo' on Windows. + raise AbsolutePathError(member) + # Ensure we stay in the destination + target_path = os.path.realpath(os.path.join(dest_path, name)) + if os.path.commonpath([target_path, dest_path]) != dest_path: + raise OutsideDestinationError(member, target_path) + # Limit permissions (no high bits, and go-w) + mode = member.mode + if mode is not None: + # Strip high bits & group/other write bits + mode = mode & 0o755 + if for_data: + # For data, handle permissions & file types + if member.isreg() or member.islnk(): + if not mode & 0o100: + # Clear executable bits if not executable by user + mode &= ~0o111 + # Ensure owner can read & write + mode |= 0o600 + elif member.isdir() or member.issym(): + # Ignore mode for directories & symlinks + mode = None + else: + # Reject special files + raise SpecialFileError(member) + if mode != member.mode: + new_attrs['mode'] = mode + if for_data: + # Ignore ownership for 'data' + if member.uid is not None: + new_attrs['uid'] = None + if member.gid is not None: + new_attrs['gid'] = None + if member.uname is not None: + new_attrs['uname'] = None + if member.gname is not None: + new_attrs['gname'] = None + # Check link destination for 'data' + if member.islnk() or member.issym(): + if os.path.isabs(member.linkname): + raise AbsoluteLinkError(member) + target_path = os.path.realpath(os.path.join(dest_path, member.linkname)) + if os.path.commonpath([target_path, dest_path]) != dest_path: + raise LinkOutsideDestinationError(member, target_path) + return new_attrs + +def fully_trusted_filter(member, dest_path): + return member + +def tar_filter(member, dest_path): + new_attrs = _get_filtered_attrs(member, dest_path, False) + if new_attrs: + return member.replace(**new_attrs, deep=False) + return member + +def data_filter(member, dest_path): + new_attrs = _get_filtered_attrs(member, dest_path, True) + if new_attrs: + return member.replace(**new_attrs, deep=False) + return member + +_NAMED_FILTERS = { + "fully_trusted": fully_trusted_filter, + "tar": tar_filter, + "data": data_filter, +} + #------------------ # Exported Classes #------------------ + +# Sentinel for replace() defaults, meaning "don't change the attribute" +_KEEP = object() + class TarInfo(object): """Informational class which holds the details about an archive member given by a tar header block. @@ -791,12 +913,44 @@ def linkpath(self, linkname): def __repr__(self): return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) + def replace(self, *, + name=_KEEP, mtime=_KEEP, mode=_KEEP, linkname=_KEEP, + uid=_KEEP, gid=_KEEP, uname=_KEEP, gname=_KEEP, + deep=True, _KEEP=_KEEP): + """Return a deep copy of self with the given attributes replaced. + """ + if deep: + result = copy.deepcopy(self) + else: + result = copy.copy(self) + if name is not _KEEP: + result.name = name + if mtime is not _KEEP: + result.mtime = mtime + if mode is not _KEEP: + result.mode = mode + if linkname is not _KEEP: + result.linkname = linkname + if uid is not _KEEP: + result.uid = uid + if gid is not _KEEP: + result.gid = gid + if uname is not _KEEP: + result.uname = uname + if gname is not _KEEP: + result.gname = gname + return result + def get_info(self): """Return the TarInfo's attributes as a dictionary. """ + if self.mode is None: + mode = None + else: + mode = self.mode & 0o7777 info = { "name": self.name, - "mode": self.mode & 0o7777, + "mode": mode, "uid": self.uid, "gid": self.gid, "size": self.size, @@ -819,6 +973,9 @@ def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescap """Return a tar header as a string of 512 byte blocks. """ info = self.get_info() + for name, value in info.items(): + if value is None: + raise ValueError("%s may not be None" % name) if format == USTAR_FORMAT: return self.create_ustar_header(info, encoding, errors) @@ -932,6 +1089,20 @@ def _create_header(info, format, encoding, errors): """Return a header block. info is a dictionary with file information, format must be one of the *_FORMAT constants. """ + has_device_fields = info.get("type") in (CHRTYPE, BLKTYPE) + if has_device_fields: + devmajor = itn(info.get("devmajor", 0), 8, format) + devminor = itn(info.get("devminor", 0), 8, format) + else: + devmajor = stn("", 8, encoding, errors) + devminor = stn("", 8, encoding, errors) + + # None values in metadata should cause ValueError. + # itn()/stn() do this for all fields except type. + filetype = info.get("type", REGTYPE) + if filetype is None: + raise ValueError("TarInfo.type must not be None") + parts = [ stn(info.get("name", ""), 100, encoding, errors), itn(info.get("mode", 0) & 0o7777, 8, format), @@ -940,7 +1111,7 @@ def _create_header(info, format, encoding, errors): itn(info.get("size", 0), 12, format), itn(info.get("mtime", 0), 12, format), b" ", # checksum field - info.get("type", REGTYPE), + filetype, stn(info.get("linkname", ""), 100, encoding, errors), info.get("magic", POSIX_MAGIC), stn(info.get("uname", ""), 32, encoding, errors), @@ -1440,6 +1611,8 @@ class TarFile(object): fileobject = ExFileObject # The file-object for extractfile(). + extraction_filter = None # The default filter for extraction. + def __init__(self, name=None, mode="r", fileobj=None, format=None, tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, errors="surrogateescape", pax_headers=None, debug=None, @@ -1909,7 +2082,10 @@ def list(self, verbose=True, *, members=None): members = self for tarinfo in members: if verbose: - _safe_print(stat.filemode(tarinfo.mode)) + if tarinfo.mode is None: + _safe_print("??????????") + else: + _safe_print(stat.filemode(tarinfo.mode)) _safe_print("%s/%s" % (tarinfo.uname or tarinfo.uid, tarinfo.gname or tarinfo.gid)) if tarinfo.ischr() or tarinfo.isblk(): @@ -1917,8 +2093,11 @@ def list(self, verbose=True, *, members=None): ("%d,%d" % (tarinfo.devmajor, tarinfo.devminor))) else: _safe_print("%10d" % tarinfo.size) - _safe_print("%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6]) + if tarinfo.mtime is None: + _safe_print("????-??-?? ??:??:??") + else: + _safe_print("%d-%02d-%02d %02d:%02d:%02d" \ + % time.localtime(tarinfo.mtime)[:6]) _safe_print(tarinfo.name + ("/" if tarinfo.isdir() else "")) @@ -2005,32 +2184,58 @@ def addfile(self, tarinfo, fileobj=None): self.members.append(tarinfo) - def extractall(self, path=".", members=None, *, numeric_owner=False): + def _get_filter_function(self, filter): + if filter is None: + filter = self.extraction_filter + if filter is None: + return fully_trusted_filter + if isinstance(filter, str): + raise TypeError( + 'String names are not supported for ' + + 'TarFile.extraction_filter. Use a function such as ' + + 'tarfile.data_filter directly.') + return filter + if callable(filter): + return filter + try: + return _NAMED_FILTERS[filter] + except KeyError: + raise ValueError(f"filter {filter!r} not found") from None + + def extractall(self, path=".", members=None, *, numeric_owner=False, + filter=None): """Extract all members from the archive to the current working directory and set owner, modification time and permissions on directories afterwards. `path' specifies a different directory to extract to. `members' is optional and must be a subset of the list returned by getmembers(). If `numeric_owner` is True, only the numbers for user/group names are used and not the names. + + The `filter` function will be called on each member just + before extraction. + It can return a changed TarInfo or None to skip the member. + String names of common filters are accepted. """ directories = [] + filter_function = self._get_filter_function(filter) if members is None: members = self - for tarinfo in members: + for member in members: + tarinfo = self._get_extract_tarinfo(member, filter_function, path) + if tarinfo is None: + continue if tarinfo.isdir(): - # Extract directories with a safe mode. + # For directories, delay setting attributes until later, + # since permissions can interfere with extraction and + # extracting contents can reset mtime. directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0o700 - # Do not set_attrs directories, as we will do that further down - self.extract(tarinfo, path, set_attrs=not tarinfo.isdir(), - numeric_owner=numeric_owner) + self._extract_one(tarinfo, path, set_attrs=not tarinfo.isdir(), + numeric_owner=numeric_owner) # Reverse sort directories. - directories.sort(key=lambda a: a.name) - directories.reverse() + directories.sort(key=lambda a: a.name, reverse=True) # Set correct owner, mtime and filemode on directories. for tarinfo in directories: @@ -2040,12 +2245,10 @@ def extractall(self, path=".", members=None, *, numeric_owner=False): self.utime(tarinfo, dirpath) self.chmod(tarinfo, dirpath) except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) + self._handle_nonfatal_error(e) - def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): + def extract(self, member, path="", set_attrs=True, *, numeric_owner=False, + filter=None): """Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. `member' may be a filename or a TarInfo object. You can @@ -2053,35 +2256,70 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False): mtime, mode) are set unless `set_attrs' is False. If `numeric_owner` is True, only the numbers for user/group names are used and not the names. + + The `filter` function will be called before extraction. + It can return a changed TarInfo or None to skip the member. + String names of common filters are accepted. """ - self._check("r") + filter_function = self._get_filter_function(filter) + tarinfo = self._get_extract_tarinfo(member, filter_function, path) + if tarinfo is not None: + self._extract_one(tarinfo, path, set_attrs, numeric_owner) + def _get_extract_tarinfo(self, member, filter_function, path): + """Get filtered TarInfo (or None) from member, which might be a str""" if isinstance(member, str): tarinfo = self.getmember(member) else: tarinfo = member + unfiltered = tarinfo + try: + tarinfo = filter_function(tarinfo, path) + except (OSError, FilterError) as e: + self._handle_fatal_error(e) + except ExtractError as e: + self._handle_nonfatal_error(e) + if tarinfo is None: + self._dbg(2, "tarfile: Excluded %r" % unfiltered.name) + return None # Prepare the link target for makelink(). if tarinfo.islnk(): + tarinfo = copy.copy(tarinfo) tarinfo._link_target = os.path.join(path, tarinfo.linkname) + return tarinfo + + def _extract_one(self, tarinfo, path, set_attrs, numeric_owner): + """Extract from filtered tarinfo to disk""" + self._check("r") try: self._extract_member(tarinfo, os.path.join(path, tarinfo.name), set_attrs=set_attrs, numeric_owner=numeric_owner) except OSError as e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + self._handle_fatal_error(e) except ExtractError as e: - if self.errorlevel > 1: - raise + self._handle_nonfatal_error(e) + + def _handle_nonfatal_error(self, e): + """Handle non-fatal error (ExtractError) according to errorlevel""" + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + def _handle_fatal_error(self, e): + """Handle "fatal" error according to self.errorlevel""" + if self.errorlevel > 0: + raise + elif isinstance(e, OSError): + if e.filename is None: + self._dbg(1, "tarfile: %s" % e.strerror) else: - self._dbg(1, "tarfile: %s" % e) + self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) + else: + self._dbg(1, "tarfile: %s %s" % (type(e).__name__, e)) def extractfile(self, member): """Extract a member from the archive as a file object. `member' may be @@ -2167,9 +2405,13 @@ def makedir(self, tarinfo, targetpath): """Make a directory called targetpath. """ try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0o700) + if tarinfo.mode is None: + # Use the system's default mode + os.mkdir(targetpath) + else: + # Use a safe mode for the directory, the real mode is set + # later in _extract_member(). + os.mkdir(targetpath, 0o700) except FileExistsError: pass @@ -2212,6 +2454,9 @@ def makedev(self, tarinfo, targetpath): raise ExtractError("special devices not supported by system") mode = tarinfo.mode + if mode is None: + # Use mknod's default + mode = 0o600 if tarinfo.isblk(): mode |= stat.S_IFBLK else: @@ -2233,7 +2478,6 @@ def makelink(self, tarinfo, targetpath): os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: - # See extract(). if os.path.exists(tarinfo._link_target): os.link(tarinfo._link_target, targetpath) else: @@ -2258,15 +2502,19 @@ def chown(self, tarinfo, targetpath, numeric_owner): u = tarinfo.uid if not numeric_owner: try: - if grp: + if grp and tarinfo.gname: g = grp.getgrnam(tarinfo.gname)[2] except KeyError: pass try: - if pwd: + if pwd and tarinfo.uname: u = pwd.getpwnam(tarinfo.uname)[2] except KeyError: pass + if g is None: + g = -1 + if u is None: + u = -1 try: if tarinfo.issym() and hasattr(os, "lchown"): os.lchown(targetpath, u, g) @@ -2278,6 +2526,8 @@ def chown(self, tarinfo, targetpath, numeric_owner): def chmod(self, tarinfo, targetpath): """Set file permissions of targetpath according to tarinfo. """ + if tarinfo.mode is None: + return try: os.chmod(targetpath, tarinfo.mode) except OSError: @@ -2286,10 +2536,13 @@ def chmod(self, tarinfo, targetpath): def utime(self, tarinfo, targetpath): """Set modification time of targetpath according to tarinfo. """ + mtime = tarinfo.mtime + if mtime is None: + return if not hasattr(os, 'utime'): return try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) + os.utime(targetpath, (mtime, mtime)) except OSError: raise ExtractError("could not change modification time") @@ -2356,13 +2609,26 @@ def _getmember(self, name, tarinfo=None, normalize=False): members = self.getmembers() # Limit the member search list up to tarinfo. + skipping = False if tarinfo is not None: - members = members[:members.index(tarinfo)] + try: + index = members.index(tarinfo) + except ValueError: + # The given starting point might be a (modified) copy. + # We'll later skip members until we find an equivalent. + skipping = True + else: + # Happy fast path + members = members[:index] if normalize: name = os.path.normpath(name) for member in reversed(members): + if skipping: + if tarinfo.offset == member.offset: + skipping = False + continue if normalize: member_name = os.path.normpath(member.name) else: @@ -2371,6 +2637,10 @@ def _getmember(self, name, tarinfo=None, normalize=False): if name == member_name: return member + if skipping: + # Starting point was not found + raise ValueError(tarinfo) + def _load(self): """Read through the entire archive file and look for readable members. @@ -2463,6 +2733,7 @@ def __exit__(self, type, value, traceback): #-------------------- # exported functions #-------------------- + def is_tarfile(name): """Return True if name points to a tar archive that we are able to handle, else return False. @@ -2484,6 +2755,10 @@ def main(): parser = argparse.ArgumentParser(description=description) parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose output') + parser.add_argument('--filter', metavar='<filtername>', + choices=_NAMED_FILTERS, + help='Filter for extraction') + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-l', '--list', metavar='<tarfile>', help='Show listing of a tarfile') @@ -2495,8 +2770,12 @@ def main(): help='Create tarfile from sources') group.add_argument('-t', '--test', metavar='<tarfile>', help='Test if a tarfile is valid') + args = parser.parse_args() + if args.filter and args.extract is None: + parser.exit(1, '--filter is only valid for extraction\n') + if args.test is not None: src = args.test if is_tarfile(src): @@ -2527,7 +2806,7 @@ def main(): if is_tarfile(src): with TarFile.open(src, 'r:*') as tf: - tf.extractall(path=curdir) + tf.extractall(path=curdir, filter=args.filter) if args.verbose: if curdir == '.': msg = '{!r} file is extracted.'.format(src) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 37940c8dcf71..5cef59ea9c67 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -1458,12 +1458,16 @@ def test_register_archive_format(self): formats = [name for name, params in get_archive_formats()] self.assertNotIn('xxx', formats) - def check_unpack_archive(self, format): - self.check_unpack_archive_with_converter(format, lambda path: path) - self.check_unpack_archive_with_converter(format, pathlib.Path) - self.check_unpack_archive_with_converter(format, FakePath) + ### shutil.unpack_archive - def check_unpack_archive_with_converter(self, format, converter): + def check_unpack_archive(self, format, **kwargs): + self.check_unpack_archive_with_converter( + format, lambda path: path, **kwargs) + self.check_unpack_archive_with_converter( + format, pathlib.Path, **kwargs) + self.check_unpack_archive_with_converter(format, FakePath, **kwargs) + + def check_unpack_archive_with_converter(self, format, converter, **kwargs): root_dir, base_dir = self._create_files() expected = rlistdir(root_dir) expected.remove('outer') @@ -1473,36 +1477,47 @@ def check_unpack_archive_with_converter(self, format, converter): # let's try to unpack it now tmpdir2 = self.mkdtemp() - unpack_archive(converter(filename), converter(tmpdir2)) + unpack_archive(converter(filename), converter(tmpdir2), **kwargs) self.assertEqual(rlistdir(tmpdir2), expected) # and again, this time with the format specified tmpdir3 = self.mkdtemp() - unpack_archive(converter(filename), converter(tmpdir3), format=format) + unpack_archive(converter(filename), converter(tmpdir3), format=format, + **kwargs) self.assertEqual(rlistdir(tmpdir3), expected) - self.assertRaises(shutil.ReadError, unpack_archive, converter(TESTFN)) - self.assertRaises(ValueError, unpack_archive, converter(TESTFN), format='xxx') + with self.assertRaises(shutil.ReadError): + unpack_archive(converter(TESTFN), **kwargs) + with self.assertRaises(ValueError): + unpack_archive(converter(TESTFN), format='xxx', **kwargs) + + def check_unpack_tarball(self, format): + self.check_unpack_archive(format, filter='fully_trusted') + self.check_unpack_archive(format, filter='data') + with support.check_no_warnings(self): + self.check_unpack_archive(format) def test_unpack_archive_tar(self): - self.check_unpack_archive('tar') + self.check_unpack_tarball('tar') @support.requires_zlib def test_unpack_archive_gztar(self): - self.check_unpack_archive('gztar') + self.check_unpack_tarball('gztar') @support.requires_bz2 def test_unpack_archive_bztar(self): - self.check_unpack_archive('bztar') + self.check_unpack_tarball('bztar') @support.requires_lzma @unittest.skipIf(AIX and not _maxdataOK(), "AIX MAXDATA must be 0x20000000 or larger") def test_unpack_archive_xztar(self): - self.check_unpack_archive('xztar') + self.check_unpack_tarball('xztar') @support.requires_zlib def test_unpack_archive_zip(self): self.check_unpack_archive('zip') + with self.assertRaises(TypeError): + self.check_unpack_archive('zip', filter='data') def test_unpack_registry(self): diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index bee00c56d610..03be10b1fee2 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -5,13 +5,17 @@ from contextlib import contextmanager from random import Random import pathlib +import shutil +import re +import warnings +import stat import unittest import unittest.mock import tarfile from test import support -from test.support import script_helper, requires_hashdigest +from test.support import script_helper # Check for our compression modules. try: @@ -2204,7 +2208,12 @@ def test__all__(self): 'EmptyHeaderError', 'TruncatedHeaderError', 'EOFHeaderError', 'InvalidHeaderError', 'SubsequentHeaderError', 'ExFileObject', - 'main'} + 'main', + 'fully_trusted_filter', 'data_filter', + 'tar_filter', 'FilterError', 'AbsoluteLinkError', + 'OutsideDestinationError', 'SpecialFileError', + 'AbsolutePathError', 'LinkOutsideDestinationError', + } support.check__all__(self, tarfile, blacklist=blacklist) @@ -2227,6 +2236,15 @@ def make_simple_tarfile(self, tar_name): for tardata in files: tf.add(tardata, arcname=os.path.basename(tardata)) + def make_evil_tarfile(self, tar_name): + files = [support.findfile('tokenize_tests.txt')] + self.addCleanup(support.unlink, tar_name) + with tarfile.open(tar_name, 'w') as tf: + benign = tarfile.TarInfo('benign') + tf.addfile(benign, fileobj=io.BytesIO(b'')) + evil = tarfile.TarInfo('../evil') + tf.addfile(evil, fileobj=io.BytesIO(b'')) + def test_bad_use(self): rc, out, err = self.tarfilecmd_failure() self.assertEqual(out, b'') @@ -2380,6 +2398,25 @@ def test_extract_command_verbose(self): finally: support.rmtree(tarextdir) + def test_extract_command_filter(self): + self.make_evil_tarfile(tmpname) + # Make an inner directory, so the member named '../evil' + # is still extracted into `tarextdir` + destdir = os.path.join(tarextdir, 'dest') + os.mkdir(tarextdir) + try: + with support.temp_cwd(destdir): + self.tarfilecmd_failure('-e', tmpname, + '-v', + '--filter', 'data') + out = self.tarfilecmd('-e', tmpname, + '-v', + '--filter', 'fully_trusted', + PYTHONIOENCODING='utf-8') + self.assertIn(b' file is extracted.', out) + finally: + support.rmtree(tarextdir) + def test_extract_command_different_directory(self): self.make_simple_tarfile(tmpname) try: @@ -2653,6 +2690,893 @@ def test_keyword_only(self, mock_geteuid): tarfl.extract, filename_1, TEMPDIR, False, True) +class ReplaceTests(ReadTest, unittest.TestCase): + def test_replace_name(self): + member = self.tar.getmember('ustar/regtype') + replaced = member.replace(name='misc/other') + self.assertEqual(replaced.name, 'misc/other') + self.assertEqual(member.name, 'ustar/regtype') + self.assertEqual(self.tar.getmember('ustar/regtype').name, + 'ustar/regtype') + + def test_replace_deep(self): + member = self.tar.getmember('pax/regtype1') + replaced = member.replace() + replaced.pax_headers['gname'] = 'not-bar' + self.assertEqual(member.pax_headers['gname'], 'bar') + self.assertEqual( + self.tar.getmember('pax/regtype1').pax_headers['gname'], 'bar') + + def test_replace_shallow(self): + member = self.tar.getmember('pax/regtype1') + replaced = member.replace(deep=False) + replaced.pax_headers['gname'] = 'not-bar' + self.assertEqual(member.pax_headers['gname'], 'not-bar') + self.assertEqual( + self.tar.getmember('pax/regtype1').pax_headers['gname'], 'not-bar') + + def test_replace_all(self): + member = self.tar.getmember('ustar/regtype') + for attr_name in ('name', 'mtime', 'mode', 'linkname', + 'uid', 'gid', 'uname', 'gname'): + with self.subTest(attr_name=attr_name): + replaced = member.replace(**{attr_name: None}) + self.assertEqual(getattr(replaced, attr_name), None) + self.assertNotEqual(getattr(member, attr_name), None) + + def test_replace_internal(self): + member = self.tar.getmember('ustar/regtype') + with self.assertRaises(TypeError): + member.replace(offset=123456789) + + +class NoneInfoExtractTests(ReadTest): + # These mainly check that all kinds of members are extracted successfully + # if some metadata is None. + # Some of the methods do additional spot checks. + + # We also test that the default filters can deal with None. + + extraction_filter = None + + @classmethod + def setUpClass(cls): + tar = tarfile.open(tarname, mode='r', encoding="iso8859-1") + cls.control_dir = pathlib.Path(TEMPDIR) / "extractall_ctrl" + tar.errorlevel = 0 + tar.extractall(cls.control_dir, filter=cls.extraction_filter) + tar.close() + cls.control_paths = set( + p.relative_to(cls.control_dir) + for p in pathlib.Path(cls.control_dir).glob('**/*')) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(cls.control_dir) + + def check_files_present(self, directory): + got_paths = set( + p.relative_to(directory) + for p in pathlib.Path(directory).glob('**/*')) + self.assertEqual(self.control_paths, got_paths) + + @contextmanager + def extract_with_none(self, *attr_names): + DIR = pathlib.Path(TEMPDIR) / "extractall_none" + self.tar.errorlevel = 0 + for member in self.tar.getmembers(): + for attr_name in attr_names: + setattr(member, attr_name, None) + with support.temp_dir(DIR): + self.tar.extractall(DIR, filter='fully_trusted') + self.check_files_present(DIR) + yield DIR + + def test_extractall_none_mtime(self): + # mtimes of extracted files should be later than 'now' -- the mtime + # of a previously created directory. + now = pathlib.Path(TEMPDIR).stat().st_mtime + with self.extract_with_none('mtime') as DIR: + for path in pathlib.Path(DIR).glob('**/*'): + with self.subTest(path=path): + try: + mtime = path.stat().st_mtime + except OSError: + # Some systems can't stat symlinks, ignore those + if not path.is_symlink(): + raise + else: + self.assertGreaterEqual(path.stat().st_mtime, now) + + def test_extractall_none_mode(self): + # modes of directories and regular files should match the mode + # of a "normally" created directory or regular file + dir_mode = pathlib.Path(TEMPDIR).stat().st_mode + regular_file = pathlib.Path(TEMPDIR) / 'regular_file' + regular_file.write_text('') + regular_file_mode = regular_file.stat().st_mode + with self.extract_with_none('mode') as DIR: + for path in pathlib.Path(DIR).glob('**/*'): + with self.subTest(path=path): + if path.is_dir(): + self.assertEqual(path.stat().st_mode, dir_mode) + elif path.is_file(): + self.assertEqual(path.stat().st_mode, + regular_file_mode) + + def test_extractall_none_uid(self): + with self.extract_with_none('uid'): + pass + + def test_extractall_none_gid(self): + with self.extract_with_none('gid'): + pass + + def test_extractall_none_uname(self): + with self.extract_with_none('uname'): + pass + + def test_extractall_none_gname(self): + with self.extract_with_none('gname'): + pass + + def test_extractall_none_ownership(self): + with self.extract_with_none('uid', 'gid', 'uname', 'gname'): + pass + +class NoneInfoExtractTests_Data(NoneInfoExtractTests, unittest.TestCase): + extraction_filter = 'data' + +class NoneInfoExtractTests_FullyTrusted(NoneInfoExtractTests, + unittest.TestCase): + extraction_filter = 'fully_trusted' + +class NoneInfoExtractTests_Tar(NoneInfoExtractTests, unittest.TestCase): + extraction_filter = 'tar' + +class NoneInfoExtractTests_Default(NoneInfoExtractTests, + unittest.TestCase): + extraction_filter = None + +class NoneInfoTests_Misc(unittest.TestCase): + def test_add(self): + # When addfile() encounters None metadata, it raises a ValueError + bio = io.BytesIO() + for tarformat in (tarfile.USTAR_FORMAT, tarfile.GNU_FORMAT, + tarfile.PAX_FORMAT): + with self.subTest(tarformat=tarformat): + tar = tarfile.open(fileobj=bio, mode='w', format=tarformat) + tarinfo = tar.gettarinfo(tarname) + try: + tar.addfile(tarinfo) + except Exception: + if tarformat == tarfile.USTAR_FORMAT: + # In the old, limited format, adding might fail for + # reasons like the UID being too large + pass + else: + raise + else: + for attr_name in ('mtime', 'mode', 'uid', 'gid', + 'uname', 'gname'): + with self.subTest(attr_name=attr_name): + replaced = tarinfo.replace(**{attr_name: None}) + with self.assertRaisesRegex(ValueError, + f"{attr_name}"): + tar.addfile(replaced) + + def test_list(self): + # Change some metadata to None, then compare list() output + # word-for-word. We want list() to not raise, and to only change + # printout for the affected piece of metadata. + # (n.b.: some contents of the test archive are hardcoded.) + for attr_names in ({'mtime'}, {'mode'}, {'uid'}, {'gid'}, + {'uname'}, {'gname'}, + {'uid', 'uname'}, {'gid', 'gname'}): + with self.subTest(attr_names=attr_names), \ + tarfile.open(tarname, encoding="iso8859-1") as tar: + tio_prev = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') + with support.swap_attr(sys, 'stdout', tio_prev): + tar.list() + for member in tar.getmembers(): + for attr_name in attr_names: + setattr(member, attr_name, None) + tio_new = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n') + with support.swap_attr(sys, 'stdout', tio_new): + tar.list() + for expected, got in zip(tio_prev.detach().getvalue().split(), + tio_new.detach().getvalue().split()): + if attr_names == {'mtime'} and re.match(rb'2003-01-\d\d', expected): + self.assertEqual(got, b'????-??-??') + elif attr_names == {'mtime'} and re.match(rb'\d\d:\d\d:\d\d', expected): + self.assertEqual(got, b'??:??:??') + elif attr_names == {'mode'} and re.match( + rb'.([r-][w-][x-]){3}', expected): + self.assertEqual(got, b'??????????') + elif attr_names == {'uname'} and expected.startswith( + (b'tarfile/', b'lars/', b'foo/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertRegex(got_user, b'[0-9]+') + elif attr_names == {'gname'} and expected.endswith( + (b'/tarfile', b'/users', b'/bar')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertRegex(got_group, b'[0-9]+') + elif attr_names == {'uid'} and expected.startswith( + (b'1000/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertEqual(got_user, b'None') + elif attr_names == {'gid'} and expected.endswith((b'/100')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertEqual(got_group, b'None') + elif attr_names == {'uid', 'uname'} and expected.startswith( + (b'tarfile/', b'lars/', b'foo/', b'1000/')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_group, exp_group) + self.assertEqual(got_user, b'None') + elif attr_names == {'gname', 'gid'} and expected.endswith( + (b'/tarfile', b'/users', b'/bar', b'/100')): + exp_user, exp_group = expected.split(b'/') + got_user, got_group = got.split(b'/') + self.assertEqual(got_user, exp_user) + self.assertEqual(got_group, b'None') + else: + # In other cases the output should be the same + self.assertEqual(expected, got) + +def _filemode_to_int(mode): + """Inverse of `stat.filemode` (for permission bits) + + Using mode strings rather than numbers makes the later tests more readable. + """ + str_mode = mode[1:] + result = ( + {'r': stat.S_IRUSR, '-': 0}[str_mode[0]] + | {'w': stat.S_IWUSR, '-': 0}[str_mode[1]] + | {'x': stat.S_IXUSR, '-': 0, + 's': stat.S_IXUSR | stat.S_ISUID, + 'S': stat.S_ISUID}[str_mode[2]] + | {'r': stat.S_IRGRP, '-': 0}[str_mode[3]] + | {'w': stat.S_IWGRP, '-': 0}[str_mode[4]] + | {'x': stat.S_IXGRP, '-': 0, + 's': stat.S_IXGRP | stat.S_ISGID, + 'S': stat.S_ISGID}[str_mode[5]] + | {'r': stat.S_IROTH, '-': 0}[str_mode[6]] + | {'w': stat.S_IWOTH, '-': 0}[str_mode[7]] + | {'x': stat.S_IXOTH, '-': 0, + 't': stat.S_IXOTH | stat.S_ISVTX, + 'T': stat.S_ISVTX}[str_mode[8]] + ) + # check we did this right + assert stat.filemode(result)[1:] == mode[1:] + + return result + +class ArchiveMaker: + """Helper to create a tar file with specific contents + + Usage: + + with ArchiveMaker() as t: + t.add('filename', ...) + + with t.open() as tar: + ... # `tar` is now a TarFile with 'filename' in it! + """ + def __init__(self): + self.bio = io.BytesIO() + + def __enter__(self): + self.tar_w = tarfile.TarFile(mode='w', fileobj=self.bio) + return self + + def __exit__(self, *exc): + self.tar_w.close() + self.contents = self.bio.getvalue() + self.bio = None + + def add(self, name, *, type=None, symlink_to=None, hardlink_to=None, + mode=None, **kwargs): + """Add a member to the test archive. Call within `with`.""" + name = str(name) + tarinfo = tarfile.TarInfo(name).replace(**kwargs) + if mode: + tarinfo.mode = _filemode_to_int(mode) + if symlink_to is not None: + type = tarfile.SYMTYPE + tarinfo.linkname = str(symlink_to) + if hardlink_to is not None: + type = tarfile.LNKTYPE + tarinfo.linkname = str(hardlink_to) + if name.endswith('/') and type is None: + type = tarfile.DIRTYPE + if type is not None: + tarinfo.type = type + if tarinfo.isreg(): + fileobj = io.BytesIO(bytes(tarinfo.size)) + else: + fileobj = None + self.tar_w.addfile(tarinfo, fileobj) + + def open(self, **kwargs): + """Open the resulting archive as TarFile. Call after `with`.""" + bio = io.BytesIO(self.contents) + return tarfile.open(fileobj=bio, **kwargs) + + +class TestExtractionFilters(unittest.TestCase): + + # A temporary directory for the extraction results. + # All files that "escape" the destination path should still end + # up in this directory. + outerdir = pathlib.Path(TEMPDIR) / 'outerdir' + + # The destination for the extraction, within `outerdir` + destdir = outerdir / 'dest' + + @contextmanager + def check_context(self, tar, filter): + """Extracts `tar` to `self.destdir` and allows checking the result + + If an error occurs, it must be checked using `expect_exception` + + Otherwise, all resulting files must be checked using `expect_file`, + except the destination directory itself and parent directories of + other files. + When checking directories, do so before their contents. + """ + with support.temp_dir(self.outerdir): + try: + tar.extractall(self.destdir, filter=filter) + except Exception as exc: + self.raised_exception = exc + self.expected_paths = set() + else: + self.raised_exception = None + self.expected_paths = set(self.outerdir.glob('**/*')) + self.expected_paths.discard(self.destdir) + try: + yield + finally: + tar.close() + if self.raised_exception: + raise self.raised_exception + self.assertEqual(self.expected_paths, set()) + + def expect_file(self, name, type=None, symlink_to=None, mode=None): + """Check a single file. See check_context.""" + if self.raised_exception: + raise self.raised_exception + # use normpath() rather than resolve() so we don't follow symlinks + path = pathlib.Path(os.path.normpath(self.destdir / name)) + self.assertIn(path, self.expected_paths) + self.expected_paths.remove(path) + + # When checking mode, ignore Windows (which can only set user read and + # user write bits). Newer versions of Python use `os_helper.can_chmod()` + # instead of hardcoding Windows. + if mode is not None and sys.platform != 'win32': + got = stat.filemode(stat.S_IMODE(path.stat().st_mode)) + self.assertEqual(got, mode) + + if type is None and isinstance(name, str) and name.endswith('/'): + type = tarfile.DIRTYPE + if symlink_to is not None: + got = pathlib.Path(os.readlink(self.destdir / name)) + expected = pathlib.Path(symlink_to) + # The symlink might be the same (textually) as what we expect, + # but some systems change the link to an equivalent path, so + # we fall back to samefile(). + if expected != got: + self.assertTrue(got.samefile(expected)) + elif type == tarfile.REGTYPE or type is None: + self.assertTrue(path.is_file()) + elif type == tarfile.DIRTYPE: + self.assertTrue(path.is_dir()) + elif type == tarfile.FIFOTYPE: + self.assertTrue(path.is_fifo()) + else: + raise NotImplementedError(type) + for parent in path.parents: + self.expected_paths.discard(parent) + + def expect_exception(self, exc_type, message_re='.'): + with self.assertRaisesRegex(exc_type, message_re): + if self.raised_exception is not None: + raise self.raised_exception + self.raised_exception = None + + def test_benign_file(self): + with ArchiveMaker() as arc: + arc.add('benign.txt') + for filter in 'fully_trusted', 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_file('benign.txt') + + def test_absolute(self): + # Test handling a member with an absolute path + # Inspired by 'absolute1' in https://github.com/jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add(self.outerdir / 'escaped.evil') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('../escaped.evil') + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + if str(self.outerdir).startswith('/'): + # We strip leading slashes, as e.g. GNU tar does + # (without --absolute-filenames). + outerdir_stripped = str(self.outerdir).lstrip('/') + self.expect_file(f'{outerdir_stripped}/escaped.evil') + else: + # On this system, absolute paths don't have leading + # slashes. + # So, there's nothing to strip. We refuse to unpack + # to an absolute path, nonetheless. + self.expect_exception( + tarfile.AbsolutePathError, + """['"].*escaped.evil['"] has an absolute path""") + + def test_parent_symlink(self): + # Test interplaying symlinks + # Inspired by 'dirsymlink2a' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('current', symlink_to='.') + arc.add('parent', symlink_to='current/..') + arc.add('parent/evil') + + if support.can_symlink(): + with self.check_context(arc.open(), 'fully_trusted'): + if self.raised_exception is not None: + # Windows will refuse to create a file that's a symlink to itself + # (and tarfile doesn't swallow that exception) + self.expect_exception(FileExistsError) + # The other cases will fail with this error too. + # Skip the rest of this test. + return + else: + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='current/..') + self.expect_file('../evil') + + with self.check_context(arc.open(), 'tar'): + self.expect_exception( + tarfile.OutsideDestinationError, + """'parent/evil' would be extracted to ['"].*evil['"], """ + + "which is outside the destination") + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'parent' would link to ['"].*outerdir['"], """ + + "which is outside the destination") + + else: + # No symlink support. The symlinks are ignored. + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('parent/evil') + with self.check_context(arc.open(), 'tar'): + self.expect_file('parent/evil') + with self.check_context(arc.open(), 'data'): + self.expect_file('parent/evil') + + def test_parent_symlink2(self): + # Test interplaying symlinks + # Inspired by 'dirsymlink2b' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('current', symlink_to='.') + arc.add('current/parent', symlink_to='..') + arc.add('parent/evil') + + with self.check_context(arc.open(), 'fully_trusted'): + if support.can_symlink(): + self.expect_file('current', symlink_to='.') + self.expect_file('parent', symlink_to='..') + self.expect_file('../evil') + else: + self.expect_file('current/') + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'tar'): + if support.can_symlink(): + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + self.expect_file('current/') + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.LinkOutsideDestinationError, + """'current/parent' would link to ['"].*['"], """ + + "which is outside the destination") + + def test_absolute_symlink(self): + # Test symlink to an absolute path + # Inspired by 'dirsymlink' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('parent', symlink_to=self.outerdir) + arc.add('parent/evil') + + with self.check_context(arc.open(), 'fully_trusted'): + if support.can_symlink(): + self.expect_file('parent', symlink_to=self.outerdir) + self.expect_file('../evil') + else: + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'tar'): + if support.can_symlink(): + self.expect_exception( + tarfile.OutsideDestinationError, + "'parent/evil' would be extracted to " + + """['"].*evil['"], which is outside """ + + "the destination") + else: + self.expect_file('parent/evil') + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.AbsoluteLinkError, + "'parent' is a symlink to an absolute path") + + def test_sly_relative0(self): + # Inspired by 'relative0' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('../moo', symlink_to='..//tmp/moo') + + try: + with self.check_context(arc.open(), filter='fully_trusted'): + if support.can_symlink(): + if isinstance(self.raised_exception, FileExistsError): + # XXX TarFile happens to fail creating a parent + # directory. + # This might be a bug, but fixing it would hurt + # security. + # Note that e.g. GNU `tar` rejects '..' components, + # so you could argue this is an invalid archive and we + # just raise an bad type of exception. + self.expect_exception(FileExistsError) + else: + self.expect_file('../moo', symlink_to='..//tmp/moo') + else: + # The symlink can't be extracted and is ignored + pass + except FileExistsError: + pass + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_exception( + tarfile.OutsideDestinationError, + "'../moo' would be extracted to " + + "'.*moo', which is outside " + + "the destination") + + def test_sly_relative2(self): + # Inspired by 'relative2' in jwilk/traversal-archives + with ArchiveMaker() as arc: + arc.add('tmp/') + arc.add('tmp/../../moo', symlink_to='tmp/../..//tmp/moo') + + with self.check_context(arc.open(), 'fully_trusted'): + self.expect_file('tmp', type=tarfile.DIRTYPE) + if support.can_symlink(): + self.expect_file('../moo', symlink_to='tmp/../../tmp/moo') + + for filter in 'tar', 'data': + with self.check_context(arc.open(), filter): + self.expect_exception( + tarfile.OutsideDestinationError, + "'tmp/../../moo' would be extracted to " + + """['"].*moo['"], which is outside the """ + + "destination") + + def test_modes(self): + # Test how file modes are extracted + # (Note that the modes are ignored on platforms without working chmod) + with ArchiveMaker() as arc: + arc.add('all_bits', mode='?rwsrwsrwt') + arc.add('perm_bits', mode='?rwxrwxrwx') + arc.add('exec_group_other', mode='?rw-rwxrwx') + arc.add('read_group_only', mode='?---r-----') + arc.add('no_bits', mode='?---------') + arc.add('dir/', mode='?---rwsrwt') + + # On some systems, setting the sticky bit is a no-op. + # Check if that's the case. + tmp_filename = os.path.join(TEMPDIR, "tmp.file") + with open(tmp_filename, 'w'): + pass + os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) + have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + os.unlink(tmp_filename) + + os.mkdir(tmp_filename) + os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) + have_sticky_dirs = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + os.rmdir(tmp_filename) + + with self.check_context(arc.open(), 'fully_trusted'): + if have_sticky_files: + self.expect_file('all_bits', mode='?rwsrwsrwt') + else: + self.expect_file('all_bits', mode='?rwsrwsrwx') + self.expect_file('perm_bits', mode='?rwxrwxrwx') + self.expect_file('exec_group_other', mode='?rw-rwxrwx') + self.expect_file('read_group_only', mode='?---r-----') + self.expect_file('no_bits', mode='?---------') + if have_sticky_dirs: + self.expect_file('dir/', mode='?---rwsrwt') + else: + self.expect_file('dir/', mode='?---rwsrwx') + + with self.check_context(arc.open(), 'tar'): + self.expect_file('all_bits', mode='?rwxr-xr-x') + self.expect_file('perm_bits', mode='?rwxr-xr-x') + self.expect_file('exec_group_other', mode='?rw-r-xr-x') + self.expect_file('read_group_only', mode='?---r-----') + self.expect_file('no_bits', mode='?---------') + self.expect_file('dir/', mode='?---r-xr-x') + + with self.check_context(arc.open(), 'data'): + normal_dir_mode = stat.filemode(stat.S_IMODE( + self.outerdir.stat().st_mode)) + self.expect_file('all_bits', mode='?rwxr-xr-x') + self.expect_file('perm_bits', mode='?rwxr-xr-x') + self.expect_file('exec_group_other', mode='?rw-r--r--') + self.expect_file('read_group_only', mode='?rw-r-----') + self.expect_file('no_bits', mode='?rw-------') + self.expect_file('dir/', mode=normal_dir_mode) + + def test_pipe(self): + # Test handling of a special file + with ArchiveMaker() as arc: + arc.add('foo', type=tarfile.FIFOTYPE) + + for filter in 'fully_trusted', 'tar': + with self.check_context(arc.open(), filter): + if hasattr(os, 'mkfifo'): + self.expect_file('foo', type=tarfile.FIFOTYPE) + else: + # The pipe can't be extracted and is skipped. + pass + + with self.check_context(arc.open(), 'data'): + self.expect_exception( + tarfile.SpecialFileError, + "'foo' is a special file") + + def test_special_files(self): + # Creating device files is tricky. Instead of attempting that let's + # only check the filter result. + for special_type in tarfile.FIFOTYPE, tarfile.CHRTYPE, tarfile.BLKTYPE: + tarinfo = tarfile.TarInfo('foo') + tarinfo.type = special_type + trusted = tarfile.fully_trusted_filter(tarinfo, '') + self.assertIs(trusted, tarinfo) + tar = tarfile.tar_filter(tarinfo, '') + self.assertEqual(tar.type, special_type) + with self.assertRaises(tarfile.SpecialFileError) as cm: + tarfile.data_filter(tarinfo, '') + self.assertIsInstance(cm.exception.tarinfo, tarfile.TarInfo) + self.assertEqual(cm.exception.tarinfo.name, 'foo') + + def test_fully_trusted_filter(self): + # The 'fully_trusted' filter returns the original TarInfo objects. + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + filtered = tarfile.fully_trusted_filter(tarinfo, '') + self.assertIs(filtered, tarinfo) + + def test_tar_filter(self): + # The 'tar' filter returns TarInfo objects with the same name/type. + # (It can also fail for particularly "evil" input, but we don't have + # that in the test archive.) + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + filtered = tarfile.tar_filter(tarinfo, '') + self.assertIs(filtered.name, tarinfo.name) + self.assertIs(filtered.type, tarinfo.type) + + def test_data_filter(self): + # The 'data' filter either raises, or returns TarInfo with the same + # name/type. + with tarfile.TarFile.open(tarname) as tar: + for tarinfo in tar.getmembers(): + try: + filtered = tarfile.data_filter(tarinfo, '') + except tarfile.FilterError: + continue + self.assertIs(filtered.name, tarinfo.name) + self.assertIs(filtered.type, tarinfo.type) + + def test_default_filter_warns_not(self): + """Ensure the default filter does not warn (like in 3.12)""" + with ArchiveMaker() as arc: + arc.add('foo') + with support.check_no_warnings(self): + with self.check_context(arc.open(), None): + self.expect_file('foo') + + def test_change_default_filter_on_instance(self): + tar = tarfile.TarFile(tarname, 'r') + def strict_filter(tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + tar.extraction_filter = strict_filter + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_on_class(self): + def strict_filter(tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + tar = tarfile.TarFile(tarname, 'r') + with support.swap_attr(tarfile.TarFile, 'extraction_filter', + staticmethod(strict_filter)): + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_on_subclass(self): + class TarSubclass(tarfile.TarFile): + def extraction_filter(self, tarinfo, path): + if tarinfo.name == 'ustar/regtype': + return tarinfo + else: + return None + + tar = TarSubclass(tarname, 'r') + with self.check_context(tar, None): + self.expect_file('ustar/regtype') + + def test_change_default_filter_to_string(self): + tar = tarfile.TarFile(tarname, 'r') + tar.extraction_filter = 'data' + with self.check_context(tar, None): + self.expect_exception(TypeError) + + def test_custom_filter(self): + def custom_filter(tarinfo, path): + self.assertIs(path, self.destdir) + if tarinfo.name == 'move_this': + return tarinfo.replace(name='moved') + if tarinfo.name == 'ignore_this': + return None + return tarinfo + + with ArchiveMaker() as arc: + arc.add('move_this') + arc.add('ignore_this') + arc.add('keep') + with self.check_context(arc.open(), custom_filter): + self.expect_file('moved') + self.expect_file('keep') + + def test_bad_filter_name(self): + with ArchiveMaker() as arc: + arc.add('foo') + with self.check_context(arc.open(), 'bad filter name'): + self.expect_exception(ValueError) + + def test_stateful_filter(self): + # Stateful filters should be possible. + # (This doesn't really test tarfile. Rather, it demonstrates + # that third parties can implement a stateful filter.) + class StatefulFilter: + def __enter__(self): + self.num_files_processed = 0 + return self + + def __call__(self, tarinfo, path): + try: + tarinfo = tarfile.data_filter(tarinfo, path) + except tarfile.FilterError: + return None + self.num_files_processed += 1 + return tarinfo + + def __exit__(self, *exc_info): + self.done = True + + with ArchiveMaker() as arc: + arc.add('good') + arc.add('bad', symlink_to='/') + arc.add('good') + with StatefulFilter() as custom_filter: + with self.check_context(arc.open(), custom_filter): + self.expect_file('good') + self.assertEqual(custom_filter.num_files_processed, 2) + self.assertEqual(custom_filter.done, True) + + def test_errorlevel(self): + def extracterror_filter(tarinfo, path): + raise tarfile.ExtractError('failed with ExtractError') + def filtererror_filter(tarinfo, path): + raise tarfile.FilterError('failed with FilterError') + def oserror_filter(tarinfo, path): + raise OSError('failed with OSError') + def tarerror_filter(tarinfo, path): + raise tarfile.TarError('failed with base TarError') + def valueerror_filter(tarinfo, path): + raise ValueError('failed with ValueError') + + with ArchiveMaker() as arc: + arc.add('file') + + # If errorlevel is 0, errors affected by errorlevel are ignored + + with self.check_context(arc.open(errorlevel=0), extracterror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), filtererror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), oserror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=0), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=0), valueerror_filter): + self.expect_exception(ValueError) + + # If 1, all fatal errors are raised + + with self.check_context(arc.open(errorlevel=1), extracterror_filter): + self.expect_file('file') + + with self.check_context(arc.open(errorlevel=1), filtererror_filter): + self.expect_exception(tarfile.FilterError) + + with self.check_context(arc.open(errorlevel=1), oserror_filter): + self.expect_exception(OSError) + + with self.check_context(arc.open(errorlevel=1), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=1), valueerror_filter): + self.expect_exception(ValueError) + + # If 2, all non-fatal errors are raised as well. + + with self.check_context(arc.open(errorlevel=2), extracterror_filter): + self.expect_exception(tarfile.ExtractError) + + with self.check_context(arc.open(errorlevel=2), filtererror_filter): + self.expect_exception(tarfile.FilterError) + + with self.check_context(arc.open(errorlevel=2), oserror_filter): + self.expect_exception(OSError) + + with self.check_context(arc.open(errorlevel=2), tarerror_filter): + self.expect_exception(tarfile.TarError) + + with self.check_context(arc.open(errorlevel=2), valueerror_filter): + self.expect_exception(ValueError) + + # We only handle ExtractionError, FilterError & OSError specially. + + with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter): + self.expect_exception(TypeError) # errorlevel is not int + + def setUpModule(): support.unlink(TEMPDIR) os.makedirs(TEMPDIR) diff --git a/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst new file mode 100644 index 000000000000..48a105a4a17b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst @@ -0,0 +1,4 @@ +The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, +have a new a *filter* argument that allows limiting tar features than may be +surprising or dangerous, such as creating files outside the destination +directory. See :ref:`tarfile-extraction-filter` for details. From webhook-mailer at python.org Wed May 17 09:04:06 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 17 May 2023 13:04:06 -0000 Subject: [Python-checkins] typing: Use PEP 695 syntax in typing.py (#104553) Message-ID: <mailman.407.1684328647.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0cb2fdc6217aa7c04b5c798cfd195c8d0f4af353 commit: 0cb2fdc6217aa7c04b5c798cfd195c8d0f4af353 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-17T06:03:58-07:00 summary: typing: Use PEP 695 syntax in typing.py (#104553) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 50a8f5159458..82107300734a 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2471,8 +2471,9 @@ class Other(Leaf): # Error reported by type checker return f -# Some unconstrained type variables. These are used by the container types. -# (These are not for export.) +# Some unconstrained type variables. These were initially used by the container types. +# They were never meant for export and are now unused, but we keep them around to +# avoid breaking compatibility with users who import them. T = TypeVar('T') # Any type. KT = TypeVar('KT') # Key type. VT = TypeVar('VT') # Value type. @@ -2577,8 +2578,6 @@ def new_user(user_class: Type[U]) -> U: At this point the type checker knows that joe has type BasicUser. """ -# Internal type variable for callables. Not for export. -F = TypeVar("F", bound=Callable[..., Any]) @runtime_checkable class SupportsInt(Protocol): @@ -2631,22 +2630,22 @@ def __index__(self) -> int: @runtime_checkable -class SupportsAbs(Protocol[T_co]): +class SupportsAbs[T](Protocol): """An ABC with one abstract method __abs__ that is covariant in its return type.""" __slots__ = () @abstractmethod - def __abs__(self) -> T_co: + def __abs__(self) -> T: pass @runtime_checkable -class SupportsRound(Protocol[T_co]): +class SupportsRound[T](Protocol): """An ABC with one abstract method __round__ that is covariant in its return type.""" __slots__ = () @abstractmethod - def __round__(self, ndigits: int = 0) -> T_co: + def __round__(self, ndigits: int = 0) -> T: pass @@ -3183,7 +3182,7 @@ class re(metaclass=_DeprecatedType): sys.modules[re.__name__] = re -def reveal_type(obj: T, /) -> T: +def reveal_type[T](obj: T, /) -> T: """Reveal the inferred type of a variable. When a static type checker encounters a call to ``reveal_type()``, @@ -3203,6 +3202,11 @@ def reveal_type(obj: T, /) -> T: return obj +class _IdentityCallable(Protocol): + def __call__[T](self, arg: T, /) -> T: + ... + + def dataclass_transform( *, eq_default: bool = True, @@ -3211,7 +3215,7 @@ def dataclass_transform( frozen_default: bool = False, field_specifiers: tuple[type[Any] | Callable[..., Any], ...] = (), **kwargs: Any, -) -> Callable[[T], T]: +) -> _IdentityCallable: """Decorator that marks a function, class, or metaclass as providing dataclass-like behavior. @@ -3288,8 +3292,10 @@ def decorator(cls_or_fn): return decorator +type _Func = Callable[..., Any] + -def override(method: F, /) -> F: +def override[F: _Func](method: F, /) -> F: """Indicate that a method is intended to override a method in a base class. Usage: From webhook-mailer at python.org Wed May 17 09:05:50 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 17 May 2023 13:05:50 -0000 Subject: [Python-checkins] gh-104572: Improve error messages for invalid constructs in PEP 695 contexts (#104573) Message-ID: <mailman.408.1684328752.13550.python-checkins@python.org> https://github.com/python/cpython/commit/97db2f3e07bf7d56750e215e4f32653bf3867ef8 commit: 97db2f3e07bf7d56750e215e4f32653bf3867ef8 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-17T06:05:42-07:00 summary: gh-104572: Improve error messages for invalid constructs in PEP 695 contexts (#104573) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst M Lib/test/test_syntax.py M Python/symtable.c diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index f959bbb44007..477879db2fd4 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1877,6 +1877,68 @@ def f(x: *b) ^^^^^^^^^^^ SyntaxError: bytes can only contain ASCII literal characters +Invalid expressions in type scopes: + + >>> type A[T: (x:=3)] = int + Traceback (most recent call last): + ... + SyntaxError: named expression cannot be used within a TypeVar bound + + >>> type A[T: (yield 3)] = int + Traceback (most recent call last): + ... + SyntaxError: yield expression cannot be used within a TypeVar bound + + >>> type A[T: (await 3)] = int + Traceback (most recent call last): + ... + SyntaxError: await expression cannot be used within a TypeVar bound + + >>> type A[T: (yield from [])] = int + Traceback (most recent call last): + ... + SyntaxError: yield expression cannot be used within a TypeVar bound + + >>> type A = (x := 3) + Traceback (most recent call last): + ... + SyntaxError: named expression cannot be used within a type alias + + >>> type A = (yield 3) + Traceback (most recent call last): + ... + SyntaxError: yield expression cannot be used within a type alias + + >>> type A = (await 3) + Traceback (most recent call last): + ... + SyntaxError: await expression cannot be used within a type alias + + >>> type A = (yield from []) + Traceback (most recent call last): + ... + SyntaxError: yield expression cannot be used within a type alias + + >>> class A[T]((x := 3)): ... + Traceback (most recent call last): + ... + SyntaxError: named expression cannot be used within the definition of a generic + + >>> class A[T]((yield 3)): ... + Traceback (most recent call last): + ... + SyntaxError: yield expression cannot be used within the definition of a generic + + >>> class A[T]((await 3)): ... + Traceback (most recent call last): + ... + SyntaxError: await expression cannot be used within the definition of a generic + + >>> class A[T]((yield from [])): ... + Traceback (most recent call last): + ... + SyntaxError: yield expression cannot be used within the definition of a generic + """ import re diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst new file mode 100644 index 000000000000..25bad8aa6e3e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst @@ -0,0 +1,2 @@ +Improve syntax error message for invalid constructs in :pep:`695` contexts +and in annotations when ``from __future__ import annotations`` is active. diff --git a/Python/symtable.c b/Python/symtable.c index 3451f6c7bffb..f896f7cbe338 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -45,16 +45,16 @@ "assignment expression cannot be used in a comprehension iterable expression" #define ANNOTATION_NOT_ALLOWED \ -"'%s' can not be used within an annotation" +"%s cannot be used within an annotation" #define TYPEVAR_BOUND_NOT_ALLOWED \ -"'%s' can not be used within a TypeVar bound" +"%s cannot be used within a TypeVar bound" #define TYPEALIAS_NOT_ALLOWED \ -"'%s' can not be used within a type alias" +"%s cannot be used within a type alias" #define TYPEPARAM_NOT_ALLOWED \ -"'%s' can not be used within the definition of a generic" +"%s cannot be used within the definition of a generic" #define DUPLICATE_TYPE_PARAM \ "duplicate type parameter '%U'" From webhook-mailer at python.org Wed May 17 09:08:29 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 17 May 2023 13:08:29 -0000 Subject: [Python-checkins] typing: Add more tests for TypeVar (#104571) Message-ID: <mailman.409.1684328909.13550.python-checkins@python.org> https://github.com/python/cpython/commit/26931944dd8abd6554249239344fa62b789b9028 commit: 26931944dd8abd6554249239344fa62b789b9028 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-17T06:08:21-07:00 summary: typing: Add more tests for TypeVar (#104571) During the PEP 695 implementation at one point I made TypeVar.__name__ return garbage, and all of test_typing passed. So I decided to add a few more tests. In the process I discovered a minor incompatibility from the C implementation of TypeVar: empty constraints were returned as None instead of an empty tuple. files: M Lib/test/test_type_params.py M Lib/test/test_typing.py M Objects/typevarobject.c diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 3ca13c21c61a..96bd1fa0bab9 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -425,11 +425,11 @@ class Foo[T: Foo, U: (Foo, Foo)]: type_params = Foo.__type_params__ self.assertEqual(len(type_params), 2) self.assertEqual(type_params[0].__name__, "T") - self.assertEqual(type_params[0].__bound__, Foo) - self.assertEqual(type_params[0].__constraints__, None) + self.assertIs(type_params[0].__bound__, Foo) + self.assertEqual(type_params[0].__constraints__, ()) self.assertEqual(type_params[1].__name__, "U") - self.assertEqual(type_params[1].__bound__, None) + self.assertIs(type_params[1].__bound__, None) self.assertEqual(type_params[1].__constraints__, (Foo, Foo)) def test_evaluation_error(self): @@ -439,16 +439,16 @@ class Foo[T: Undefined, U: (Undefined,)]: type_params = Foo.__type_params__ with self.assertRaises(NameError): type_params[0].__bound__ - self.assertEqual(type_params[0].__constraints__, None) - self.assertEqual(type_params[1].__bound__, None) + self.assertEqual(type_params[0].__constraints__, ()) + self.assertIs(type_params[1].__bound__, None) with self.assertRaises(NameError): type_params[1].__constraints__ Undefined = "defined" self.assertEqual(type_params[0].__bound__, "defined") - self.assertEqual(type_params[0].__constraints__, None) + self.assertEqual(type_params[0].__constraints__, ()) - self.assertEqual(type_params[1].__bound__, None) + self.assertIs(type_params[1].__bound__, None) self.assertEqual(type_params[1].__constraints__, ("defined",)) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 0cd67c51e508..045f2a3b4dfe 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -367,6 +367,41 @@ def test_basic_plain(self): self.assertEqual(T, T) # T is an instance of TypeVar self.assertIsInstance(T, TypeVar) + self.assertEqual(T.__name__, 'T') + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, None) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, False) + self.assertIs(T.__infer_variance__, False) + + def test_attributes(self): + T_bound = TypeVar('T_bound', bound=int) + self.assertEqual(T_bound.__name__, 'T_bound') + self.assertEqual(T_bound.__constraints__, ()) + self.assertIs(T_bound.__bound__, int) + + T_constraints = TypeVar('T_constraints', int, str) + self.assertEqual(T_constraints.__name__, 'T_constraints') + self.assertEqual(T_constraints.__constraints__, (int, str)) + self.assertIs(T_constraints.__bound__, None) + + T_co = TypeVar('T_co', covariant=True) + self.assertEqual(T_co.__name__, 'T_co') + self.assertIs(T_co.__covariant__, True) + self.assertIs(T_co.__contravariant__, False) + self.assertIs(T_co.__infer_variance__, False) + + T_contra = TypeVar('T_contra', contravariant=True) + self.assertEqual(T_contra.__name__, 'T_contra') + self.assertIs(T_contra.__covariant__, False) + self.assertIs(T_contra.__contravariant__, True) + self.assertIs(T_contra.__infer_variance__, False) + + T_infer = TypeVar('T_infer', infer_variance=True) + self.assertEqual(T_infer.__name__, 'T_infer') + self.assertIs(T_infer.__covariant__, False) + self.assertIs(T_infer.__contravariant__, False) + self.assertIs(T_infer.__infer_variance__, True) def test_typevar_instance_type_error(self): T = TypeVar('T') @@ -458,6 +493,12 @@ def test_no_bivariant(self): with self.assertRaises(ValueError): TypeVar('T', covariant=True, contravariant=True) + def test_cannot_combine_explicit_and_infer(self): + with self.assertRaises(ValueError): + TypeVar('T', covariant=True, infer_variance=True) + with self.assertRaises(ValueError): + TypeVar('T', contravariant=True, infer_variance=True) + def test_var_substitution(self): T = TypeVar('T') subst = T.__typing_subst__ @@ -7812,6 +7853,7 @@ def test_basic_plain(self): P = ParamSpec('P') self.assertEqual(P, P) self.assertIsInstance(P, ParamSpec) + self.assertEqual(P.__name__, 'P') def test_valid_uses(self): P = ParamSpec('P') diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index b0578756f7df..4464e7a9da89 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -271,7 +271,7 @@ typevar_constraints(typevarobject *self, void *Py_UNUSED(ignored)) return Py_NewRef(self->constraints); } if (self->evaluate_constraints == NULL) { - Py_RETURN_NONE; + return PyTuple_New(0); } PyObject *constraints = PyObject_CallNoArgs(self->evaluate_constraints); self->constraints = Py_XNewRef(constraints); From webhook-mailer at python.org Wed May 17 09:17:24 2023 From: webhook-mailer at python.org (markshannon) Date: Wed, 17 May 2023 13:17:24 -0000 Subject: [Python-checkins] GH-101520: Move tracemalloc functionality into core, leaving interface in Modules. (#104508) Message-ID: <mailman.410.1684329446.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f7df17394906f2af51afef3c8ccaaab3847b059c commit: f7df17394906f2af51afef3c8ccaaab3847b059c branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-17T14:17:16+01:00 summary: GH-101520: Move tracemalloc functionality into core, leaving interface in Modules. (#104508) files: A Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst A Python/tracemalloc.c M Include/internal/pycore_pylifecycle.h M Include/tracemalloc.h M Makefile.pre.in M Modules/_tracemalloc.c M PCbuild/_freeze_module.vcxproj M PCbuild/_freeze_module.vcxproj.filters M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/pylifecycle.c diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 7f8cc643ec0c..7cd998a704c8 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -31,7 +31,6 @@ PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc); extern void _Py_InitVersion(void); extern PyStatus _PyFaulthandler_Init(int enable); -extern int _PyTraceMalloc_Init(int enable); extern PyObject * _PyBuiltin_Init(PyInterpreterState *interp); extern PyStatus _PySys_Create( PyThreadState *tstate, diff --git a/Include/tracemalloc.h b/Include/tracemalloc.h index bd14217c199c..580027a8e365 100644 --- a/Include/tracemalloc.h +++ b/Include/tracemalloc.h @@ -33,6 +33,40 @@ PyAPI_FUNC(int) PyTraceMalloc_Untrack( PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback( unsigned int domain, uintptr_t ptr); + +/* Return non-zero if tracemalloc is tracing */ +PyAPI_FUNC(int) _PyTraceMalloc_IsTracing(void); + +/* Clear the tracemalloc traces */ +PyAPI_FUNC(void) _PyTraceMalloc_ClearTraces(void); + +/* Clear the tracemalloc traces */ +PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTraces(void); + +/* Clear tracemalloc traceback for an object */ +PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetObjectTraceback(PyObject *obj); + +/* Initialize tracemalloc */ +PyAPI_FUNC(int) _PyTraceMalloc_Init(void); + +/* Start tracemalloc */ +PyAPI_FUNC(int) _PyTraceMalloc_Start(int max_nframe); + +/* Stop tracemalloc */ +PyAPI_FUNC(void) _PyTraceMalloc_Stop(void); + +/* Get the tracemalloc traceback limit */ +PyAPI_FUNC(int) _PyTraceMalloc_GetTracebackLimit(void); + +/* Get the memory usage of tracemalloc in bytes */ +PyAPI_FUNC(size_t) _PyTraceMalloc_GetMemory(void); + +/* Get the current size and peak size of traced memory blocks as a 2-tuple */ +PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTracedMemory(void); + +/* Set the peak size of traced memory blocks to the current size */ +PyAPI_FUNC(void) _PyTraceMalloc_ResetPeak(void); + #endif #endif /* !Py_TRACEMALLOC_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 8f43def305f3..da3a8f6c13f9 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -421,6 +421,7 @@ PYTHON_OBJS= \ Python/sysmodule.o \ Python/thread.o \ Python/traceback.o \ + Python/tracemalloc.o \ Python/getopt.o \ Python/pystrcmp.o \ Python/pystrtod.o \ diff --git a/Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst b/Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst new file mode 100644 index 000000000000..5e8bf967bfdc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst @@ -0,0 +1,2 @@ +Move the core functionality of the ``tracemalloc`` module in the ``Python/`` +folder, leaving just the module wrapper in ``Modules/``. diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index c5714d5e7d5a..f3f4af9aba08 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -1,987 +1,12 @@ #include "Python.h" -#include "pycore_fileutils.h" // _Py_write_noraise() -#include "pycore_gc.h" // PyGC_Head -#include "pycore_hashtable.h" // _Py_hashtable_t -#include "pycore_object.h" // _PyType_PreHeaderSize -#include "pycore_pymem.h" // _Py_tracemalloc_config -#include "pycore_runtime.h" // _Py_ID() -#include "pycore_traceback.h" -#include <pycore_frame.h> -#include "frameobject.h" // _PyInterpreterFrame_GetLine -#include <stdlib.h> // malloc() - -#include "clinic/_tracemalloc.c.h" - -/*[clinic input] -module _tracemalloc -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/ - -#define tracemalloc_config _PyRuntime.tracemalloc.config - -_Py_DECLARE_STR(anon_unknown, "<unknown>"); - -/* Forward declaration */ -static void tracemalloc_stop(void); -static void* raw_malloc(size_t size); -static void raw_free(void *ptr); - -#ifdef Py_DEBUG -# define TRACE_DEBUG -#endif - -#define TO_PTR(key) ((const void *)(uintptr_t)(key)) -#define FROM_PTR(key) ((uintptr_t)(key)) - -#define allocators _PyRuntime.tracemalloc.allocators - - -#if defined(TRACE_RAW_MALLOC) -/* This lock is needed because tracemalloc_free() is called without - the GIL held from PyMem_RawFree(). It cannot acquire the lock because it - would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ -# define tables_lock _PyRuntime.tracemalloc.tables_lock -# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) -# define TABLES_UNLOCK() PyThread_release_lock(tables_lock) -#else - /* variables are protected by the GIL */ -# define TABLES_LOCK() -# define TABLES_UNLOCK() -#endif - - -#define DEFAULT_DOMAIN 0 - -typedef struct tracemalloc_frame frame_t; -typedef struct tracemalloc_traceback traceback_t; - -#define TRACEBACK_SIZE(NFRAME) \ - (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) - -/* The maximum number of frames is either: - - The maximum number of frames we can store in `traceback_t.nframe` - - The maximum memory size_t we can allocate */ -static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1)); - - -#define tracemalloc_empty_traceback _PyRuntime.tracemalloc.empty_traceback - - -/* Trace of a memory block */ -typedef struct { - /* Size of the memory block in bytes */ - size_t size; - - /* Traceback where the memory block was allocated */ - traceback_t *traceback; -} trace_t; - - -#define tracemalloc_traced_memory _PyRuntime.tracemalloc.traced_memory -#define tracemalloc_peak_traced_memory _PyRuntime.tracemalloc.peak_traced_memory -#define tracemalloc_filenames _PyRuntime.tracemalloc.filenames -#define tracemalloc_traceback _PyRuntime.tracemalloc.traceback -#define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks -#define tracemalloc_traces _PyRuntime.tracemalloc.traces -#define tracemalloc_domains _PyRuntime.tracemalloc.domains - - -#ifdef TRACE_DEBUG -static void -tracemalloc_error(const char *format, ...) -{ - va_list ap; - fprintf(stderr, "tracemalloc: "); - va_start(ap, format); - vfprintf(stderr, format, ap); - va_end(ap); - fprintf(stderr, "\n"); - fflush(stderr); -} -#endif - - -#if defined(TRACE_RAW_MALLOC) -#define REENTRANT_THREADLOCAL - -#define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key - -/* Any non-NULL pointer can be used */ -#define REENTRANT Py_True - -static int -get_reentrant(void) -{ - void *ptr; - - assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); - ptr = PyThread_tss_get(&tracemalloc_reentrant_key); - if (ptr != NULL) { - assert(ptr == REENTRANT); - return 1; - } - else - return 0; -} - -static void -set_reentrant(int reentrant) -{ - assert(reentrant == 0 || reentrant == 1); - assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); - - if (reentrant) { - assert(!get_reentrant()); - PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT); - } - else { - assert(get_reentrant()); - PyThread_tss_set(&tracemalloc_reentrant_key, NULL); - } -} - -#else - -/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ -static int tracemalloc_reentrant = 0; - -static int -get_reentrant(void) -{ - return tracemalloc_reentrant; -} - -static void -set_reentrant(int reentrant) -{ - assert(reentrant != tracemalloc_reentrant); - tracemalloc_reentrant = reentrant; -} -#endif - - -static Py_uhash_t -hashtable_hash_pyobject(const void *key) -{ - PyObject *obj = (PyObject *)key; - return PyObject_Hash(obj); -} - - -static int -hashtable_compare_unicode(const void *key1, const void *key2) -{ - PyObject *obj1 = (PyObject *)key1; - PyObject *obj2 = (PyObject *)key2; - if (obj1 != NULL && obj2 != NULL) { - return (PyUnicode_Compare(obj1, obj2) == 0); - } - else { - return obj1 == obj2; - } -} - - -static Py_uhash_t -hashtable_hash_uint(const void *key_raw) -{ - unsigned int key = (unsigned int)FROM_PTR(key_raw); - return (Py_uhash_t)key; -} - - -static _Py_hashtable_t * -hashtable_new(_Py_hashtable_hash_func hash_func, - _Py_hashtable_compare_func compare_func, - _Py_hashtable_destroy_func key_destroy_func, - _Py_hashtable_destroy_func value_destroy_func) -{ - _Py_hashtable_allocator_t hashtable_alloc = {malloc, free}; - return _Py_hashtable_new_full(hash_func, compare_func, - key_destroy_func, value_destroy_func, - &hashtable_alloc); -} - - -static void* -raw_malloc(size_t size) -{ - return allocators.raw.malloc(allocators.raw.ctx, size); -} - -static void -raw_free(void *ptr) -{ - allocators.raw.free(allocators.raw.ctx, ptr); -} - - -static Py_uhash_t -hashtable_hash_traceback(const void *key) -{ - const traceback_t *traceback = (const traceback_t *)key; - return traceback->hash; -} - - -static int -hashtable_compare_traceback(const void *key1, const void *key2) -{ - const traceback_t *traceback1 = (const traceback_t *)key1; - const traceback_t *traceback2 = (const traceback_t *)key2; - - if (traceback1->nframe != traceback2->nframe) { - return 0; - } - if (traceback1->total_nframe != traceback2->total_nframe) { - return 0; - } - - for (int i=0; i < traceback1->nframe; i++) { - const frame_t *frame1 = &traceback1->frames[i]; - const frame_t *frame2 = &traceback2->frames[i]; - - if (frame1->lineno != frame2->lineno) { - return 0; - } - if (frame1->filename != frame2->filename) { - assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0); - return 0; - } - } - return 1; -} - - -static void -tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) -{ - frame->filename = &_Py_STR(anon_unknown); - int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); - if (lineno < 0) { - lineno = 0; - } - frame->lineno = (unsigned int)lineno; - - PyObject *filename = pyframe->f_code->co_filename; - - if (filename == NULL) { -#ifdef TRACE_DEBUG - tracemalloc_error("failed to get the filename of the code object"); -#endif - return; - } - - if (!PyUnicode_Check(filename)) { -#ifdef TRACE_DEBUG - tracemalloc_error("filename is not a unicode string"); -#endif - return; - } - if (!PyUnicode_IS_READY(filename)) { - /* Don't make a Unicode string ready to avoid reentrant calls - to tracemalloc_malloc() or tracemalloc_realloc() */ -#ifdef TRACE_DEBUG - tracemalloc_error("filename is not a ready unicode string"); -#endif - return; - } - - /* intern the filename */ - _Py_hashtable_entry_t *entry; - entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename); - if (entry != NULL) { - filename = (PyObject *)entry->key; - } - else { - /* tracemalloc_filenames is responsible to keep a reference - to the filename */ - if (_Py_hashtable_set(tracemalloc_filenames, Py_NewRef(filename), - NULL) < 0) { - Py_DECREF(filename); -#ifdef TRACE_DEBUG - tracemalloc_error("failed to intern the filename"); -#endif - return; - } - } - - /* the tracemalloc_filenames table keeps a reference to the filename */ - frame->filename = filename; -} - - -static Py_uhash_t -traceback_hash(traceback_t *traceback) -{ - /* code based on tuplehash() of Objects/tupleobject.c */ - Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ - int len = traceback->nframe; - Py_uhash_t mult = _PyHASH_MULTIPLIER; - frame_t *frame; - - x = 0x345678UL; - frame = traceback->frames; - while (--len >= 0) { - y = (Py_uhash_t)PyObject_Hash(frame->filename); - y ^= (Py_uhash_t)frame->lineno; - frame++; - - x = (x ^ y) * mult; - /* the cast might truncate len; that doesn't change hash stability */ - mult += (Py_uhash_t)(82520UL + len + len); - } - x ^= traceback->total_nframe; - x += 97531UL; - return x; -} - - -static void -traceback_get_frames(traceback_t *traceback) -{ - PyThreadState *tstate = PyGILState_GetThisThreadState(); - if (tstate == NULL) { -#ifdef TRACE_DEBUG - tracemalloc_error("failed to get the current thread state"); -#endif - return; - } - - _PyInterpreterFrame *pyframe = _PyThreadState_GetFrame(tstate); - while (pyframe) { - if (traceback->nframe < tracemalloc_config.max_nframe) { - tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); - assert(traceback->frames[traceback->nframe].filename != NULL); - traceback->nframe++; - } - if (traceback->total_nframe < UINT16_MAX) { - traceback->total_nframe++; - } - pyframe = _PyFrame_GetFirstComplete(pyframe->previous); - } -} - - -static traceback_t * -traceback_new(void) -{ - traceback_t *traceback; - _Py_hashtable_entry_t *entry; - - assert(PyGILState_Check()); - - /* get frames */ - traceback = tracemalloc_traceback; - traceback->nframe = 0; - traceback->total_nframe = 0; - traceback_get_frames(traceback); - if (traceback->nframe == 0) - return &tracemalloc_empty_traceback; - traceback->hash = traceback_hash(traceback); - - /* intern the traceback */ - entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback); - if (entry != NULL) { - traceback = (traceback_t *)entry->key; - } - else { - traceback_t *copy; - size_t traceback_size; - - traceback_size = TRACEBACK_SIZE(traceback->nframe); - - copy = raw_malloc(traceback_size); - if (copy == NULL) { -#ifdef TRACE_DEBUG - tracemalloc_error("failed to intern the traceback: malloc failed"); -#endif - return NULL; - } - memcpy(copy, traceback, traceback_size); - - if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) { - raw_free(copy); -#ifdef TRACE_DEBUG - tracemalloc_error("failed to intern the traceback: putdata failed"); -#endif - return NULL; - } - traceback = copy; - } - return traceback; -} - - -static _Py_hashtable_t* -tracemalloc_create_traces_table(void) -{ - return hashtable_new(_Py_hashtable_hash_ptr, - _Py_hashtable_compare_direct, - NULL, raw_free); -} - - -static _Py_hashtable_t* -tracemalloc_create_domains_table(void) -{ - return hashtable_new(hashtable_hash_uint, - _Py_hashtable_compare_direct, - NULL, - (_Py_hashtable_destroy_func)_Py_hashtable_destroy); -} - - -static _Py_hashtable_t* -tracemalloc_get_traces_table(unsigned int domain) -{ - if (domain == DEFAULT_DOMAIN) { - return tracemalloc_traces; - } - else { - return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain)); - } -} - - -static void -tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) -{ - assert(tracemalloc_config.tracing); - - _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); - if (!traces) { - return; - } - - trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr)); - if (!trace) { - return; - } - assert(tracemalloc_traced_memory >= trace->size); - tracemalloc_traced_memory -= trace->size; - raw_free(trace); -} - -#define REMOVE_TRACE(ptr) \ - tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) - - -static int -tracemalloc_add_trace(unsigned int domain, uintptr_t ptr, - size_t size) -{ - assert(tracemalloc_config.tracing); - - traceback_t *traceback = traceback_new(); - if (traceback == NULL) { - return -1; - } - - _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); - if (traces == NULL) { - traces = tracemalloc_create_traces_table(); - if (traces == NULL) { - return -1; - } - - if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) { - _Py_hashtable_destroy(traces); - return -1; - } - } - - trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr)); - if (trace != NULL) { - /* the memory block is already tracked */ - assert(tracemalloc_traced_memory >= trace->size); - tracemalloc_traced_memory -= trace->size; - - trace->size = size; - trace->traceback = traceback; - } - else { - trace = raw_malloc(sizeof(trace_t)); - if (trace == NULL) { - return -1; - } - trace->size = size; - trace->traceback = traceback; - - int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace); - if (res != 0) { - raw_free(trace); - return res; - } - } - - assert(tracemalloc_traced_memory <= SIZE_MAX - size); - tracemalloc_traced_memory += size; - if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) { - tracemalloc_peak_traced_memory = tracemalloc_traced_memory; - } - return 0; -} - -#define ADD_TRACE(ptr, size) \ - tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) - - -static void* -tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) -{ - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - void *ptr; - - assert(elsize == 0 || nelem <= SIZE_MAX / elsize); - - if (use_calloc) - ptr = alloc->calloc(alloc->ctx, nelem, elsize); - else - ptr = alloc->malloc(alloc->ctx, nelem * elsize); - if (ptr == NULL) - return NULL; - - TABLES_LOCK(); - if (ADD_TRACE(ptr, nelem * elsize) < 0) { - /* Failed to allocate a trace for the new memory block */ - TABLES_UNLOCK(); - alloc->free(alloc->ctx, ptr); - return NULL; - } - TABLES_UNLOCK(); - return ptr; -} - - -static void* -tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) -{ - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - void *ptr2; - - ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); - if (ptr2 == NULL) - return NULL; - - if (ptr != NULL) { - /* an existing memory block has been resized */ - - TABLES_LOCK(); - - /* tracemalloc_add_trace() updates the trace if there is already - a trace at address ptr2 */ - if (ptr2 != ptr) { - REMOVE_TRACE(ptr); - } - - if (ADD_TRACE(ptr2, new_size) < 0) { - /* Memory allocation failed. The error cannot be reported to - the caller, because realloc() may already have shrunk the - memory block and so removed bytes. - - This case is very unlikely: a hash entry has just been - released, so the hash table should have at least one free entry. - - The GIL and the table lock ensures that only one thread is - allocating memory. */ - Py_FatalError("tracemalloc_realloc() failed to allocate a trace"); - } - TABLES_UNLOCK(); - } - else { - /* new allocation */ - - TABLES_LOCK(); - if (ADD_TRACE(ptr2, new_size) < 0) { - /* Failed to allocate a trace for the new memory block */ - TABLES_UNLOCK(); - alloc->free(alloc->ctx, ptr2); - return NULL; - } - TABLES_UNLOCK(); - } - return ptr2; -} - - -static void -tracemalloc_free(void *ctx, void *ptr) -{ - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - - if (ptr == NULL) - return; - - /* GIL cannot be locked in PyMem_RawFree() because it would introduce - a deadlock in _PyThreadState_DeleteCurrent(). */ - - alloc->free(alloc->ctx, ptr); - - TABLES_LOCK(); - REMOVE_TRACE(ptr); - TABLES_UNLOCK(); -} - - -static void* -tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) -{ - void *ptr; - - if (get_reentrant()) { - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - if (use_calloc) - return alloc->calloc(alloc->ctx, nelem, elsize); - else - return alloc->malloc(alloc->ctx, nelem * elsize); - } - - /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for - allocations larger than 512 bytes, don't trace the same memory - allocation twice. */ - set_reentrant(1); - - ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); - - set_reentrant(0); - return ptr; -} - - -static void* -tracemalloc_malloc_gil(void *ctx, size_t size) -{ - return tracemalloc_alloc_gil(0, ctx, 1, size); -} - - -static void* -tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) -{ - return tracemalloc_alloc_gil(1, ctx, nelem, elsize); -} - - -static void* -tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) -{ - void *ptr2; - - if (get_reentrant()) { - /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). - Example: PyMem_RawRealloc() is called internally by pymalloc - (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new - arena (new_arena()). */ - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - - ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); - if (ptr2 != NULL && ptr != NULL) { - TABLES_LOCK(); - REMOVE_TRACE(ptr); - TABLES_UNLOCK(); - } - return ptr2; - } - - /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for - allocations larger than 512 bytes. Don't trace the same memory - allocation twice. */ - set_reentrant(1); - - ptr2 = tracemalloc_realloc(ctx, ptr, new_size); - - set_reentrant(0); - return ptr2; -} - - -#ifdef TRACE_RAW_MALLOC -static void* -tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) -{ - PyGILState_STATE gil_state; - void *ptr; - - if (get_reentrant()) { - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - if (use_calloc) - return alloc->calloc(alloc->ctx, nelem, elsize); - else - return alloc->malloc(alloc->ctx, nelem * elsize); - } - - /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() - indirectly which would call PyGILState_Ensure() if reentrant are not - disabled. */ - set_reentrant(1); - - gil_state = PyGILState_Ensure(); - ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); - PyGILState_Release(gil_state); - - set_reentrant(0); - return ptr; -} - - -static void* -tracemalloc_raw_malloc(void *ctx, size_t size) -{ - return tracemalloc_raw_alloc(0, ctx, 1, size); -} - - -static void* -tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) -{ - return tracemalloc_raw_alloc(1, ctx, nelem, elsize); -} - - -static void* -tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) -{ - PyGILState_STATE gil_state; - void *ptr2; - - if (get_reentrant()) { - /* Reentrant call to PyMem_RawRealloc(). */ - PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; - - ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); - - if (ptr2 != NULL && ptr != NULL) { - TABLES_LOCK(); - REMOVE_TRACE(ptr); - TABLES_UNLOCK(); - } - return ptr2; - } - - /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() - indirectly which would call PyGILState_Ensure() if reentrant calls are - not disabled. */ - set_reentrant(1); - - gil_state = PyGILState_Ensure(); - ptr2 = tracemalloc_realloc(ctx, ptr, new_size); - PyGILState_Release(gil_state); - - set_reentrant(0); - return ptr2; -} -#endif /* TRACE_RAW_MALLOC */ - - -static void -tracemalloc_clear_filename(void *value) -{ - PyObject *filename = (PyObject *)value; - Py_DECREF(filename); -} - - -/* reentrant flag must be set to call this function and GIL must be held */ -static void -tracemalloc_clear_traces(void) -{ - /* The GIL protects variables against concurrent access */ - assert(PyGILState_Check()); - - TABLES_LOCK(); - _Py_hashtable_clear(tracemalloc_traces); - _Py_hashtable_clear(tracemalloc_domains); - tracemalloc_traced_memory = 0; - tracemalloc_peak_traced_memory = 0; - TABLES_UNLOCK(); - - _Py_hashtable_clear(tracemalloc_tracebacks); - - _Py_hashtable_clear(tracemalloc_filenames); -} - - -static int -tracemalloc_init(void) -{ - if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { - PyErr_SetString(PyExc_RuntimeError, - "the tracemalloc module has been unloaded"); - return -1; - } - - if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) - return 0; - - PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); - -#ifdef REENTRANT_THREADLOCAL - if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { -#ifdef MS_WINDOWS - PyErr_SetFromWindowsErr(0); -#else - PyErr_SetFromErrno(PyExc_OSError); -#endif - return -1; - } -#endif - -#if defined(TRACE_RAW_MALLOC) - if (tables_lock == NULL) { - tables_lock = PyThread_allocate_lock(); - if (tables_lock == NULL) { - PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); - return -1; - } - } -#endif - - tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject, - hashtable_compare_unicode, - tracemalloc_clear_filename, NULL); - - tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback, - hashtable_compare_traceback, - NULL, raw_free); - - tracemalloc_traces = tracemalloc_create_traces_table(); - tracemalloc_domains = tracemalloc_create_domains_table(); - - if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL - || tracemalloc_traces == NULL || tracemalloc_domains == NULL) { - PyErr_NoMemory(); - return -1; - } - - tracemalloc_empty_traceback.nframe = 1; - tracemalloc_empty_traceback.total_nframe = 1; - /* borrowed reference */ - tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown); - tracemalloc_empty_traceback.frames[0].lineno = 0; - tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); - - tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; - return 0; -} - - -static void -tracemalloc_deinit(void) -{ - if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED) - return; - tracemalloc_config.initialized = TRACEMALLOC_FINALIZED; - - tracemalloc_stop(); - - /* destroy hash tables */ - _Py_hashtable_destroy(tracemalloc_domains); - _Py_hashtable_destroy(tracemalloc_traces); - _Py_hashtable_destroy(tracemalloc_tracebacks); - _Py_hashtable_destroy(tracemalloc_filenames); - -#if defined(TRACE_RAW_MALLOC) - if (tables_lock != NULL) { - PyThread_free_lock(tables_lock); - tables_lock = NULL; - } -#endif - -#ifdef REENTRANT_THREADLOCAL - PyThread_tss_delete(&tracemalloc_reentrant_key); -#endif -} - - -static int -tracemalloc_start(int max_nframe) -{ - PyMemAllocatorEx alloc; - size_t size; - - if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { - PyErr_Format(PyExc_ValueError, - "the number of frames must be in range [1; %lu]", - MAX_NFRAME); - return -1; - } - - if (tracemalloc_init() < 0) { - return -1; - } - - if (tracemalloc_config.tracing) { - /* hook already installed: do nothing */ - return 0; - } - - tracemalloc_config.max_nframe = max_nframe; - - /* allocate a buffer to store a new traceback */ - size = TRACEBACK_SIZE(max_nframe); - assert(tracemalloc_traceback == NULL); - tracemalloc_traceback = raw_malloc(size); - if (tracemalloc_traceback == NULL) { - PyErr_NoMemory(); - return -1; - } - -#ifdef TRACE_RAW_MALLOC - alloc.malloc = tracemalloc_raw_malloc; - alloc.calloc = tracemalloc_raw_calloc; - alloc.realloc = tracemalloc_raw_realloc; - alloc.free = tracemalloc_free; - - alloc.ctx = &allocators.raw; - PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); -#endif - - alloc.malloc = tracemalloc_malloc_gil; - alloc.calloc = tracemalloc_calloc_gil; - alloc.realloc = tracemalloc_realloc_gil; - alloc.free = tracemalloc_free; - - alloc.ctx = &allocators.mem; - PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); - PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); - - alloc.ctx = &allocators.obj; - PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); - - /* everything is ready: start tracing Python memory allocations */ - tracemalloc_config.tracing = 1; - - return 0; -} - - -static void -tracemalloc_stop(void) -{ - if (!tracemalloc_config.tracing) - return; - - /* stop tracing Python memory allocations */ - tracemalloc_config.tracing = 0; - - /* unregister the hook on memory allocators */ -#ifdef TRACE_RAW_MALLOC - PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); -#endif - PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); - PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); - - tracemalloc_clear_traces(); +#include "clinic/_tracemalloc.c.h" - /* release memory */ - raw_free(tracemalloc_traceback); - tracemalloc_traceback = NULL; -} +/*[clinic input] +module _tracemalloc +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/ /*[clinic input] @@ -994,7 +19,7 @@ static PyObject * _tracemalloc_is_tracing_impl(PyObject *module) /*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/ { - return PyBool_FromLong(tracemalloc_config.tracing); + return PyBool_FromLong(_PyTraceMalloc_IsTracing()); } @@ -1008,262 +33,11 @@ static PyObject * _tracemalloc_clear_traces_impl(PyObject *module) /*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/ { - if (!tracemalloc_config.tracing) - Py_RETURN_NONE; - - set_reentrant(1); - tracemalloc_clear_traces(); - set_reentrant(0); - + _PyTraceMalloc_ClearTraces(); Py_RETURN_NONE; } -static PyObject* -frame_to_pyobject(frame_t *frame) -{ - PyObject *frame_obj, *lineno_obj; - - frame_obj = PyTuple_New(2); - if (frame_obj == NULL) - return NULL; - - PyTuple_SET_ITEM(frame_obj, 0, Py_NewRef(frame->filename)); - - lineno_obj = PyLong_FromUnsignedLong(frame->lineno); - if (lineno_obj == NULL) { - Py_DECREF(frame_obj); - return NULL; - } - PyTuple_SET_ITEM(frame_obj, 1, lineno_obj); - - return frame_obj; -} - - -static PyObject* -traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) -{ - PyObject *frames; - - if (intern_table != NULL) { - frames = _Py_hashtable_get(intern_table, (const void *)traceback); - if (frames) { - return Py_NewRef(frames); - } - } - - frames = PyTuple_New(traceback->nframe); - if (frames == NULL) - return NULL; - - for (int i=0; i < traceback->nframe; i++) { - PyObject *frame = frame_to_pyobject(&traceback->frames[i]); - if (frame == NULL) { - Py_DECREF(frames); - return NULL; - } - PyTuple_SET_ITEM(frames, i, frame); - } - - if (intern_table != NULL) { - if (_Py_hashtable_set(intern_table, traceback, frames) < 0) { - Py_DECREF(frames); - PyErr_NoMemory(); - return NULL; - } - /* intern_table keeps a new reference to frames */ - Py_INCREF(frames); - } - return frames; -} - - -static PyObject* -trace_to_pyobject(unsigned int domain, const trace_t *trace, - _Py_hashtable_t *intern_tracebacks) -{ - PyObject *trace_obj = NULL; - PyObject *obj; - - trace_obj = PyTuple_New(4); - if (trace_obj == NULL) - return NULL; - - obj = PyLong_FromSize_t(domain); - if (obj == NULL) { - Py_DECREF(trace_obj); - return NULL; - } - PyTuple_SET_ITEM(trace_obj, 0, obj); - - obj = PyLong_FromSize_t(trace->size); - if (obj == NULL) { - Py_DECREF(trace_obj); - return NULL; - } - PyTuple_SET_ITEM(trace_obj, 1, obj); - - obj = traceback_to_pyobject(trace->traceback, intern_tracebacks); - if (obj == NULL) { - Py_DECREF(trace_obj); - return NULL; - } - PyTuple_SET_ITEM(trace_obj, 2, obj); - - obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe); - if (obj == NULL) { - Py_DECREF(trace_obj); - return NULL; - } - PyTuple_SET_ITEM(trace_obj, 3, obj); - - return trace_obj; -} - - -typedef struct { - _Py_hashtable_t *traces; - _Py_hashtable_t *domains; - _Py_hashtable_t *tracebacks; - PyObject *list; - unsigned int domain; -} get_traces_t; - - -static int -tracemalloc_copy_trace(_Py_hashtable_t *traces, - const void *key, const void *value, - void *user_data) -{ - _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data; - - trace_t *trace = (trace_t *)value; - - trace_t *trace2 = raw_malloc(sizeof(trace_t)); - if (trace2 == NULL) { - return -1; - } - *trace2 = *trace; - if (_Py_hashtable_set(traces2, key, trace2) < 0) { - raw_free(trace2); - return -1; - } - return 0; -} - - -static _Py_hashtable_t* -tracemalloc_copy_traces(_Py_hashtable_t *traces) -{ - _Py_hashtable_t *traces2 = tracemalloc_create_traces_table(); - if (traces2 == NULL) { - return NULL; - } - - int err = _Py_hashtable_foreach(traces, - tracemalloc_copy_trace, - traces2); - if (err) { - _Py_hashtable_destroy(traces2); - return NULL; - } - return traces2; -} - - -static int -tracemalloc_copy_domain(_Py_hashtable_t *domains, - const void *key, const void *value, - void *user_data) -{ - _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data; - - unsigned int domain = (unsigned int)FROM_PTR(key); - _Py_hashtable_t *traces = (_Py_hashtable_t *)value; - - _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces); - if (traces2 == NULL) { - return -1; - } - if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) { - _Py_hashtable_destroy(traces2); - return -1; - } - return 0; -} - - -static _Py_hashtable_t* -tracemalloc_copy_domains(_Py_hashtable_t *domains) -{ - _Py_hashtable_t *domains2 = tracemalloc_create_domains_table(); - if (domains2 == NULL) { - return NULL; - } - - int err = _Py_hashtable_foreach(domains, - tracemalloc_copy_domain, - domains2); - if (err) { - _Py_hashtable_destroy(domains2); - return NULL; - } - return domains2; -} - - -static int -tracemalloc_get_traces_fill(_Py_hashtable_t *traces, - const void *key, const void *value, - void *user_data) -{ - get_traces_t *get_traces = user_data; - - const trace_t *trace = (const trace_t *)value; - - PyObject *tuple = trace_to_pyobject(get_traces->domain, trace, - get_traces->tracebacks); - if (tuple == NULL) { - return 1; - } - - int res = PyList_Append(get_traces->list, tuple); - Py_DECREF(tuple); - if (res < 0) { - return 1; - } - - return 0; -} - - -static int -tracemalloc_get_traces_domain(_Py_hashtable_t *domains, - const void *key, const void *value, - void *user_data) -{ - get_traces_t *get_traces = user_data; - - unsigned int domain = (unsigned int)FROM_PTR(key); - _Py_hashtable_t *traces = (_Py_hashtable_t *)value; - - get_traces->domain = domain; - return _Py_hashtable_foreach(traces, - tracemalloc_get_traces_fill, - get_traces); -} - - -static void -tracemalloc_pyobject_decref(void *value) -{ - PyObject *obj = (PyObject *)value; - Py_DECREF(obj); -} - - - /*[clinic input] _tracemalloc._get_traces @@ -1279,107 +53,7 @@ static PyObject * _tracemalloc__get_traces_impl(PyObject *module) /*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/ { - get_traces_t get_traces; - get_traces.domain = DEFAULT_DOMAIN; - get_traces.traces = NULL; - get_traces.domains = NULL; - get_traces.tracebacks = NULL; - get_traces.list = PyList_New(0); - if (get_traces.list == NULL) - goto error; - - if (!tracemalloc_config.tracing) - return get_traces.list; - - /* the traceback hash table is used temporarily to intern traceback tuple - of (filename, lineno) tuples */ - get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr, - _Py_hashtable_compare_direct, - NULL, tracemalloc_pyobject_decref); - if (get_traces.tracebacks == NULL) { - goto no_memory; - } - - // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable - // temporarily tracemalloc which would impact other threads and so would - // miss allocations while get_traces() is called. - TABLES_LOCK(); - get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces); - TABLES_UNLOCK(); - - if (get_traces.traces == NULL) { - goto no_memory; - } - - TABLES_LOCK(); - get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains); - TABLES_UNLOCK(); - - if (get_traces.domains == NULL) { - goto no_memory; - } - - // Convert traces to a list of tuples - set_reentrant(1); - int err = _Py_hashtable_foreach(get_traces.traces, - tracemalloc_get_traces_fill, - &get_traces); - if (!err) { - err = _Py_hashtable_foreach(get_traces.domains, - tracemalloc_get_traces_domain, - &get_traces); - } - set_reentrant(0); - if (err) { - goto error; - } - - goto finally; - -no_memory: - PyErr_NoMemory(); - -error: - Py_CLEAR(get_traces.list); - -finally: - if (get_traces.tracebacks != NULL) { - _Py_hashtable_destroy(get_traces.tracebacks); - } - if (get_traces.traces != NULL) { - _Py_hashtable_destroy(get_traces.traces); - } - if (get_traces.domains != NULL) { - _Py_hashtable_destroy(get_traces.domains); - } - - return get_traces.list; -} - - -static traceback_t* -tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) -{ - - if (!tracemalloc_config.tracing) - return NULL; - - trace_t *trace; - TABLES_LOCK(); - _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); - if (traces) { - trace = _Py_hashtable_get(traces, TO_PTR(ptr)); - } - else { - trace = NULL; - } - TABLES_UNLOCK(); - - if (!trace) { - return NULL; - } - - return trace->traceback; + return _PyTraceMalloc_GetTraces(); } @@ -1401,62 +75,9 @@ static PyObject * _tracemalloc__get_object_traceback(PyObject *module, PyObject *obj) /*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ { - PyTypeObject *type; - traceback_t *traceback; - - type = Py_TYPE(obj); - const size_t presize = _PyType_PreHeaderSize(type); - uintptr_t ptr = (uintptr_t)((char *)obj - presize); - - traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, ptr); - if (traceback == NULL) { - Py_RETURN_NONE; - } - - return traceback_to_pyobject(traceback, NULL); -} - - -#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) - -static void -_PyMem_DumpFrame(int fd, frame_t * frame) -{ - PUTS(fd, " File \""); - _Py_DumpASCII(fd, frame->filename); - PUTS(fd, "\", line "); - _Py_DumpDecimal(fd, frame->lineno); - PUTS(fd, "\n"); -} - -/* Dump the traceback where a memory block was allocated into file descriptor - fd. The function may block on TABLES_LOCK() but it is unlikely. */ -void -_PyMem_DumpTraceback(int fd, const void *ptr) -{ - traceback_t *traceback; - int i; - - if (!tracemalloc_config.tracing) { - PUTS(fd, "Enable tracemalloc to get the memory block " - "allocation traceback\n\n"); - return; - } - - traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); - if (traceback == NULL) - return; - - PUTS(fd, "Memory block allocated at (most recent call first):\n"); - for (i=0; i < traceback->nframe; i++) { - _PyMem_DumpFrame(fd, &traceback->frames[i]); - } - PUTS(fd, "\n"); + return _PyTraceMalloc_GetObjectTraceback(obj); } -#undef PUTS - - /*[clinic input] _tracemalloc.start @@ -1474,7 +95,7 @@ static PyObject * _tracemalloc_start_impl(PyObject *module, int nframe) /*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/ { - if (tracemalloc_start(nframe) < 0) { + if (_PyTraceMalloc_Start(nframe) < 0) { return NULL; } Py_RETURN_NONE; @@ -1493,7 +114,7 @@ static PyObject * _tracemalloc_stop_impl(PyObject *module) /*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/ { - tracemalloc_stop(); + _PyTraceMalloc_Stop(); Py_RETURN_NONE; } @@ -1511,22 +132,9 @@ static PyObject * _tracemalloc_get_traceback_limit_impl(PyObject *module) /*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/ { - return PyLong_FromLong(tracemalloc_config.max_nframe); -} - - -static int -tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains, - const void *key, const void *value, - void *user_data) -{ - const _Py_hashtable_t *traces = value; - size_t *size = (size_t*)user_data; - *size += _Py_hashtable_size(traces); - return 0; + return PyLong_FromLong(_PyTraceMalloc_GetTracebackLimit()); } - /*[clinic input] _tracemalloc.get_tracemalloc_memory @@ -1539,22 +147,10 @@ static PyObject * _tracemalloc_get_tracemalloc_memory_impl(PyObject *module) /*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/ { - size_t size; - - size = _Py_hashtable_size(tracemalloc_tracebacks); - size += _Py_hashtable_size(tracemalloc_filenames); - - TABLES_LOCK(); - size += _Py_hashtable_size(tracemalloc_traces); - _Py_hashtable_foreach(tracemalloc_domains, - tracemalloc_get_tracemalloc_memory_cb, &size); - TABLES_UNLOCK(); - - return PyLong_FromSize_t(size); + return PyLong_FromSize_t(_PyTraceMalloc_GetMemory()); } - /*[clinic input] _tracemalloc.get_traced_memory @@ -1567,17 +163,7 @@ static PyObject * _tracemalloc_get_traced_memory_impl(PyObject *module) /*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/ { - Py_ssize_t size, peak_size; - - if (!tracemalloc_config.tracing) - return Py_BuildValue("ii", 0, 0); - - TABLES_LOCK(); - size = tracemalloc_traced_memory; - peak_size = tracemalloc_peak_traced_memory; - TABLES_UNLOCK(); - - return Py_BuildValue("nn", size, peak_size); + return _PyTraceMalloc_GetTracedMemory(); } /*[clinic input] @@ -1593,14 +179,7 @@ static PyObject * _tracemalloc_reset_peak_impl(PyObject *module) /*[clinic end generated code: output=140c2870f691dbb2 input=18afd0635066e9ce]*/ { - if (!tracemalloc_config.tracing) { - Py_RETURN_NONE; - } - - TABLES_LOCK(); - tracemalloc_peak_traced_memory = tracemalloc_traced_memory; - TABLES_UNLOCK(); - + _PyTraceMalloc_ResetPeak(); Py_RETURN_NONE; } @@ -1640,118 +219,10 @@ PyInit__tracemalloc(void) if (m == NULL) return NULL; - if (tracemalloc_init() < 0) { + if (_PyTraceMalloc_Init() < 0) { Py_DECREF(m); return NULL; } return m; } - - -int -_PyTraceMalloc_Init(int nframe) -{ - assert(PyGILState_Check()); - if (nframe == 0) { - return 0; - } - return tracemalloc_start(nframe); -} - - -void -_PyTraceMalloc_Fini(void) -{ - assert(PyGILState_Check()); - tracemalloc_deinit(); -} - -int -PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, - size_t size) -{ - int res; - PyGILState_STATE gil_state; - - if (!tracemalloc_config.tracing) { - /* tracemalloc is not tracing: do nothing */ - return -2; - } - - gil_state = PyGILState_Ensure(); - - TABLES_LOCK(); - res = tracemalloc_add_trace(domain, ptr, size); - TABLES_UNLOCK(); - - PyGILState_Release(gil_state); - return res; -} - - -int -PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) -{ - if (!tracemalloc_config.tracing) { - /* tracemalloc is not tracing: do nothing */ - return -2; - } - - TABLES_LOCK(); - tracemalloc_remove_trace(domain, ptr); - TABLES_UNLOCK(); - - return 0; -} - - -/* If the object memory block is already traced, update its trace - with the current Python traceback. - - Do nothing if tracemalloc is not tracing memory allocations - or if the object memory block is not already traced. */ -int -_PyTraceMalloc_NewReference(PyObject *op) -{ - assert(PyGILState_Check()); - - if (!tracemalloc_config.tracing) { - /* tracemalloc is not tracing: do nothing */ - return -1; - } - - PyTypeObject *type = Py_TYPE(op); - const size_t presize = _PyType_PreHeaderSize(type); - uintptr_t ptr = (uintptr_t)((char *)op - presize); - - int res = -1; - - TABLES_LOCK(); - trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); - if (trace != NULL) { - /* update the traceback of the memory block */ - traceback_t *traceback = traceback_new(); - if (traceback != NULL) { - trace->traceback = traceback; - res = 0; - } - } - /* else: cannot track the object, its memory block size is unknown */ - TABLES_UNLOCK(); - - return res; -} - - -PyObject* -_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) -{ - traceback_t *traceback; - - traceback = tracemalloc_get_traceback(domain, ptr); - if (traceback == NULL) - Py_RETURN_NONE; - - return traceback_to_pyobject(traceback, NULL); -} diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index c9dbe195d932..3df0a0720452 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -242,6 +242,7 @@ </ClCompile> <ClCompile Include="..\Python\thread.c" /> <ClCompile Include="..\Python\traceback.c" /> + <ClCompile Include="..\Python\tracemalloc.c" /> </ItemGroup> <ItemGroup> <!-- BEGIN frozen modules --> diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 176935a63c48..d98a4c5ae4e2 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -394,6 +394,9 @@ <ClCompile Include="..\Python\traceback.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\Python\tracemalloc.c"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\Objects\tupleobject.c"> <Filter>Source Files</Filter> </ClCompile> diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index ca43404454c4..48cd4418f90f 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -567,6 +567,7 @@ </ClCompile> <ClCompile Include="..\Python\thread.c" /> <ClCompile Include="..\Python\traceback.c" /> + <ClCompile Include="..\Python\tracemalloc.c" /> </ItemGroup> <ItemGroup> <!-- BEGIN deepfreeze --> diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index a3c2e2476dd6..5c8c1444e810 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1268,6 +1268,9 @@ <ClCompile Include="..\Python\traceback.c"> <Filter>Python</Filter> </ClCompile> + <ClCompile Include="..\Python\tracemalloc.c"> + <Filter>Python</Filter> + </ClCompile> <ClCompile Include="..\Python\bootstrap_hash.c"> <Filter>Python</Filter> </ClCompile> diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 740901f53d2d..93ad1fe09801 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1129,11 +1129,12 @@ init_interp_main(PyThreadState *tstate) return _PyStatus_ERR("can't initialize signals"); } - if (_PyTraceMalloc_Init(config->tracemalloc) < 0) { - return _PyStatus_ERR("can't initialize tracemalloc"); + if (config->tracemalloc) { + if (_PyTraceMalloc_Start(config->tracemalloc) < 0) { + return _PyStatus_ERR("can't start tracemalloc"); + } } - #ifdef PY_HAVE_PERF_TRAMPOLINE if (config->perf_profiling) { if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 || diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c new file mode 100644 index 000000000000..bc7656235222 --- /dev/null +++ b/Python/tracemalloc.c @@ -0,0 +1,1560 @@ +#include "Python.h" +#include "pycore_fileutils.h" // _Py_write_noraise() +#include "pycore_gc.h" // PyGC_Head +#include "pycore_hashtable.h" // _Py_hashtable_t +#include "pycore_object.h" // _PyType_PreHeaderSize +#include "pycore_pymem.h" // _Py_tracemalloc_config +#include "pycore_runtime.h" // _Py_ID() +#include "pycore_traceback.h" +#include <pycore_frame.h> +#include "frameobject.h" // _PyInterpreterFrame_GetLine + +#include <stdlib.h> // malloc() + +#define tracemalloc_config _PyRuntime.tracemalloc.config + +_Py_DECLARE_STR(anon_unknown, "<unknown>"); + +/* Forward declaration */ +static void* raw_malloc(size_t size); +static void raw_free(void *ptr); + +#ifdef Py_DEBUG +# define TRACE_DEBUG +#endif + +#define TO_PTR(key) ((const void *)(uintptr_t)(key)) +#define FROM_PTR(key) ((uintptr_t)(key)) + +#define allocators _PyRuntime.tracemalloc.allocators + + +#if defined(TRACE_RAW_MALLOC) +/* This lock is needed because tracemalloc_free() is called without + the GIL held from PyMem_RawFree(). It cannot acquire the lock because it + would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ +# define tables_lock _PyRuntime.tracemalloc.tables_lock +# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) +# define TABLES_UNLOCK() PyThread_release_lock(tables_lock) +#else + /* variables are protected by the GIL */ +# define TABLES_LOCK() +# define TABLES_UNLOCK() +#endif + + +#define DEFAULT_DOMAIN 0 + +typedef struct tracemalloc_frame frame_t; +typedef struct tracemalloc_traceback traceback_t; + +#define TRACEBACK_SIZE(NFRAME) \ + (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) + +/* The maximum number of frames is either: + - The maximum number of frames we can store in `traceback_t.nframe` + - The maximum memory size_t we can allocate */ +static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1)); + + +#define tracemalloc_empty_traceback _PyRuntime.tracemalloc.empty_traceback + + +/* Trace of a memory block */ +typedef struct { + /* Size of the memory block in bytes */ + size_t size; + + /* Traceback where the memory block was allocated */ + traceback_t *traceback; +} trace_t; + + +#define tracemalloc_traced_memory _PyRuntime.tracemalloc.traced_memory +#define tracemalloc_peak_traced_memory _PyRuntime.tracemalloc.peak_traced_memory +#define tracemalloc_filenames _PyRuntime.tracemalloc.filenames +#define tracemalloc_traceback _PyRuntime.tracemalloc.traceback +#define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks +#define tracemalloc_traces _PyRuntime.tracemalloc.traces +#define tracemalloc_domains _PyRuntime.tracemalloc.domains + + +#ifdef TRACE_DEBUG +static void +tracemalloc_error(const char *format, ...) +{ + va_list ap; + fprintf(stderr, "tracemalloc: "); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, "\n"); + fflush(stderr); +} +#endif + + +#if defined(TRACE_RAW_MALLOC) +#define REENTRANT_THREADLOCAL + +#define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key + +/* Any non-NULL pointer can be used */ +#define REENTRANT Py_True + +static int +get_reentrant(void) +{ + void *ptr; + + assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); + ptr = PyThread_tss_get(&tracemalloc_reentrant_key); + if (ptr != NULL) { + assert(ptr == REENTRANT); + return 1; + } + else + return 0; +} + +static void +set_reentrant(int reentrant) +{ + assert(reentrant == 0 || reentrant == 1); + assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); + + if (reentrant) { + assert(!get_reentrant()); + PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT); + } + else { + assert(get_reentrant()); + PyThread_tss_set(&tracemalloc_reentrant_key, NULL); + } +} + +#else + +/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ +static int tracemalloc_reentrant = 0; + +static int +get_reentrant(void) +{ + return tracemalloc_reentrant; +} + +static void +set_reentrant(int reentrant) +{ + assert(reentrant != tracemalloc_reentrant); + tracemalloc_reentrant = reentrant; +} +#endif + + +static Py_uhash_t +hashtable_hash_pyobject(const void *key) +{ + PyObject *obj = (PyObject *)key; + return PyObject_Hash(obj); +} + + +static int +hashtable_compare_unicode(const void *key1, const void *key2) +{ + PyObject *obj1 = (PyObject *)key1; + PyObject *obj2 = (PyObject *)key2; + if (obj1 != NULL && obj2 != NULL) { + return (PyUnicode_Compare(obj1, obj2) == 0); + } + else { + return obj1 == obj2; + } +} + + +static Py_uhash_t +hashtable_hash_uint(const void *key_raw) +{ + unsigned int key = (unsigned int)FROM_PTR(key_raw); + return (Py_uhash_t)key; +} + + +static _Py_hashtable_t * +hashtable_new(_Py_hashtable_hash_func hash_func, + _Py_hashtable_compare_func compare_func, + _Py_hashtable_destroy_func key_destroy_func, + _Py_hashtable_destroy_func value_destroy_func) +{ + _Py_hashtable_allocator_t hashtable_alloc = {malloc, free}; + return _Py_hashtable_new_full(hash_func, compare_func, + key_destroy_func, value_destroy_func, + &hashtable_alloc); +} + + +static void* +raw_malloc(size_t size) +{ + return allocators.raw.malloc(allocators.raw.ctx, size); +} + +static void +raw_free(void *ptr) +{ + allocators.raw.free(allocators.raw.ctx, ptr); +} + + +static Py_uhash_t +hashtable_hash_traceback(const void *key) +{ + const traceback_t *traceback = (const traceback_t *)key; + return traceback->hash; +} + + +static int +hashtable_compare_traceback(const void *key1, const void *key2) +{ + const traceback_t *traceback1 = (const traceback_t *)key1; + const traceback_t *traceback2 = (const traceback_t *)key2; + + if (traceback1->nframe != traceback2->nframe) { + return 0; + } + if (traceback1->total_nframe != traceback2->total_nframe) { + return 0; + } + + for (int i=0; i < traceback1->nframe; i++) { + const frame_t *frame1 = &traceback1->frames[i]; + const frame_t *frame2 = &traceback2->frames[i]; + + if (frame1->lineno != frame2->lineno) { + return 0; + } + if (frame1->filename != frame2->filename) { + assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0); + return 0; + } + } + return 1; +} + + +static void +tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) +{ + frame->filename = &_Py_STR(anon_unknown); + int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); + if (lineno < 0) { + lineno = 0; + } + frame->lineno = (unsigned int)lineno; + + PyObject *filename = pyframe->f_code->co_filename; + + if (filename == NULL) { +#ifdef TRACE_DEBUG + tracemalloc_error("failed to get the filename of the code object"); +#endif + return; + } + + if (!PyUnicode_Check(filename)) { +#ifdef TRACE_DEBUG + tracemalloc_error("filename is not a unicode string"); +#endif + return; + } + if (!PyUnicode_IS_READY(filename)) { + /* Don't make a Unicode string ready to avoid reentrant calls + to tracemalloc_malloc() or tracemalloc_realloc() */ +#ifdef TRACE_DEBUG + tracemalloc_error("filename is not a ready unicode string"); +#endif + return; + } + + /* intern the filename */ + _Py_hashtable_entry_t *entry; + entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename); + if (entry != NULL) { + filename = (PyObject *)entry->key; + } + else { + /* tracemalloc_filenames is responsible to keep a reference + to the filename */ + if (_Py_hashtable_set(tracemalloc_filenames, Py_NewRef(filename), + NULL) < 0) { + Py_DECREF(filename); +#ifdef TRACE_DEBUG + tracemalloc_error("failed to intern the filename"); +#endif + return; + } + } + + /* the tracemalloc_filenames table keeps a reference to the filename */ + frame->filename = filename; +} + + +static Py_uhash_t +traceback_hash(traceback_t *traceback) +{ + /* code based on tuplehash() of Objects/tupleobject.c */ + Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ + int len = traceback->nframe; + Py_uhash_t mult = _PyHASH_MULTIPLIER; + frame_t *frame; + + x = 0x345678UL; + frame = traceback->frames; + while (--len >= 0) { + y = (Py_uhash_t)PyObject_Hash(frame->filename); + y ^= (Py_uhash_t)frame->lineno; + frame++; + + x = (x ^ y) * mult; + /* the cast might truncate len; that doesn't change hash stability */ + mult += (Py_uhash_t)(82520UL + len + len); + } + x ^= traceback->total_nframe; + x += 97531UL; + return x; +} + + +static void +traceback_get_frames(traceback_t *traceback) +{ + PyThreadState *tstate = PyGILState_GetThisThreadState(); + if (tstate == NULL) { +#ifdef TRACE_DEBUG + tracemalloc_error("failed to get the current thread state"); +#endif + return; + } + + _PyInterpreterFrame *pyframe = _PyThreadState_GetFrame(tstate); + while (pyframe) { + if (traceback->nframe < tracemalloc_config.max_nframe) { + tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); + assert(traceback->frames[traceback->nframe].filename != NULL); + traceback->nframe++; + } + if (traceback->total_nframe < UINT16_MAX) { + traceback->total_nframe++; + } + pyframe = _PyFrame_GetFirstComplete(pyframe->previous); + } +} + + +static traceback_t * +traceback_new(void) +{ + traceback_t *traceback; + _Py_hashtable_entry_t *entry; + + assert(PyGILState_Check()); + + /* get frames */ + traceback = tracemalloc_traceback; + traceback->nframe = 0; + traceback->total_nframe = 0; + traceback_get_frames(traceback); + if (traceback->nframe == 0) + return &tracemalloc_empty_traceback; + traceback->hash = traceback_hash(traceback); + + /* intern the traceback */ + entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback); + if (entry != NULL) { + traceback = (traceback_t *)entry->key; + } + else { + traceback_t *copy; + size_t traceback_size; + + traceback_size = TRACEBACK_SIZE(traceback->nframe); + + copy = raw_malloc(traceback_size); + if (copy == NULL) { +#ifdef TRACE_DEBUG + tracemalloc_error("failed to intern the traceback: malloc failed"); +#endif + return NULL; + } + memcpy(copy, traceback, traceback_size); + + if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) { + raw_free(copy); +#ifdef TRACE_DEBUG + tracemalloc_error("failed to intern the traceback: putdata failed"); +#endif + return NULL; + } + traceback = copy; + } + return traceback; +} + + +static _Py_hashtable_t* +tracemalloc_create_traces_table(void) +{ + return hashtable_new(_Py_hashtable_hash_ptr, + _Py_hashtable_compare_direct, + NULL, raw_free); +} + + +static _Py_hashtable_t* +tracemalloc_create_domains_table(void) +{ + return hashtable_new(hashtable_hash_uint, + _Py_hashtable_compare_direct, + NULL, + (_Py_hashtable_destroy_func)_Py_hashtable_destroy); +} + + +static _Py_hashtable_t* +tracemalloc_get_traces_table(unsigned int domain) +{ + if (domain == DEFAULT_DOMAIN) { + return tracemalloc_traces; + } + else { + return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain)); + } +} + + +static void +tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) +{ + assert(tracemalloc_config.tracing); + + _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); + if (!traces) { + return; + } + + trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr)); + if (!trace) { + return; + } + assert(tracemalloc_traced_memory >= trace->size); + tracemalloc_traced_memory -= trace->size; + raw_free(trace); +} + +#define REMOVE_TRACE(ptr) \ + tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) + + +static int +tracemalloc_add_trace(unsigned int domain, uintptr_t ptr, + size_t size) +{ + assert(tracemalloc_config.tracing); + + traceback_t *traceback = traceback_new(); + if (traceback == NULL) { + return -1; + } + + _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); + if (traces == NULL) { + traces = tracemalloc_create_traces_table(); + if (traces == NULL) { + return -1; + } + + if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) { + _Py_hashtable_destroy(traces); + return -1; + } + } + + trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr)); + if (trace != NULL) { + /* the memory block is already tracked */ + assert(tracemalloc_traced_memory >= trace->size); + tracemalloc_traced_memory -= trace->size; + + trace->size = size; + trace->traceback = traceback; + } + else { + trace = raw_malloc(sizeof(trace_t)); + if (trace == NULL) { + return -1; + } + trace->size = size; + trace->traceback = traceback; + + int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace); + if (res != 0) { + raw_free(trace); + return res; + } + } + + assert(tracemalloc_traced_memory <= SIZE_MAX - size); + tracemalloc_traced_memory += size; + if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) { + tracemalloc_peak_traced_memory = tracemalloc_traced_memory; + } + return 0; +} + +#define ADD_TRACE(ptr, size) \ + tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) + + +static void* +tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) +{ + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + void *ptr; + + assert(elsize == 0 || nelem <= SIZE_MAX / elsize); + + if (use_calloc) + ptr = alloc->calloc(alloc->ctx, nelem, elsize); + else + ptr = alloc->malloc(alloc->ctx, nelem * elsize); + if (ptr == NULL) + return NULL; + + TABLES_LOCK(); + if (ADD_TRACE(ptr, nelem * elsize) < 0) { + /* Failed to allocate a trace for the new memory block */ + TABLES_UNLOCK(); + alloc->free(alloc->ctx, ptr); + return NULL; + } + TABLES_UNLOCK(); + return ptr; +} + + +static void* +tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) +{ + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + void *ptr2; + + ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + if (ptr2 == NULL) + return NULL; + + if (ptr != NULL) { + /* an existing memory block has been resized */ + + TABLES_LOCK(); + + /* tracemalloc_add_trace() updates the trace if there is already + a trace at address ptr2 */ + if (ptr2 != ptr) { + REMOVE_TRACE(ptr); + } + + if (ADD_TRACE(ptr2, new_size) < 0) { + /* Memory allocation failed. The error cannot be reported to + the caller, because realloc() may already have shrunk the + memory block and so removed bytes. + + This case is very unlikely: a hash entry has just been + released, so the hash table should have at least one free entry. + + The GIL and the table lock ensures that only one thread is + allocating memory. */ + Py_FatalError("tracemalloc_realloc() failed to allocate a trace"); + } + TABLES_UNLOCK(); + } + else { + /* new allocation */ + + TABLES_LOCK(); + if (ADD_TRACE(ptr2, new_size) < 0) { + /* Failed to allocate a trace for the new memory block */ + TABLES_UNLOCK(); + alloc->free(alloc->ctx, ptr2); + return NULL; + } + TABLES_UNLOCK(); + } + return ptr2; +} + + +static void +tracemalloc_free(void *ctx, void *ptr) +{ + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + + if (ptr == NULL) + return; + + /* GIL cannot be locked in PyMem_RawFree() because it would introduce + a deadlock in _PyThreadState_DeleteCurrent(). */ + + alloc->free(alloc->ctx, ptr); + + TABLES_LOCK(); + REMOVE_TRACE(ptr); + TABLES_UNLOCK(); +} + + +static void* +tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) +{ + void *ptr; + + if (get_reentrant()) { + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + if (use_calloc) + return alloc->calloc(alloc->ctx, nelem, elsize); + else + return alloc->malloc(alloc->ctx, nelem * elsize); + } + + /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for + allocations larger than 512 bytes, don't trace the same memory + allocation twice. */ + set_reentrant(1); + + ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); + + set_reentrant(0); + return ptr; +} + + +static void* +tracemalloc_malloc_gil(void *ctx, size_t size) +{ + return tracemalloc_alloc_gil(0, ctx, 1, size); +} + + +static void* +tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) +{ + return tracemalloc_alloc_gil(1, ctx, nelem, elsize); +} + + +static void* +tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) +{ + void *ptr2; + + if (get_reentrant()) { + /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). + Example: PyMem_RawRealloc() is called internally by pymalloc + (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new + arena (new_arena()). */ + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + + ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + if (ptr2 != NULL && ptr != NULL) { + TABLES_LOCK(); + REMOVE_TRACE(ptr); + TABLES_UNLOCK(); + } + return ptr2; + } + + /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for + allocations larger than 512 bytes. Don't trace the same memory + allocation twice. */ + set_reentrant(1); + + ptr2 = tracemalloc_realloc(ctx, ptr, new_size); + + set_reentrant(0); + return ptr2; +} + + +#ifdef TRACE_RAW_MALLOC +static void* +tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) +{ + PyGILState_STATE gil_state; + void *ptr; + + if (get_reentrant()) { + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + if (use_calloc) + return alloc->calloc(alloc->ctx, nelem, elsize); + else + return alloc->malloc(alloc->ctx, nelem * elsize); + } + + /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() + indirectly which would call PyGILState_Ensure() if reentrant are not + disabled. */ + set_reentrant(1); + + gil_state = PyGILState_Ensure(); + ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); + PyGILState_Release(gil_state); + + set_reentrant(0); + return ptr; +} + + +static void* +tracemalloc_raw_malloc(void *ctx, size_t size) +{ + return tracemalloc_raw_alloc(0, ctx, 1, size); +} + + +static void* +tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) +{ + return tracemalloc_raw_alloc(1, ctx, nelem, elsize); +} + + +static void* +tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) +{ + PyGILState_STATE gil_state; + void *ptr2; + + if (get_reentrant()) { + /* Reentrant call to PyMem_RawRealloc(). */ + PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; + + ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); + + if (ptr2 != NULL && ptr != NULL) { + TABLES_LOCK(); + REMOVE_TRACE(ptr); + TABLES_UNLOCK(); + } + return ptr2; + } + + /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() + indirectly which would call PyGILState_Ensure() if reentrant calls are + not disabled. */ + set_reentrant(1); + + gil_state = PyGILState_Ensure(); + ptr2 = tracemalloc_realloc(ctx, ptr, new_size); + PyGILState_Release(gil_state); + + set_reentrant(0); + return ptr2; +} +#endif /* TRACE_RAW_MALLOC */ + + +static void +tracemalloc_clear_filename(void *value) +{ + PyObject *filename = (PyObject *)value; + Py_DECREF(filename); +} + + +/* reentrant flag must be set to call this function and GIL must be held */ +static void +tracemalloc_clear_traces(void) +{ + /* The GIL protects variables against concurrent access */ + assert(PyGILState_Check()); + + TABLES_LOCK(); + _Py_hashtable_clear(tracemalloc_traces); + _Py_hashtable_clear(tracemalloc_domains); + tracemalloc_traced_memory = 0; + tracemalloc_peak_traced_memory = 0; + TABLES_UNLOCK(); + + _Py_hashtable_clear(tracemalloc_tracebacks); + + _Py_hashtable_clear(tracemalloc_filenames); +} + + +int +_PyTraceMalloc_Init(void) +{ + if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { + PyErr_SetString(PyExc_RuntimeError, + "the tracemalloc module has been unloaded"); + return -1; + } + + if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) + return 0; + + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); + +#ifdef REENTRANT_THREADLOCAL + if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { +#ifdef MS_WINDOWS + PyErr_SetFromWindowsErr(0); +#else + PyErr_SetFromErrno(PyExc_OSError); +#endif + return -1; + } +#endif + +#if defined(TRACE_RAW_MALLOC) + if (tables_lock == NULL) { + tables_lock = PyThread_allocate_lock(); + if (tables_lock == NULL) { + PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); + return -1; + } + } +#endif + + tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject, + hashtable_compare_unicode, + tracemalloc_clear_filename, NULL); + + tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback, + hashtable_compare_traceback, + NULL, raw_free); + + tracemalloc_traces = tracemalloc_create_traces_table(); + tracemalloc_domains = tracemalloc_create_domains_table(); + + if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL + || tracemalloc_traces == NULL || tracemalloc_domains == NULL) { + PyErr_NoMemory(); + return -1; + } + + tracemalloc_empty_traceback.nframe = 1; + tracemalloc_empty_traceback.total_nframe = 1; + /* borrowed reference */ + tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown); + tracemalloc_empty_traceback.frames[0].lineno = 0; + tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); + + tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; + return 0; +} + + +static void +tracemalloc_deinit(void) +{ + if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED) + return; + tracemalloc_config.initialized = TRACEMALLOC_FINALIZED; + + _PyTraceMalloc_Stop(); + + /* destroy hash tables */ + _Py_hashtable_destroy(tracemalloc_domains); + _Py_hashtable_destroy(tracemalloc_traces); + _Py_hashtable_destroy(tracemalloc_tracebacks); + _Py_hashtable_destroy(tracemalloc_filenames); + +#if defined(TRACE_RAW_MALLOC) + if (tables_lock != NULL) { + PyThread_free_lock(tables_lock); + tables_lock = NULL; + } +#endif + +#ifdef REENTRANT_THREADLOCAL + PyThread_tss_delete(&tracemalloc_reentrant_key); +#endif +} + + +int +_PyTraceMalloc_Start(int max_nframe) +{ + PyMemAllocatorEx alloc; + size_t size; + + if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { + PyErr_Format(PyExc_ValueError, + "the number of frames must be in range [1; %lu]", + MAX_NFRAME); + return -1; + } + + if (_PyTraceMalloc_Init() < 0) { + return -1; + } + + if (tracemalloc_config.tracing) { + /* hook already installed: do nothing */ + return 0; + } + + tracemalloc_config.max_nframe = max_nframe; + + /* allocate a buffer to store a new traceback */ + size = TRACEBACK_SIZE(max_nframe); + assert(tracemalloc_traceback == NULL); + tracemalloc_traceback = raw_malloc(size); + if (tracemalloc_traceback == NULL) { + PyErr_NoMemory(); + return -1; + } + +#ifdef TRACE_RAW_MALLOC + alloc.malloc = tracemalloc_raw_malloc; + alloc.calloc = tracemalloc_raw_calloc; + alloc.realloc = tracemalloc_raw_realloc; + alloc.free = tracemalloc_free; + + alloc.ctx = &allocators.raw; + PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); +#endif + + alloc.malloc = tracemalloc_malloc_gil; + alloc.calloc = tracemalloc_calloc_gil; + alloc.realloc = tracemalloc_realloc_gil; + alloc.free = tracemalloc_free; + + alloc.ctx = &allocators.mem; + PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); + + alloc.ctx = &allocators.obj; + PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); + + /* everything is ready: start tracing Python memory allocations */ + tracemalloc_config.tracing = 1; + + return 0; +} + + +void +_PyTraceMalloc_Stop(void) +{ + if (!tracemalloc_config.tracing) + return; + + /* stop tracing Python memory allocations */ + tracemalloc_config.tracing = 0; + + /* unregister the hook on memory allocators */ +#ifdef TRACE_RAW_MALLOC + PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); +#endif + PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); + PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); + + tracemalloc_clear_traces(); + + /* release memory */ + raw_free(tracemalloc_traceback); + tracemalloc_traceback = NULL; +} + + + +static PyObject* +frame_to_pyobject(frame_t *frame) +{ + PyObject *frame_obj, *lineno_obj; + + frame_obj = PyTuple_New(2); + if (frame_obj == NULL) + return NULL; + + PyTuple_SET_ITEM(frame_obj, 0, Py_NewRef(frame->filename)); + + lineno_obj = PyLong_FromUnsignedLong(frame->lineno); + if (lineno_obj == NULL) { + Py_DECREF(frame_obj); + return NULL; + } + PyTuple_SET_ITEM(frame_obj, 1, lineno_obj); + + return frame_obj; +} + + +static PyObject* +traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) +{ + PyObject *frames; + + if (intern_table != NULL) { + frames = _Py_hashtable_get(intern_table, (const void *)traceback); + if (frames) { + return Py_NewRef(frames); + } + } + + frames = PyTuple_New(traceback->nframe); + if (frames == NULL) + return NULL; + + for (int i=0; i < traceback->nframe; i++) { + PyObject *frame = frame_to_pyobject(&traceback->frames[i]); + if (frame == NULL) { + Py_DECREF(frames); + return NULL; + } + PyTuple_SET_ITEM(frames, i, frame); + } + + if (intern_table != NULL) { + if (_Py_hashtable_set(intern_table, traceback, frames) < 0) { + Py_DECREF(frames); + PyErr_NoMemory(); + return NULL; + } + /* intern_table keeps a new reference to frames */ + Py_INCREF(frames); + } + return frames; +} + + +static PyObject* +trace_to_pyobject(unsigned int domain, const trace_t *trace, + _Py_hashtable_t *intern_tracebacks) +{ + PyObject *trace_obj = NULL; + PyObject *obj; + + trace_obj = PyTuple_New(4); + if (trace_obj == NULL) + return NULL; + + obj = PyLong_FromSize_t(domain); + if (obj == NULL) { + Py_DECREF(trace_obj); + return NULL; + } + PyTuple_SET_ITEM(trace_obj, 0, obj); + + obj = PyLong_FromSize_t(trace->size); + if (obj == NULL) { + Py_DECREF(trace_obj); + return NULL; + } + PyTuple_SET_ITEM(trace_obj, 1, obj); + + obj = traceback_to_pyobject(trace->traceback, intern_tracebacks); + if (obj == NULL) { + Py_DECREF(trace_obj); + return NULL; + } + PyTuple_SET_ITEM(trace_obj, 2, obj); + + obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe); + if (obj == NULL) { + Py_DECREF(trace_obj); + return NULL; + } + PyTuple_SET_ITEM(trace_obj, 3, obj); + + return trace_obj; +} + + +typedef struct { + _Py_hashtable_t *traces; + _Py_hashtable_t *domains; + _Py_hashtable_t *tracebacks; + PyObject *list; + unsigned int domain; +} get_traces_t; + + +static int +tracemalloc_copy_trace(_Py_hashtable_t *traces, + const void *key, const void *value, + void *user_data) +{ + _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data; + + trace_t *trace = (trace_t *)value; + + trace_t *trace2 = raw_malloc(sizeof(trace_t)); + if (trace2 == NULL) { + return -1; + } + *trace2 = *trace; + if (_Py_hashtable_set(traces2, key, trace2) < 0) { + raw_free(trace2); + return -1; + } + return 0; +} + + +static _Py_hashtable_t* +tracemalloc_copy_traces(_Py_hashtable_t *traces) +{ + _Py_hashtable_t *traces2 = tracemalloc_create_traces_table(); + if (traces2 == NULL) { + return NULL; + } + + int err = _Py_hashtable_foreach(traces, + tracemalloc_copy_trace, + traces2); + if (err) { + _Py_hashtable_destroy(traces2); + return NULL; + } + return traces2; +} + + +static int +tracemalloc_copy_domain(_Py_hashtable_t *domains, + const void *key, const void *value, + void *user_data) +{ + _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data; + + unsigned int domain = (unsigned int)FROM_PTR(key); + _Py_hashtable_t *traces = (_Py_hashtable_t *)value; + + _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces); + if (traces2 == NULL) { + return -1; + } + if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) { + _Py_hashtable_destroy(traces2); + return -1; + } + return 0; +} + + +static _Py_hashtable_t* +tracemalloc_copy_domains(_Py_hashtable_t *domains) +{ + _Py_hashtable_t *domains2 = tracemalloc_create_domains_table(); + if (domains2 == NULL) { + return NULL; + } + + int err = _Py_hashtable_foreach(domains, + tracemalloc_copy_domain, + domains2); + if (err) { + _Py_hashtable_destroy(domains2); + return NULL; + } + return domains2; +} + + +static int +tracemalloc_get_traces_fill(_Py_hashtable_t *traces, + const void *key, const void *value, + void *user_data) +{ + get_traces_t *get_traces = user_data; + + const trace_t *trace = (const trace_t *)value; + + PyObject *tuple = trace_to_pyobject(get_traces->domain, trace, + get_traces->tracebacks); + if (tuple == NULL) { + return 1; + } + + int res = PyList_Append(get_traces->list, tuple); + Py_DECREF(tuple); + if (res < 0) { + return 1; + } + + return 0; +} + + +static int +tracemalloc_get_traces_domain(_Py_hashtable_t *domains, + const void *key, const void *value, + void *user_data) +{ + get_traces_t *get_traces = user_data; + + unsigned int domain = (unsigned int)FROM_PTR(key); + _Py_hashtable_t *traces = (_Py_hashtable_t *)value; + + get_traces->domain = domain; + return _Py_hashtable_foreach(traces, + tracemalloc_get_traces_fill, + get_traces); +} + + +static void +tracemalloc_pyobject_decref(void *value) +{ + PyObject *obj = (PyObject *)value; + Py_DECREF(obj); +} + + +static traceback_t* +tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) +{ + + if (!tracemalloc_config.tracing) + return NULL; + + trace_t *trace; + TABLES_LOCK(); + _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); + if (traces) { + trace = _Py_hashtable_get(traces, TO_PTR(ptr)); + } + else { + trace = NULL; + } + TABLES_UNLOCK(); + + if (!trace) { + return NULL; + } + + return trace->traceback; +} + + +#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) + +static void +_PyMem_DumpFrame(int fd, frame_t * frame) +{ + PUTS(fd, " File \""); + _Py_DumpASCII(fd, frame->filename); + PUTS(fd, "\", line "); + _Py_DumpDecimal(fd, frame->lineno); + PUTS(fd, "\n"); +} + +/* Dump the traceback where a memory block was allocated into file descriptor + fd. The function may block on TABLES_LOCK() but it is unlikely. */ +void +_PyMem_DumpTraceback(int fd, const void *ptr) +{ + traceback_t *traceback; + int i; + + if (!tracemalloc_config.tracing) { + PUTS(fd, "Enable tracemalloc to get the memory block " + "allocation traceback\n\n"); + return; + } + + traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); + if (traceback == NULL) + return; + + PUTS(fd, "Memory block allocated at (most recent call first):\n"); + for (i=0; i < traceback->nframe; i++) { + _PyMem_DumpFrame(fd, &traceback->frames[i]); + } + PUTS(fd, "\n"); +} + +#undef PUTS + + +static int +tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains, + const void *key, const void *value, + void *user_data) +{ + const _Py_hashtable_t *traces = value; + size_t *size = (size_t*)user_data; + *size += _Py_hashtable_size(traces); + return 0; +} + +int +PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, + size_t size) +{ + int res; + PyGILState_STATE gil_state; + + if (!tracemalloc_config.tracing) { + /* tracemalloc is not tracing: do nothing */ + return -2; + } + + gil_state = PyGILState_Ensure(); + + TABLES_LOCK(); + res = tracemalloc_add_trace(domain, ptr, size); + TABLES_UNLOCK(); + + PyGILState_Release(gil_state); + return res; +} + + +int +PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) +{ + if (!tracemalloc_config.tracing) { + /* tracemalloc is not tracing: do nothing */ + return -2; + } + + TABLES_LOCK(); + tracemalloc_remove_trace(domain, ptr); + TABLES_UNLOCK(); + + return 0; +} + + +void +_PyTraceMalloc_Fini(void) +{ + assert(PyGILState_Check()); + tracemalloc_deinit(); +} + + +/* If the object memory block is already traced, update its trace + with the current Python traceback. + + Do nothing if tracemalloc is not tracing memory allocations + or if the object memory block is not already traced. */ +int +_PyTraceMalloc_NewReference(PyObject *op) +{ + assert(PyGILState_Check()); + + if (!tracemalloc_config.tracing) { + /* tracemalloc is not tracing: do nothing */ + return -1; + } + + PyTypeObject *type = Py_TYPE(op); + const size_t presize = _PyType_PreHeaderSize(type); + uintptr_t ptr = (uintptr_t)((char *)op - presize); + + int res = -1; + + TABLES_LOCK(); + trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); + if (trace != NULL) { + /* update the traceback of the memory block */ + traceback_t *traceback = traceback_new(); + if (traceback != NULL) { + trace->traceback = traceback; + res = 0; + } + } + /* else: cannot track the object, its memory block size is unknown */ + TABLES_UNLOCK(); + + return res; +} + + +PyObject* +_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) +{ + traceback_t *traceback; + + traceback = tracemalloc_get_traceback(domain, ptr); + if (traceback == NULL) + Py_RETURN_NONE; + + return traceback_to_pyobject(traceback, NULL); +} + +int +_PyTraceMalloc_IsTracing(void) +{ + return tracemalloc_config.tracing; +} + +void +_PyTraceMalloc_ClearTraces(void) +{ + + if (!tracemalloc_config.tracing) { + return; + } + set_reentrant(1); + tracemalloc_clear_traces(); + set_reentrant(0); +} + +PyObject * +_PyTraceMalloc_GetTraces(void) +{ + get_traces_t get_traces; + get_traces.domain = DEFAULT_DOMAIN; + get_traces.traces = NULL; + get_traces.domains = NULL; + get_traces.tracebacks = NULL; + get_traces.list = PyList_New(0); + if (get_traces.list == NULL) + goto error; + + if (!tracemalloc_config.tracing) + return get_traces.list; + + /* the traceback hash table is used temporarily to intern traceback tuple + of (filename, lineno) tuples */ + get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr, + _Py_hashtable_compare_direct, + NULL, tracemalloc_pyobject_decref); + if (get_traces.tracebacks == NULL) { + goto no_memory; + } + + // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable + // temporarily tracemalloc which would impact other threads and so would + // miss allocations while get_traces() is called. + TABLES_LOCK(); + get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces); + TABLES_UNLOCK(); + + if (get_traces.traces == NULL) { + goto no_memory; + } + + TABLES_LOCK(); + get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains); + TABLES_UNLOCK(); + + if (get_traces.domains == NULL) { + goto no_memory; + } + + // Convert traces to a list of tuples + set_reentrant(1); + int err = _Py_hashtable_foreach(get_traces.traces, + tracemalloc_get_traces_fill, + &get_traces); + if (!err) { + err = _Py_hashtable_foreach(get_traces.domains, + tracemalloc_get_traces_domain, + &get_traces); + } + set_reentrant(0); + if (err) { + goto error; + } + + goto finally; + +no_memory: + PyErr_NoMemory(); + +error: + Py_CLEAR(get_traces.list); + +finally: + if (get_traces.tracebacks != NULL) { + _Py_hashtable_destroy(get_traces.tracebacks); + } + if (get_traces.traces != NULL) { + _Py_hashtable_destroy(get_traces.traces); + } + if (get_traces.domains != NULL) { + _Py_hashtable_destroy(get_traces.domains); + } + + return get_traces.list; +} + +PyObject * +_PyTraceMalloc_GetObjectTraceback(PyObject *obj) +/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ +{ + PyTypeObject *type; + traceback_t *traceback; + + type = Py_TYPE(obj); + const size_t presize = _PyType_PreHeaderSize(type); + uintptr_t ptr = (uintptr_t)((char *)obj - presize); + + traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, ptr); + if (traceback == NULL) { + Py_RETURN_NONE; + } + + return traceback_to_pyobject(traceback, NULL); +} + +int _PyTraceMalloc_GetTracebackLimit(void) { + return tracemalloc_config.max_nframe; +} + +size_t +_PyTraceMalloc_GetMemory(void) { + + size_t size; + + size = _Py_hashtable_size(tracemalloc_tracebacks); + size += _Py_hashtable_size(tracemalloc_filenames); + + TABLES_LOCK(); + size += _Py_hashtable_size(tracemalloc_traces); + _Py_hashtable_foreach(tracemalloc_domains, + tracemalloc_get_tracemalloc_memory_cb, &size); + TABLES_UNLOCK(); + return size; +} + + +PyObject * +_PyTraceMalloc_GetTracedMemory(void) +{ + Py_ssize_t size, peak_size; + + if (!tracemalloc_config.tracing) + return Py_BuildValue("ii", 0, 0); + + TABLES_LOCK(); + size = tracemalloc_traced_memory; + peak_size = tracemalloc_peak_traced_memory; + TABLES_UNLOCK(); + + return Py_BuildValue("nn", size, peak_size); +} + +void +_PyTraceMalloc_ResetPeak(void) +{ + if (!tracemalloc_config.tracing) { + return; + } + TABLES_LOCK(); + tracemalloc_peak_traced_memory = tracemalloc_traced_memory; + TABLES_UNLOCK(); +} From webhook-mailer at python.org Wed May 17 09:41:13 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 17 May 2023 13:41:13 -0000 Subject: [Python-checkins] [3.11] typing: Add more tests for TypeVar (GH-104571) (#104577) Message-ID: <mailman.411.1684330874.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f106aef24a2bc968944c89290b12d68648e365bb commit: f106aef24a2bc968944c89290b12d68648e365bb branch: 3.11 author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-17T13:40:34Z summary: [3.11] typing: Add more tests for TypeVar (GH-104571) (#104577) During the PEP 695 implementation at one point I made TypeVar.__name__ return garbage, and all of test_typing passed. So I decided to add a few more tests. (cherry picked from commit 26931944dd8abd6554249239344fa62b789b9028) Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index e46a6ca06200..e36cab601621 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -364,6 +364,32 @@ def test_basic_plain(self): self.assertEqual(T, T) # T is an instance of TypeVar self.assertIsInstance(T, TypeVar) + self.assertEqual(T.__name__, 'T') + self.assertEqual(T.__constraints__, ()) + self.assertIs(T.__bound__, None) + self.assertIs(T.__covariant__, False) + self.assertIs(T.__contravariant__, False) + + def test_attributes(self): + T_bound = TypeVar('T_bound', bound=int) + self.assertEqual(T_bound.__name__, 'T_bound') + self.assertEqual(T_bound.__constraints__, ()) + self.assertIs(T_bound.__bound__, int) + + T_constraints = TypeVar('T_constraints', int, str) + self.assertEqual(T_constraints.__name__, 'T_constraints') + self.assertEqual(T_constraints.__constraints__, (int, str)) + self.assertIs(T_constraints.__bound__, None) + + T_co = TypeVar('T_co', covariant=True) + self.assertEqual(T_co.__name__, 'T_co') + self.assertIs(T_co.__covariant__, True) + self.assertIs(T_co.__contravariant__, False) + + T_contra = TypeVar('T_contra', contravariant=True) + self.assertEqual(T_contra.__name__, 'T_contra') + self.assertIs(T_contra.__covariant__, False) + self.assertIs(T_contra.__contravariant__, True) def test_typevar_instance_type_error(self): T = TypeVar('T') @@ -7426,6 +7452,7 @@ def test_basic_plain(self): P = ParamSpec('P') self.assertEqual(P, P) self.assertIsInstance(P, ParamSpec) + self.assertEqual(P.__name__, 'P') def test_valid_uses(self): P = ParamSpec('P') From webhook-mailer at python.org Wed May 17 12:00:04 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 17 May 2023 16:00:04 -0000 Subject: [Python-checkins] gh-104372: Cleanup _posixsubprocess `make_inheritable` for async signal safety and no GIL requirement (#104518) Message-ID: <mailman.412.1684339205.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c649df63e0d052044a4660101d5769ff46ae9234 commit: c649df63e0d052044a4660101d5769ff46ae9234 branch: main author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-17T08:59:45-07:00 summary: gh-104372: Cleanup _posixsubprocess `make_inheritable` for async signal safety and no GIL requirement (#104518) Move all of the Python C API calls into the parent process up front instead of doing PyLong_AsLong and PyErr_Occurred and PyTuple_GET from the post-fork/vfork child process. Much of this was long overdue. We shouldn't have been using PyTuple and PyLong APIs within all of these low level functions anyways. files: A Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst M Modules/_posixsubprocess.c diff --git a/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst b/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst new file mode 100644 index 000000000000..c228f503aab4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst @@ -0,0 +1 @@ +Refactored the ``_posixsubprocess`` internals to avoid Python C API usage between fork and exec when marking ``pass_fds=`` file descriptors inheritable. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 2bf83db0e228..75965d338d59 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -160,16 +160,17 @@ _sanity_check_python_fd_sequence(PyObject *fd_sequence) /* Is fd found in the sorted Python Sequence? */ static int -_is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence) +_is_fd_in_sorted_fd_sequence(int fd, int *fd_sequence, + Py_ssize_t fd_sequence_len) { /* Binary search. */ Py_ssize_t search_min = 0; - Py_ssize_t search_max = PyTuple_GET_SIZE(fd_sequence) - 1; + Py_ssize_t search_max = fd_sequence_len - 1; if (search_max < 0) return 0; do { long middle = (search_min + search_max) / 2; - long middle_fd = PyLong_AsLong(PyTuple_GET_ITEM(fd_sequence, middle)); + long middle_fd = fd_sequence[middle]; if (fd == middle_fd) return 1; if (fd > middle_fd) @@ -180,8 +181,18 @@ _is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence) return 0; } +/* + * Do all the Python C API calls in the parent process to turn the pass_fds + * "py_fds_to_keep" tuple into a C array. The caller owns allocation and + * freeing of the array. + * + * On error an unknown number of array elements may have been filled in. + * A Python exception has been set when an error is returned. + * + * Returns: -1 on error, 0 on success. + */ static int -make_inheritable(PyObject *py_fds_to_keep, int errpipe_write) +convert_fds_to_keep_to_c(PyObject *py_fds_to_keep, int *c_fds_to_keep) { Py_ssize_t i, len; @@ -189,15 +200,37 @@ make_inheritable(PyObject *py_fds_to_keep, int errpipe_write) for (i = 0; i < len; ++i) { PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i); long fd = PyLong_AsLong(fdobj); - assert(!PyErr_Occurred()); - assert(0 <= fd && fd <= INT_MAX); + if (PyErr_Occurred()) { + return -1; + } + if (fd < 0 || fd > INT_MAX) { + PyErr_SetString(PyExc_ValueError, + "fd out of range in fds_to_keep."); + return -1; + } + c_fds_to_keep[i] = (int)fd; + } + return 0; +} + + +/* This function must be async-signal-safe as it is called from child_exec() + * after fork() or vfork(). + */ +static int +make_inheritable(int *c_fds_to_keep, Py_ssize_t len, int errpipe_write) +{ + Py_ssize_t i; + + for (i = 0; i < len; ++i) { + int fd = c_fds_to_keep[i]; if (fd == errpipe_write) { - /* errpipe_write is part of py_fds_to_keep. It must be closed at + /* errpipe_write is part of fds_to_keep. It must be closed at exec(), but kept open in the child process until exec() is called. */ continue; } - if (_Py_set_inheritable_async_safe((int)fd, 1, NULL) < 0) + if (_Py_set_inheritable_async_safe(fd, 1, NULL) < 0) return -1; } return 0; @@ -233,7 +266,7 @@ safe_get_max_fd(void) /* Close all file descriptors in the given range except for those in - * py_fds_to_keep by invoking closer on each subrange. + * fds_to_keep by invoking closer on each subrange. * * If end_fd == -1, it's guessed via safe_get_max_fd(), but it isn't * possible to know for sure what the max fd to go up to is for @@ -243,19 +276,18 @@ safe_get_max_fd(void) static int _close_range_except(int start_fd, int end_fd, - PyObject *py_fds_to_keep, + int *fds_to_keep, + Py_ssize_t fds_to_keep_len, int (*closer)(int, int)) { if (end_fd == -1) { end_fd = Py_MIN(safe_get_max_fd(), INT_MAX); } - Py_ssize_t num_fds_to_keep = PyTuple_GET_SIZE(py_fds_to_keep); Py_ssize_t keep_seq_idx; - /* As py_fds_to_keep is sorted we can loop through the list closing + /* As fds_to_keep is sorted we can loop through the list closing * fds in between any in the keep list falling within our range. */ - for (keep_seq_idx = 0; keep_seq_idx < num_fds_to_keep; ++keep_seq_idx) { - PyObject* py_keep_fd = PyTuple_GET_ITEM(py_fds_to_keep, keep_seq_idx); - int keep_fd = PyLong_AsLong(py_keep_fd); + for (keep_seq_idx = 0; keep_seq_idx < fds_to_keep_len; ++keep_seq_idx) { + int keep_fd = fds_to_keep[keep_seq_idx]; if (keep_fd < start_fd) continue; if (closer(start_fd, keep_fd - 1) != 0) @@ -295,7 +327,7 @@ _brute_force_closer(int first, int last) } /* Close all open file descriptors in the range from start_fd and higher - * Do not close any in the sorted py_fds_to_keep list. + * Do not close any in the sorted fds_to_keep list. * * This version is async signal safe as it does not make any unsafe C library * calls, malloc calls or handle any locks. It is _unfortunate_ to be forced @@ -310,14 +342,16 @@ _brute_force_closer(int first, int last) * it with some cpp #define magic to work on other OSes as well if you want. */ static void -_close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep) +_close_open_fds_safe(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len) { int fd_dir_fd; fd_dir_fd = _Py_open_noraise(FD_DIR, O_RDONLY); if (fd_dir_fd == -1) { /* No way to get a list of open fds. */ - _close_range_except(start_fd, -1, py_fds_to_keep, _brute_force_closer); + _close_range_except(start_fd, -1, + fds_to_keep, fds_to_keep_len, + _brute_force_closer); return; } else { char buffer[sizeof(struct linux_dirent64)]; @@ -336,7 +370,8 @@ _close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep) if ((fd = _pos_int_from_ascii(entry->d_name)) < 0) continue; /* Not a number. */ if (fd != fd_dir_fd && fd >= start_fd && - !_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) { + !_is_fd_in_sorted_fd_sequence(fd, fds_to_keep, + fds_to_keep_len)) { close(fd); } } @@ -357,7 +392,7 @@ _unsafe_closer(int first, int last) } /* Close all open file descriptors from start_fd and higher. - * Do not close any in the sorted py_fds_to_keep tuple. + * Do not close any in the sorted fds_to_keep tuple. * * This function violates the strict use of async signal safe functions. :( * It calls opendir(), readdir() and closedir(). Of these, the one most @@ -370,11 +405,13 @@ _unsafe_closer(int first, int last) * http://womble.decadent.org.uk/readdir_r-advisory.html */ static void -_close_open_fds_maybe_unsafe(int start_fd, PyObject* py_fds_to_keep) +_close_open_fds_maybe_unsafe(int start_fd, int *fds_to_keep, + Py_ssize_t fds_to_keep_len) { DIR *proc_fd_dir; #ifndef HAVE_DIRFD - while (_is_fd_in_sorted_fd_sequence(start_fd, py_fds_to_keep)) { + while (_is_fd_in_sorted_fd_sequence(start_fd, fds_to_keep, + fds_to_keep_len)) { ++start_fd; } /* Close our lowest fd before we call opendir so that it is likely to @@ -393,7 +430,8 @@ _close_open_fds_maybe_unsafe(int start_fd, PyObject* py_fds_to_keep) proc_fd_dir = opendir(FD_DIR); if (!proc_fd_dir) { /* No way to get a list of open fds. */ - _close_range_except(start_fd, -1, py_fds_to_keep, _unsafe_closer); + _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len, + _unsafe_closer); } else { struct dirent *dir_entry; #ifdef HAVE_DIRFD @@ -407,14 +445,16 @@ _close_open_fds_maybe_unsafe(int start_fd, PyObject* py_fds_to_keep) if ((fd = _pos_int_from_ascii(dir_entry->d_name)) < 0) continue; /* Not a number. */ if (fd != fd_used_by_opendir && fd >= start_fd && - !_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) { + !_is_fd_in_sorted_fd_sequence(fd, fds_to_keep, + fds_to_keep_len)) { close(fd); } errno = 0; } if (errno) { /* readdir error, revert behavior. Highly Unlikely. */ - _close_range_except(start_fd, -1, py_fds_to_keep, _unsafe_closer); + _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len, + _unsafe_closer); } closedir(proc_fd_dir); } @@ -442,16 +482,16 @@ _close_range_closer(int first, int last) #endif static void -_close_open_fds(int start_fd, PyObject* py_fds_to_keep) +_close_open_fds(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len) { #ifdef HAVE_ASYNC_SAFE_CLOSE_RANGE if (_close_range_except( - start_fd, INT_MAX, py_fds_to_keep, + start_fd, INT_MAX, fds_to_keep, fds_to_keep_len, _close_range_closer) == 0) { return; } #endif - _close_open_fds_fallback(start_fd, py_fds_to_keep); + _close_open_fds_fallback(start_fd, fds_to_keep, fds_to_keep_len); } #ifdef VFORK_USABLE @@ -544,7 +584,7 @@ child_exec(char *const exec_array[], Py_ssize_t extra_group_size, const gid_t *extra_groups, uid_t uid, int child_umask, const void *child_sigmask, - PyObject *py_fds_to_keep, + int *fds_to_keep, Py_ssize_t fds_to_keep_len, PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { @@ -554,7 +594,7 @@ child_exec(char *const exec_array[], /* Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1]; - if (make_inheritable(py_fds_to_keep, errpipe_write) < 0) + if (make_inheritable(fds_to_keep, fds_to_keep_len, errpipe_write) < 0) goto error; /* Close parent's pipe ends. */ @@ -676,7 +716,7 @@ child_exec(char *const exec_array[], /* close FDs after executing preexec_fn, which might open FDs */ if (close_fds) { /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */ - _close_open_fds(3, py_fds_to_keep); + _close_open_fds(3, fds_to_keep, fds_to_keep_len); } /* This loop matches the Lib/os.py _execvpe()'s PATH search when */ @@ -750,7 +790,7 @@ do_fork_exec(char *const exec_array[], Py_ssize_t extra_group_size, const gid_t *extra_groups, uid_t uid, int child_umask, const void *child_sigmask, - PyObject *py_fds_to_keep, + int *fds_to_keep, Py_ssize_t fds_to_keep_len, PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { @@ -801,7 +841,8 @@ do_fork_exec(char *const exec_array[], close_fds, restore_signals, call_setsid, pgid_to_set, gid, extra_group_size, extra_groups, uid, child_umask, child_sigmask, - py_fds_to_keep, preexec_fn, preexec_fn_args_tuple); + fds_to_keep, fds_to_keep_len, + preexec_fn, preexec_fn_args_tuple); _exit(255); return 0; /* Dead code to avoid a potential compiler warning. */ } @@ -881,6 +922,8 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, Py_ssize_t extra_group_size = 0; int need_after_fork = 0; int saved_errno = 0; + int *c_fds_to_keep = NULL; + Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep); PyInterpreterState *interp = PyInterpreterState_Get(); if ((preexec_fn != Py_None) && (interp != PyInterpreterState_Main())) { @@ -1031,6 +1074,15 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, #endif /* HAVE_SETREUID */ } + c_fds_to_keep = PyMem_RawMalloc(fds_to_keep_len * sizeof(int)); + if (c_fds_to_keep == NULL) { + PyErr_SetString(PyExc_MemoryError, "failed to malloc c_fds_to_keep"); + goto cleanup; + } + if (convert_fds_to_keep_to_c(py_fds_to_keep, c_fds_to_keep) < 0) { + goto cleanup; + } + /* This must be the last thing done before fork() because we do not * want to call PyOS_BeforeFork() if there is any chance of another * error leading to the cleanup: code without calling fork(). */ @@ -1073,7 +1125,8 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, close_fds, restore_signals, call_setsid, pgid_to_set, gid, extra_group_size, extra_groups, uid, child_umask, old_sigmask, - py_fds_to_keep, preexec_fn, preexec_fn_args_tuple); + c_fds_to_keep, fds_to_keep_len, + preexec_fn, preexec_fn_args_tuple); /* Parent (original) process */ if (pid == (pid_t)-1) { @@ -1103,6 +1156,10 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, PyOS_AfterFork_Parent(); cleanup: + if (c_fds_to_keep != NULL) { + PyMem_RawFree(c_fds_to_keep); + } + if (saved_errno != 0) { errno = saved_errno; /* We can't call this above as PyOS_AfterFork_Parent() calls back From webhook-mailer at python.org Wed May 17 15:59:20 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 17 May 2023 19:59:20 -0000 Subject: [Python-checkins] gh-104496: IDLE - fix About for mixed tcl/tk versions (#104585) Message-ID: <mailman.413.1684353561.13550.python-checkins@python.org> https://github.com/python/cpython/commit/aed643baa968b4959b830d37750080cac546fba7 commit: aed643baa968b4959b830d37750080cac546fba7 branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-17T15:59:13-04:00 summary: gh-104496: IDLE - fix About for mixed tcl/tk versions (#104585) Print both if they are different, as may happen in the future. files: A Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/help_about.py M Lib/idlelib/idle_test/test_help_about.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index e97e3ca01ef3..f78e45e671c9 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,9 @@ Released on 2023-10-02 ========================= +gh-104486: Make About print both tcl and tk versions if different, +as is expected someday. + gh-88496 Fix IDLE test hang on macOS. gh-103314 Support sys.last_exc after exceptions in Shell. diff --git a/Lib/idlelib/help_about.py b/Lib/idlelib/help_about.py index a0085a40b980..cfa4ca781f08 100644 --- a/Lib/idlelib/help_about.py +++ b/Lib/idlelib/help_about.py @@ -11,15 +11,12 @@ from idlelib import textview -version = python_version() +pyver = python_version() - -def build_bits(): - "Return bits for platform." - if sys.platform == 'darwin': - return '64' if sys.maxsize > 2**32 else '32' - else: - return architecture()[0][:2] +if sys.platform == 'darwin': + bits = '64' if sys.maxsize > 2**32 else '32' +else: + bits = architecture()[0][:2] class AboutDialog(Toplevel): @@ -45,7 +42,7 @@ def __init__(self, parent, title=None, *, _htest=False, _utest=False): self.create_widgets() self.resizable(height=False, width=False) self.title(title or - f'About IDLE {version} ({build_bits()} bit)') + f'About IDLE {pyver} ({bits} bit)') self.transient(parent) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.ok) @@ -76,8 +73,8 @@ def create_widgets(self): bg=self.bg, font=('courier', 24, 'bold')) header.grid(row=0, column=0, sticky=E, padx=10, pady=10) - tk_patchlevel = self.info_patchlevel() - ext = '.png' if tk_patchlevel >= (8, 6) else '.gif' + tkpatch = self._root().getvar('tk_patchLevel') + ext = '.png' if tkpatch >= '8.6' else '.gif' icon = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Icons', f'idle_48{ext}') self.icon_image = PhotoImage(master=self._root(), file=icon) @@ -102,13 +99,11 @@ def create_widgets(self): height=2, bg=self.bg).grid(row=8, column=0, sticky=EW, columnspan=3, padx=5, pady=5) - pyver = Label(frame_background, - text='Python version: ' + version, - fg=self.fg, bg=self.bg) - pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0) - tkver = Label(frame_background, text=f'Tk version: {tk_patchlevel}', - fg=self.fg, bg=self.bg) - tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0) + tclver = str(self.info_patchlevel()) + tkver = ' and ' + tkpatch if tkpatch != tclver else '' + versions = f"Python {pyver} with tcl/tk {tclver}{tkver}" + vers = Label(frame_background, text=versions, fg=self.fg, bg=self.bg) + vers.grid(row=9, column=0, sticky=W, padx=10, pady=0) py_buttons = Frame(frame_background, bg=self.bg) py_buttons.grid(row=10, column=0, columnspan=2, sticky=NSEW) self.py_license = Button(py_buttons, text='License', width=8, @@ -128,10 +123,10 @@ def create_widgets(self): height=2, bg=self.bg).grid(row=11, column=0, sticky=EW, columnspan=3, padx=5, pady=5) - idlever = Label(frame_background, - text='IDLE version: ' + version, + idle = Label(frame_background, + text='IDLE', fg=self.fg, bg=self.bg) - idlever.grid(row=12, column=0, sticky=W, padx=10, pady=0) + idle.grid(row=12, column=0, sticky=W, padx=10, pady=0) idle_buttons = Frame(frame_background, bg=self.bg) idle_buttons.grid(row=13, column=0, columnspan=3, sticky=NSEW) self.readme = Button(idle_buttons, text='README', width=8, diff --git a/Lib/idlelib/idle_test/test_help_about.py b/Lib/idlelib/idle_test/test_help_about.py index b915535acac0..8b79487b15d4 100644 --- a/Lib/idlelib/idle_test/test_help_about.py +++ b/Lib/idlelib/idle_test/test_help_about.py @@ -36,7 +36,7 @@ def tearDownClass(cls): del cls.root def test_build_bits(self): - self.assertIn(help_about.build_bits(), ('32', '64')) + self.assertIn(help_about.bits, ('32', '64')) def test_dialog_title(self): """Test about dialog title""" @@ -107,7 +107,7 @@ def test_dialog_title(self): """Test about dialog title""" self.assertEqual(self.dialog.title(), f'About IDLE {python_version()}' - f' ({help_about.build_bits()} bit)') + f' ({help_about.bits} bit)') class CloseTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst b/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst new file mode 100644 index 000000000000..18d83150e94f --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst @@ -0,0 +1 @@ +About prints both tcl and tk versions if different (expected someday). From webhook-mailer at python.org Wed May 17 16:31:32 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 17 May 2023 20:31:32 -0000 Subject: [Python-checkins] [3.11] gh-104496: IDLE - fix About for mixed tcl/tk versions (GH-104585) (#104587) Message-ID: <mailman.414.1684355493.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0560fd3f9874d577f0fe3d7a47fd3c46b16af068 commit: 0560fd3f9874d577f0fe3d7a47fd3c46b16af068 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-17T20:31:22Z summary: [3.11] gh-104496: IDLE - fix About for mixed tcl/tk versions (GH-104585) (#104587) gh-104496: IDLE - fix About for mixed tcl/tk versions (GH-104585) Print both if they are different, as may happen in the future. (cherry picked from commit aed643baa968b4959b830d37750080cac546fba7) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: A Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/help_about.py M Lib/idlelib/idle_test/test_help_about.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 987c9924ea92..8e8e6c33bd3e 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,9 @@ Released after 2022-10-24 ========================= +gh-104486: Make About print both tcl and tk versions if different, +as is expected someday. + gh-88496 Fix IDLE test hang on macOS. gh-103314 Support sys.last_exc after exceptions in Shell. diff --git a/Lib/idlelib/help_about.py b/Lib/idlelib/help_about.py index a0085a40b980..cfa4ca781f08 100644 --- a/Lib/idlelib/help_about.py +++ b/Lib/idlelib/help_about.py @@ -11,15 +11,12 @@ from idlelib import textview -version = python_version() +pyver = python_version() - -def build_bits(): - "Return bits for platform." - if sys.platform == 'darwin': - return '64' if sys.maxsize > 2**32 else '32' - else: - return architecture()[0][:2] +if sys.platform == 'darwin': + bits = '64' if sys.maxsize > 2**32 else '32' +else: + bits = architecture()[0][:2] class AboutDialog(Toplevel): @@ -45,7 +42,7 @@ def __init__(self, parent, title=None, *, _htest=False, _utest=False): self.create_widgets() self.resizable(height=False, width=False) self.title(title or - f'About IDLE {version} ({build_bits()} bit)') + f'About IDLE {pyver} ({bits} bit)') self.transient(parent) self.grab_set() self.protocol("WM_DELETE_WINDOW", self.ok) @@ -76,8 +73,8 @@ def create_widgets(self): bg=self.bg, font=('courier', 24, 'bold')) header.grid(row=0, column=0, sticky=E, padx=10, pady=10) - tk_patchlevel = self.info_patchlevel() - ext = '.png' if tk_patchlevel >= (8, 6) else '.gif' + tkpatch = self._root().getvar('tk_patchLevel') + ext = '.png' if tkpatch >= '8.6' else '.gif' icon = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Icons', f'idle_48{ext}') self.icon_image = PhotoImage(master=self._root(), file=icon) @@ -102,13 +99,11 @@ def create_widgets(self): height=2, bg=self.bg).grid(row=8, column=0, sticky=EW, columnspan=3, padx=5, pady=5) - pyver = Label(frame_background, - text='Python version: ' + version, - fg=self.fg, bg=self.bg) - pyver.grid(row=9, column=0, sticky=W, padx=10, pady=0) - tkver = Label(frame_background, text=f'Tk version: {tk_patchlevel}', - fg=self.fg, bg=self.bg) - tkver.grid(row=9, column=1, sticky=W, padx=2, pady=0) + tclver = str(self.info_patchlevel()) + tkver = ' and ' + tkpatch if tkpatch != tclver else '' + versions = f"Python {pyver} with tcl/tk {tclver}{tkver}" + vers = Label(frame_background, text=versions, fg=self.fg, bg=self.bg) + vers.grid(row=9, column=0, sticky=W, padx=10, pady=0) py_buttons = Frame(frame_background, bg=self.bg) py_buttons.grid(row=10, column=0, columnspan=2, sticky=NSEW) self.py_license = Button(py_buttons, text='License', width=8, @@ -128,10 +123,10 @@ def create_widgets(self): height=2, bg=self.bg).grid(row=11, column=0, sticky=EW, columnspan=3, padx=5, pady=5) - idlever = Label(frame_background, - text='IDLE version: ' + version, + idle = Label(frame_background, + text='IDLE', fg=self.fg, bg=self.bg) - idlever.grid(row=12, column=0, sticky=W, padx=10, pady=0) + idle.grid(row=12, column=0, sticky=W, padx=10, pady=0) idle_buttons = Frame(frame_background, bg=self.bg) idle_buttons.grid(row=13, column=0, columnspan=3, sticky=NSEW) self.readme = Button(idle_buttons, text='README', width=8, diff --git a/Lib/idlelib/idle_test/test_help_about.py b/Lib/idlelib/idle_test/test_help_about.py index b915535acac0..8b79487b15d4 100644 --- a/Lib/idlelib/idle_test/test_help_about.py +++ b/Lib/idlelib/idle_test/test_help_about.py @@ -36,7 +36,7 @@ def tearDownClass(cls): del cls.root def test_build_bits(self): - self.assertIn(help_about.build_bits(), ('32', '64')) + self.assertIn(help_about.bits, ('32', '64')) def test_dialog_title(self): """Test about dialog title""" @@ -107,7 +107,7 @@ def test_dialog_title(self): """Test about dialog title""" self.assertEqual(self.dialog.title(), f'About IDLE {python_version()}' - f' ({help_about.build_bits()} bit)') + f' ({help_about.bits} bit)') class CloseTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst b/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst new file mode 100644 index 000000000000..18d83150e94f --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst @@ -0,0 +1 @@ +About prints both tcl and tk versions if different (expected someday). From webhook-mailer at python.org Wed May 17 17:05:29 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 17 May 2023 21:05:29 -0000 Subject: [Python-checkins] gh-104050: Add type hints to Argument Clinic converter keywords (#104588) Message-ID: <mailman.415.1684357530.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2f369cafeeb4a4886b00396abd8a5f33e555e1c3 commit: 2f369cafeeb4a4886b00396abd8a5f33e555e1c3 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-17T21:05:22Z summary: gh-104050: Add type hints to Argument Clinic converter keywords (#104588) Introduce TypeSet, and use it to annotate the 'accept' keyword of various C converters. Also add some missing return annotations for converter init functions. files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3e54ba03d7a5..5fcf2bf485fc 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2600,7 +2600,7 @@ class CConverter(metaclass=CConverterAutoRegister): # Or the magic value "unknown" if this value is a cannot be evaluated # at Argument-Clinic-preprocessing time (but is presumed to be valid # at runtime). - default = unspecified + default: bool | Unspecified = unspecified # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) @@ -2655,7 +2655,7 @@ class CConverter(metaclass=CConverterAutoRegister): # What encoding do we want for this variable? Only used # by format units starting with 'e'. - encoding = None + encoding: str | None = None # Should this object be required to be a subclass of a specific type? # If not None, should be a string representing a pointer to a @@ -2982,6 +2982,8 @@ def parser_name(self): # note however that they will never be called with keyword-only parameters. legacy_converters: ConverterDict = {} +TypeSet = set[bltns.type[Any]] + class bool_converter(CConverter): type = 'int' @@ -2989,7 +2991,7 @@ class bool_converter(CConverter): format_unit = 'p' c_ignored_default = '0' - def converter_init(self, *, accept={object}): + def converter_init(self, *, accept: TypeSet = {object}) -> None: if accept == {int}: self.format_unit = 'i' elif accept != {object}: @@ -3176,7 +3178,7 @@ class int_converter(CConverter): format_unit = 'i' c_ignored_default = "0" - def converter_init(self, *, accept={int}, type=None) -> None: + def converter_init(self, *, accept: TypeSet = {int}, type=None) -> None: if accept == {str}: self.format_unit = 'C' elif accept != {int}: @@ -3313,7 +3315,7 @@ class Py_ssize_t_converter(CConverter): type = 'Py_ssize_t' c_ignored_default = "0" - def converter_init(self, *, accept={int}) -> None: + def converter_init(self, *, accept: TypeSet = {int}) -> None: if accept == {int}: self.format_unit = 'n' self.default_type = int @@ -3344,7 +3346,7 @@ def parse_arg(self, argname: str, displayname: str) -> str: class slice_index_converter(CConverter): type = 'Py_ssize_t' - def converter_init(self, *, accept={int, NoneType}) -> None: + def converter_init(self, *, accept: TypeSet = {int, NoneType}) -> None: if accept == {int}: self.converter = '_PyEval_SliceIndexNotNone' elif accept == {int, NoneType}: @@ -3447,7 +3449,12 @@ class object_converter(CConverter): type = 'PyObject *' format_unit = 'O' - def converter_init(self, *, converter=None, type=None, subclass_of=None): + def converter_init( + self, *, + converter=None, + type=None, + subclass_of=None + ) -> None: if converter: if subclass_of: fail("object: Cannot pass in both 'converter' and 'subclass_of'") @@ -3483,7 +3490,13 @@ class str_converter(CConverter): default_type = (str, Null, NoneType) format_unit = 's' - def converter_init(self, *, accept={str}, encoding=None, zeroes=False): + def converter_init( + self, + *, + accept: TypeSet = {str}, + encoding: str | None = None, + zeroes: bool = False + ) -> None: key = str_converter_key(accept, encoding, zeroes) format_unit = str_converter_argument_map.get(key) @@ -3561,7 +3574,14 @@ def parse_arg(self, argname: str, displayname: str) -> str: # mapping from arguments to format unit *and* registers the # legacy C converter for that format unit. # -def r(format_unit, *, accept, encoding=False, zeroes=False): +ConverterKeywordDict = dict[str, TypeSet | bool] + +def r(format_unit: str, + *, + accept: TypeSet, + encoding: bool = False, + zeroes: bool = False +) -> None: if not encoding and format_unit != 's': # add the legacy c converters here too. # @@ -3571,7 +3591,7 @@ def r(format_unit, *, accept, encoding=False, zeroes=False): # # also don't add the converter for 's' because # the metaclass for CConverter adds it for us. - kwargs = {} + kwargs: ConverterKeywordDict = {} if accept != {str}: kwargs['accept'] = accept if zeroes: @@ -3660,7 +3680,11 @@ class Py_UNICODE_converter(CConverter): type = 'const Py_UNICODE *' default_type = (str, Null, NoneType) - def converter_init(self, *, accept={str}, zeroes: bool = False) -> None: + def converter_init( + self, *, + accept: TypeSet = {str}, + zeroes: bool = False + ) -> None: format_unit = 'Z' if accept=={str, NoneType} else 'u' if zeroes: format_unit += '#' @@ -3722,7 +3746,7 @@ class Py_buffer_converter(CConverter): impl_by_reference = True c_ignored_default = "{NULL, NULL}" - def converter_init(self, *, accept={buffer}) -> None: + def converter_init(self, *, accept: TypeSet = {buffer}) -> None: if self.default not in (unspecified, None): fail("The only legal default value for Py_buffer is None.") From webhook-mailer at python.org Wed May 17 17:41:32 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 17 May 2023 21:41:32 -0000 Subject: [Python-checkins] [3.11] gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (#104575) Message-ID: <mailman.416.1684359693.13550.python-checkins@python.org> https://github.com/python/cpython/commit/610cc0ab1b760b2abaac92bd256b96191c46b941 commit: 610cc0ab1b760b2abaac92bd256b96191c46b941 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-17T21:41:25Z summary: [3.11] gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (#104575) * gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) `urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%20any%20leading%20and%20trailing%20C0%20control%20or%20space%20from%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). --------- (cherry picked from commit 2f630e1ce18ad2e07428296532a68b11dc66ad10) Co-authored-by: Illia Volochii <illia.volochii at gmail.com> Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst M Doc/library/urllib.parse.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 96b396510794..a326e82e308d 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -159,6 +159,10 @@ or on combining URL components into a URL string. ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html', params='', query='', fragment='') + .. warning:: + + :func:`urlparse` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.2 Added IPv6 URL parsing capabilities. @@ -324,8 +328,14 @@ or on combining URL components into a URL string. ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is decomposed before parsing, no error will be raised. - Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline - ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL. + Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0 + control and space characters are stripped from the URL. ``\n``, + ``\r`` and tab ``\t`` characters are removed from the URL at any position. + + .. warning:: + + :func:`urlsplit` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of @@ -338,6 +348,9 @@ or on combining URL components into a URL string. .. versionchanged:: 3.10 ASCII newline and tab characters are stripped from the URL. + .. versionchanged:: 3.11.4 + Leading WHATWG C0 control and space characters are stripped from the URL. + .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser .. function:: urlunsplit(parts) @@ -414,6 +427,35 @@ or on combining URL components into a URL string. or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned without changes. +.. _url-parsing-security: + +URL parsing security +-------------------- + +The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of +inputs. They may not raise errors on inputs that other applications consider +invalid. They may also succeed on some inputs that might not be considered +URLs elsewhere. Their purpose is for practical functionality rather than +purity. + +Instead of raising an exception on unusual input, they may instead return some +component parts as empty strings. Or components may contain more than perhaps +they should. + +We recommend that users of these APIs where the values may be used anywhere +with security implications code defensively. Do some verification within your +code before trusting a returned component part. Does that ``scheme`` make +sense? Is that a sensible ``path``? Is there anything strange about that +``hostname``? etc. + +What constitutes a URL is not universally well defined. Different applications +have different needs and desired constraints. For instance the living `WHATWG +spec`_ describes what user facing web clients such as a web browser require. +While :rfc:`3986` is more general. These functions incorporate some aspects of +both, but cannot be claimed compliant with either. The APIs and existing user +code with expectations on specific behaviors predate both standards leading us +to be very cautious about making API behavior changes. + .. _parsing-ascii-encoded-bytes: Parsing ASCII Encoded Bytes diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 6b23ba604cce..83ea618291e8 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -649,6 +649,65 @@ def test_urlsplit_remove_unsafe_bytes(self): self.assertEqual(p.scheme, "http") self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment") + def test_urlsplit_strip_url(self): + noise = bytes(range(0, 0x20 + 1)) + base_url = "http://User:Pass at www.python.org:080/doc/?query=yes#frag" + + url = noise.decode("utf-8") + base_url + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, "http") + self.assertEqual(p.netloc, "User:Pass at www.python.org:080") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query=yes") + self.assertEqual(p.fragment, "frag") + self.assertEqual(p.username, "User") + self.assertEqual(p.password, "Pass") + self.assertEqual(p.hostname, "www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url) + + url = noise + base_url.encode("utf-8") + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"User:Pass at www.python.org:080") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"query=yes") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, b"User") + self.assertEqual(p.password, b"Pass") + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url.encode("utf-8")) + + # Test that trailing space is preserved as some applications rely on + # this within query strings. + query_spaces_url = "https://www.python.org:88/doc/?query= " + p = urllib.parse.urlsplit(noise.decode("utf-8") + query_spaces_url) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.netloc, "www.python.org:88") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query= ") + self.assertEqual(p.port, 88) + self.assertEqual(p.geturl(), query_spaces_url) + + p = urllib.parse.urlsplit("www.pypi.org ") + # That "hostname" gets considered a "path" due to the + # trailing space and our existing logic... YUCK... + # and re-assembles via geturl aka unurlsplit into the original. + # django.core.validators.URLValidator (at least through v3.2) relies on + # this, for better or worse, to catch it in a ValidationError via its + # regular expressions. + # Here we test the basic round trip concept of such a trailing space. + self.assertEqual(urllib.parse.urlunsplit(p), "www.pypi.org ") + + # with scheme as cache-key + url = "//www.python.org/" + scheme = noise.decode("utf-8") + "https" + noise.decode("utf-8") + for _ in range(2): + p = urllib.parse.urlsplit(url, scheme=scheme) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.geturl(), "https://www.python.org/") + def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): @@ -656,7 +715,7 @@ def test_attributes_bad_port(self): for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "?"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port - url = "http://" + netloc + url = "http://" + netloc + "/" if bytes: if netloc.isascii() and port.isascii(): netloc = netloc.encode("ascii") diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 2af4700a703e..e5f0b784bf69 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -25,6 +25,10 @@ scenarios for parsing, and for backward compatibility purposes, some parsing quirks from older RFCs are retained. The testcases in test_urlparse.py provides a good indicator of parsing behavior. + +The WHATWG URL Parser spec should also be considered. We are not compliant with +it either due to existing user code API behavior expectations (Hyrum's Law). +It serves as a useful guide when making changes. """ from collections import namedtuple @@ -80,6 +84,10 @@ '0123456789' '+-.') +# Leading and trailing C0 control and space to be stripped per WHATWG spec. +# == "".join([chr(i) for i in range(0, 0x20 + 1)]) +_WHATWG_C0_CONTROL_OR_SPACE = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' + # Unsafe bytes to be removed per WHATWG spec _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] @@ -464,6 +472,10 @@ def urlsplit(url, scheme='', allow_fragments=True): """ url, scheme, _coerce_result = _coerce_args(url, scheme) + # Only lstrip url as some applications rely on preserving trailing space. + # (https://url.spec.whatwg.org/#concept-basic-url-parser would strip both) + url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) + scheme = scheme.strip(_WHATWG_C0_CONTROL_OR_SPACE) for b in _UNSAFE_URL_BYTES_TO_REMOVE: url = url.replace(b, "") diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst new file mode 100644 index 000000000000..e57ac4ed3ac5 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst @@ -0,0 +1,3 @@ +:func:`urllib.parse.urlsplit` now strips leading C0 control and space +characters following the specification for URLs defined by WHATWG in +response to CVE-2023-24329. Patch by Illia Volochii. From webhook-mailer at python.org Wed May 17 19:06:27 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 17 May 2023 23:06:27 -0000 Subject: [Python-checkins] [3.10] [3.11] gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (GH-104575) (#104592) Message-ID: <mailman.417.1684364788.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f48a96a28012d28ae37a2f4587a780a5eb779946 commit: f48a96a28012d28ae37a2f4587a780a5eb779946 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-17T16:06:06-07:00 summary: [3.10] [3.11] gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (GH-104575) (#104592) gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) `urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%20any%20leading%20and%20trailing%20C0%20control%20or%20space%20from%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). I simplified the docs by eliding the state of the world explanatory paragraph in this security release only backport. (people will see that in the mainline /3/ docs) --------- (cherry picked from commit 2f630e1ce18ad2e07428296532a68b11dc66ad10) (cherry picked from commit 610cc0ab1b760b2abaac92bd256b96191c46b941) Co-authored-by: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> Co-authored-by: Illia Volochii <illia.volochii at gmail.com> Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst M Doc/library/urllib.parse.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 96b396510794..1e85602951c2 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -159,6 +159,10 @@ or on combining URL components into a URL string. ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html', params='', query='', fragment='') + .. warning:: + + :func:`urlparse` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.2 Added IPv6 URL parsing capabilities. @@ -324,8 +328,14 @@ or on combining URL components into a URL string. ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is decomposed before parsing, no error will be raised. - Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline - ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL. + Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0 + control and space characters are stripped from the URL. ``\n``, + ``\r`` and tab ``\t`` characters are removed from the URL at any position. + + .. warning:: + + :func:`urlsplit` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of @@ -338,6 +348,9 @@ or on combining URL components into a URL string. .. versionchanged:: 3.10 ASCII newline and tab characters are stripped from the URL. + .. versionchanged:: 3.10.12 + Leading WHATWG C0 control and space characters are stripped from the URL. + .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser .. function:: urlunsplit(parts) @@ -414,6 +427,27 @@ or on combining URL components into a URL string. or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned without changes. +.. _url-parsing-security: + +URL parsing security +-------------------- + +The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of +inputs. They may not raise errors on inputs that other applications consider +invalid. They may also succeed on some inputs that might not be considered +URLs elsewhere. Their purpose is for practical functionality rather than +purity. + +Instead of raising an exception on unusual input, they may instead return some +component parts as empty strings. Or components may contain more than perhaps +they should. + +We recommend that users of these APIs where the values may be used anywhere +with security implications code defensively. Do some verification within your +code before trusting a returned component part. Does that ``scheme`` make +sense? Is that a sensible ``path``? Is there anything strange about that +``hostname``? etc. + .. _parsing-ascii-encoded-bytes: Parsing ASCII Encoded Bytes diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index ca37c3c403e3..b0aed37de7dc 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -649,6 +649,65 @@ def test_urlsplit_remove_unsafe_bytes(self): self.assertEqual(p.scheme, "http") self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment") + def test_urlsplit_strip_url(self): + noise = bytes(range(0, 0x20 + 1)) + base_url = "http://User:Pass at www.python.org:080/doc/?query=yes#frag" + + url = noise.decode("utf-8") + base_url + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, "http") + self.assertEqual(p.netloc, "User:Pass at www.python.org:080") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query=yes") + self.assertEqual(p.fragment, "frag") + self.assertEqual(p.username, "User") + self.assertEqual(p.password, "Pass") + self.assertEqual(p.hostname, "www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url) + + url = noise + base_url.encode("utf-8") + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"User:Pass at www.python.org:080") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"query=yes") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, b"User") + self.assertEqual(p.password, b"Pass") + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url.encode("utf-8")) + + # Test that trailing space is preserved as some applications rely on + # this within query strings. + query_spaces_url = "https://www.python.org:88/doc/?query= " + p = urllib.parse.urlsplit(noise.decode("utf-8") + query_spaces_url) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.netloc, "www.python.org:88") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query= ") + self.assertEqual(p.port, 88) + self.assertEqual(p.geturl(), query_spaces_url) + + p = urllib.parse.urlsplit("www.pypi.org ") + # That "hostname" gets considered a "path" due to the + # trailing space and our existing logic... YUCK... + # and re-assembles via geturl aka unurlsplit into the original. + # django.core.validators.URLValidator (at least through v3.2) relies on + # this, for better or worse, to catch it in a ValidationError via its + # regular expressions. + # Here we test the basic round trip concept of such a trailing space. + self.assertEqual(urllib.parse.urlunsplit(p), "www.pypi.org ") + + # with scheme as cache-key + url = "//www.python.org/" + scheme = noise.decode("utf-8") + "https" + noise.decode("utf-8") + for _ in range(2): + p = urllib.parse.urlsplit(url, scheme=scheme) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.geturl(), "https://www.python.org/") + def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): @@ -656,7 +715,7 @@ def test_attributes_bad_port(self): for port in ("foo", "1.5", "-1", "0x10", "-0", "1_1", " 1", "1 ", "?"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port - url = "http://" + netloc + url = "http://" + netloc + "/" if bytes: if netloc.isascii() and port.isascii(): netloc = netloc.encode("ascii") diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 26ddf307485d..0ab2023843f6 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -25,6 +25,10 @@ scenarios for parsing, and for backward compatibility purposes, some parsing quirks from older RFCs are retained. The testcases in test_urlparse.py provides a good indicator of parsing behavior. + +The WHATWG URL Parser spec should also be considered. We are not compliant with +it either due to existing user code API behavior expectations (Hyrum's Law). +It serves as a useful guide when making changes. """ import re @@ -78,6 +82,10 @@ '0123456789' '+-.') +# Leading and trailing C0 control and space to be stripped per WHATWG spec. +# == "".join([chr(i) for i in range(0, 0x20 + 1)]) +_WHATWG_C0_CONTROL_OR_SPACE = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' + # Unsafe bytes to be removed per WHATWG spec _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] @@ -455,6 +463,10 @@ def urlsplit(url, scheme='', allow_fragments=True): """ url, scheme, _coerce_result = _coerce_args(url, scheme) + # Only lstrip url as some applications rely on preserving trailing space. + # (https://url.spec.whatwg.org/#concept-basic-url-parser would strip both) + url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) + scheme = scheme.strip(_WHATWG_C0_CONTROL_OR_SPACE) for b in _UNSAFE_URL_BYTES_TO_REMOVE: url = url.replace(b, "") diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst new file mode 100644 index 000000000000..e57ac4ed3ac5 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst @@ -0,0 +1,3 @@ +:func:`urllib.parse.urlsplit` now strips leading C0 control and space +characters following the specification for URLs defined by WHATWG in +response to CVE-2023-24329. Patch by Illia Volochii. From webhook-mailer at python.org Wed May 17 19:43:38 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 17 May 2023 23:43:38 -0000 Subject: [Python-checkins] gh-104555: Runtime-checkable protocols: Don't let previous calls to `isinstance()` influence whether `issubclass()` raises an exception (#104559) Message-ID: <mailman.418.1684367019.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b27fe67f3c643e174c3619b669228ef34b6d87ee commit: b27fe67f3c643e174c3619b669228ef34b6d87ee branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-17T23:43:12Z summary: gh-104555: Runtime-checkable protocols: Don't let previous calls to `isinstance()` influence whether `issubclass()` raises an exception (#104559) Co-authored-by: Carl Meyer <carl at oddbird.net> files: A Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.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 045f2a3b4dfe..bf038bf143a6 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2695,6 +2695,82 @@ class D(PNonCall): ... with self.assertRaises(TypeError): issubclass(D, PNonCall) + def test_no_weird_caching_with_issubclass_after_isinstance(self): + @runtime_checkable + class Spam(Protocol): + x: int + + class Eggs: + def __init__(self) -> None: + self.x = 42 + + self.assertIsInstance(Eggs(), Spam) + + # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, + # TypeError wouldn't be raised here, + # as the cached result of the isinstance() check immediately above + # would mean the issubclass() call would short-circuit + # before we got to the "raise TypeError" line + with self.assertRaises(TypeError): + issubclass(Eggs, Spam) + + def test_no_weird_caching_with_issubclass_after_isinstance_2(self): + @runtime_checkable + class Spam(Protocol): + x: int + + class Eggs: ... + + self.assertNotIsInstance(Eggs(), Spam) + + # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, + # TypeError wouldn't be raised here, + # as the cached result of the isinstance() check immediately above + # would mean the issubclass() call would short-circuit + # before we got to the "raise TypeError" line + with self.assertRaises(TypeError): + issubclass(Eggs, Spam) + + def test_no_weird_caching_with_issubclass_after_isinstance_3(self): + @runtime_checkable + class Spam(Protocol): + x: int + + class Eggs: + def __getattr__(self, attr): + if attr == "x": + return 42 + raise AttributeError(attr) + + self.assertNotIsInstance(Eggs(), Spam) + + # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, + # TypeError wouldn't be raised here, + # as the cached result of the isinstance() check immediately above + # would mean the issubclass() call would short-circuit + # before we got to the "raise TypeError" line + with self.assertRaises(TypeError): + issubclass(Eggs, Spam) + + def test_no_weird_caching_with_issubclass_after_isinstance_pep695(self): + @runtime_checkable + class Spam[T](Protocol): + x: T + + class Eggs[T]: + def __init__(self, x: T) -> None: + self.x = x + + self.assertIsInstance(Eggs(42), Spam) + + # gh-104555: If we didn't override ABCMeta.__subclasscheck__ in _ProtocolMeta, + # TypeError wouldn't be raised here, + # as the cached result of the isinstance() check immediately above + # would mean the issubclass() call would short-circuit + # before we got to the "raise TypeError" line + with self.assertRaises(TypeError): + issubclass(Eggs, Spam) + def test_protocols_isinstance(self): T = TypeVar('T') diff --git a/Lib/typing.py b/Lib/typing.py index 82107300734a..91b5fe5b87e6 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1775,8 +1775,8 @@ def _pickle_pskwargs(pskwargs): class _ProtocolMeta(ABCMeta): - # This metaclass is really unfortunate and exists only because of - # the lack of __instancehook__. + # This metaclass is somewhat unfortunate, + # but is necessary for several reasons... def __init__(cls, *args, **kwargs): super().__init__(*args, **kwargs) cls.__protocol_attrs__ = _get_protocol_attrs(cls) @@ -1786,6 +1786,17 @@ def __init__(cls, *args, **kwargs): callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__ ) + def __subclasscheck__(cls, other): + if ( + getattr(cls, '_is_protocol', False) + and not cls.__callable_proto_members_only__ + and not _allow_reckless_class_checks(depth=2) + ): + raise TypeError( + "Protocols with non-method members don't support issubclass()" + ) + return super().__subclasscheck__(other) + def __instancecheck__(cls, instance): # We need this method for situations where attributes are # assigned in __init__. @@ -1869,11 +1880,6 @@ def _proto_hook(other): raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") - if not cls.__callable_proto_members_only__ : - if _allow_reckless_class_checks(): - return NotImplemented - raise TypeError("Protocols with non-method members" - " don't support issubclass()") if not isinstance(other, type): # Same error message as for issubclass(1, int). raise TypeError('issubclass() arg 1 must be a class') diff --git a/Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst b/Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst new file mode 100644 index 000000000000..2992346484c5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst @@ -0,0 +1,7 @@ +Fix issue where an :func:`issubclass` check comparing a class ``X`` against a +:func:`runtime-checkable protocol <typing.runtime_checkable>` ``Y`` with +non-callable members would not cause :exc:`TypeError` to be raised if an +:func:`isinstance` call had previously been made comparing an instance of ``X`` +to ``Y``. This issue was present in edge cases on Python 3.11, but became more +prominent in 3.12 due to some unrelated changes that were made to +runtime-checkable protocols. Patch by Alex Waygood. From webhook-mailer at python.org Wed May 17 19:45:18 2023 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 17 May 2023 23:45:18 -0000 Subject: [Python-checkins] gh-104340: Suppress warning about unawaited exception for closed pipe stdin (#104586) Message-ID: <mailman.419.1684367119.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7fc8e2d4627cdba5cb0075c9052ed6f4b6ecd36d commit: 7fc8e2d4627cdba5cb0075c9052ed6f4b6ecd36d branch: main author: Guido van Rossum <guido at python.org> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-17T16:45:11-07:00 summary: gh-104340: Suppress warning about unawaited exception for closed pipe stdin (#104586) files: A Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst M Lib/asyncio/subprocess.py diff --git a/Lib/asyncio/subprocess.py b/Lib/asyncio/subprocess.py index 50727ca300e6..c4e5ba2061cf 100644 --- a/Lib/asyncio/subprocess.py +++ b/Lib/asyncio/subprocess.py @@ -81,6 +81,9 @@ def pipe_connection_lost(self, fd, exc): self._stdin_closed.set_result(None) else: self._stdin_closed.set_exception(exc) + # Since calling `wait_closed()` is not mandatory, + # we shouldn't log the traceback if this is not awaited. + self._stdin_closed._log_traceback = False return if fd == 1: reader = self.stdout diff --git a/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst b/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst new file mode 100644 index 000000000000..5b03622df6a2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst @@ -0,0 +1 @@ +When an ``asyncio`` pipe protocol loses its connection due to an error, and the caller doesn't await ``wait_closed()`` on the corresponding ``StreamWriter``, don't log a warning about an exception that was never retrieved. After all, according to the ``StreamWriter.close()`` docs, the ``wait_closed()`` call is optional ("not mandatory"). From webhook-mailer at python.org Wed May 17 20:09:31 2023 From: webhook-mailer at python.org (gvanrossum) Date: Thu, 18 May 2023 00:09:31 -0000 Subject: [Python-checkins] [3.11] gh-104340: Suppress warning about unawaited exception for closed pipe stdin (GH-104586) (#104594) Message-ID: <mailman.420.1684368572.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a8fc8b7e81e1e830771758a00312b7cea2803085 commit: a8fc8b7e81e1e830771758a00312b7cea2803085 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-18T00:09:12Z summary: [3.11] gh-104340: Suppress warning about unawaited exception for closed pipe stdin (GH-104586) (#104594) (cherry picked from commit 7fc8e2d4627cdba5cb0075c9052ed6f4b6ecd36d) Co-authored-by: Guido van Rossum <guido at python.org> files: A Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst M Lib/asyncio/subprocess.py diff --git a/Lib/asyncio/subprocess.py b/Lib/asyncio/subprocess.py index cd10231f710f..c380bbb0ee93 100644 --- a/Lib/asyncio/subprocess.py +++ b/Lib/asyncio/subprocess.py @@ -81,6 +81,9 @@ def pipe_connection_lost(self, fd, exc): self._stdin_closed.set_result(None) else: self._stdin_closed.set_exception(exc) + # Since calling `wait_closed()` is not mandatory, + # we shouldn't log the traceback if this is not awaited. + self._stdin_closed._log_traceback = False return if fd == 1: reader = self.stdout diff --git a/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst b/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst new file mode 100644 index 000000000000..5b03622df6a2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst @@ -0,0 +1 @@ +When an ``asyncio`` pipe protocol loses its connection due to an error, and the caller doesn't await ``wait_closed()`` on the corresponding ``StreamWriter``, don't log a warning about an exception that was never retrieved. After all, according to the ``StreamWriter.close()`` docs, the ``wait_closed()`` call is optional ("not mandatory"). From webhook-mailer at python.org Wed May 17 21:37:16 2023 From: webhook-mailer at python.org (terryjreedy) Date: Thu, 18 May 2023 01:37:16 -0000 Subject: [Python-checkins] gh-104499: IDLE - fix completions for tk aqua 8.7 (#104591) Message-ID: <mailman.421.1684373837.13550.python-checkins@python.org> https://github.com/python/cpython/commit/678bf57ed04b8c250f0bc031ebd264bece76e731 commit: 678bf57ed04b8c250f0bc031ebd264bece76e731 branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-17T21:36:58-04:00 summary: gh-104499: IDLE - fix completions for tk aqua 8.7 (#104591) files: A Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/autocomplete_w.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index f78e45e671c9..553b932aa6b6 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,8 @@ Released on 2023-10-02 ========================= +gh-104499: Fix completions for Tk Aqua 8.7 (currently blank). + gh-104486: Make About print both tcl and tk versions if different, as is expected someday. diff --git a/Lib/idlelib/autocomplete_w.py b/Lib/idlelib/autocomplete_w.py index 0f835a9cc1d0..5bd7ce7f5e5a 100644 --- a/Lib/idlelib/autocomplete_w.py +++ b/Lib/idlelib/autocomplete_w.py @@ -182,16 +182,11 @@ def show_window(self, comp_lists, index, complete, mode, userWantsWin): self.userwantswindow = userWantsWin self.lasttypedstart = self.start - # Put widgets in place self.autocompletewindow = acw = Toplevel(self.widget) - # Put it in a position so that it is not seen. - acw.wm_geometry("+10000+10000") - # Make it float + acw.withdraw() acw.wm_overrideredirect(1) try: - # This command is only needed and available on Tk >= 8.4.0 for OSX - # Without it, call tips intrude on the typing process by grabbing - # the focus. + # Prevent grabbing focus on maxOS. acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w, "help", "noActivates") except TclError: @@ -271,6 +266,7 @@ def winconfig_event(self, event): # place acw above current line new_y -= acw_height acw.wm_geometry("+%d+%d" % (new_x, new_y)) + acw.deiconify() acw.update_idletasks() except TclError: pass diff --git a/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst b/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst new file mode 100644 index 000000000000..20cbd9ab9e57 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst @@ -0,0 +1 @@ +Fix completions for Tk Aqua 8.7 (currently blank). From webhook-mailer at python.org Wed May 17 22:03:00 2023 From: webhook-mailer at python.org (terryjreedy) Date: Thu, 18 May 2023 02:03:00 -0000 Subject: [Python-checkins] [3.11] gh-104499: IDLE - fix completions for tk aqua 8.7 (GH-104591) (#104596) Message-ID: <mailman.422.1684375380.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e96fb399c11fdd0e9698ee44c33fe5d08def4977 commit: e96fb399c11fdd0e9698ee44c33fe5d08def4977 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-18T02:02:53Z summary: [3.11] gh-104499: IDLE - fix completions for tk aqua 8.7 (GH-104591) (#104596) gh-104499: IDLE - fix completions for tk aqua 8.7 (GH-104591) (cherry picked from commit 678bf57ed04b8c250f0bc031ebd264bece76e731) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: A Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/autocomplete_w.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 8e8e6c33bd3e..89e86c13b25e 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,8 @@ Released after 2022-10-24 ========================= +gh-104499: Fix completions for Tk Aqua 8.7 (currently blank). + gh-104486: Make About print both tcl and tk versions if different, as is expected someday. diff --git a/Lib/idlelib/autocomplete_w.py b/Lib/idlelib/autocomplete_w.py index 0f835a9cc1d0..5bd7ce7f5e5a 100644 --- a/Lib/idlelib/autocomplete_w.py +++ b/Lib/idlelib/autocomplete_w.py @@ -182,16 +182,11 @@ def show_window(self, comp_lists, index, complete, mode, userWantsWin): self.userwantswindow = userWantsWin self.lasttypedstart = self.start - # Put widgets in place self.autocompletewindow = acw = Toplevel(self.widget) - # Put it in a position so that it is not seen. - acw.wm_geometry("+10000+10000") - # Make it float + acw.withdraw() acw.wm_overrideredirect(1) try: - # This command is only needed and available on Tk >= 8.4.0 for OSX - # Without it, call tips intrude on the typing process by grabbing - # the focus. + # Prevent grabbing focus on maxOS. acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w, "help", "noActivates") except TclError: @@ -271,6 +266,7 @@ def winconfig_event(self, event): # place acw above current line new_y -= acw_height acw.wm_geometry("+%d+%d" % (new_x, new_y)) + acw.deiconify() acw.update_idletasks() except TclError: pass diff --git a/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst b/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst new file mode 100644 index 000000000000..20cbd9ab9e57 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst @@ -0,0 +1 @@ +Fix completions for Tk Aqua 8.7 (currently blank). From webhook-mailer at python.org Wed May 17 22:35:53 2023 From: webhook-mailer at python.org (terryjreedy) Date: Thu, 18 May 2023 02:35:53 -0000 Subject: [Python-checkins] gh-104499: Fix typo. (#104598) Message-ID: <mailman.423.1684377354.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c5b670efd1e6dabc94b6308734d63f762480b80f commit: c5b670efd1e6dabc94b6308734d63f762480b80f branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-18T02:35:46Z summary: gh-104499: Fix typo. (#104598) files: M Lib/idlelib/autocomplete_w.py diff --git a/Lib/idlelib/autocomplete_w.py b/Lib/idlelib/autocomplete_w.py index 5bd7ce7f5e5a..24320b5a3bff 100644 --- a/Lib/idlelib/autocomplete_w.py +++ b/Lib/idlelib/autocomplete_w.py @@ -186,7 +186,7 @@ def show_window(self, comp_lists, index, complete, mode, userWantsWin): acw.withdraw() acw.wm_overrideredirect(1) try: - # Prevent grabbing focus on maxOS. + # Prevent grabbing focus on macOS. acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w, "help", "noActivates") except TclError: From webhook-mailer at python.org Thu May 18 00:20:54 2023 From: webhook-mailer at python.org (vsajip) Date: Thu, 18 May 2023 04:20:54 -0000 Subject: [Python-checkins] gh-103606: Improve error message from logging.config.FileConfig (GH-103628) Message-ID: <mailman.424.1684383655.13550.python-checkins@python.org> https://github.com/python/cpython/commit/152227b569c3a9b87fe0483706f704762ced6d75 commit: 152227b569c3a9b87fe0483706f704762ced6d75 branch: main author: Prince Roshan <princekrroshan01 at gmail.com> committer: vsajip <vinay_sajip at yahoo.co.uk> date: 2023-05-18T05:20:47+01:00 summary: gh-103606: Improve error message from logging.config.FileConfig (GH-103628) files: 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 8f0b833f8534..452832f26aa7 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -87,6 +87,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in provides a mechanism to present the choices and load the chosen configuration). + It will raise :exc:`FileNotFoundError` if the file + doesn't exist and :exc:`ValueError` if the file is invalid or + empty. + :param fname: A filename, or a file-like object, or an instance derived from :class:`~configparser.RawConfigParser`. If a ``RawConfigParser``-derived instance is passed, it is used as @@ -126,6 +130,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in .. versionadded:: 3.10 The *encoding* parameter is added. + .. versionadded:: 3.12 + An exception will be thrown if the provided file + doesn't exist or is invalid or empty. + .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None) Starts up a socket server on the specified port, and listens for new diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 16c54a6a4f7a..652f21ecb459 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -29,6 +29,7 @@ import io import logging import logging.handlers +import os import queue import re import struct @@ -60,15 +61,24 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non """ import configparser + if isinstance(fname, str): + if not os.path.exists(fname): + raise FileNotFoundError(f"{fname} doesn't exist") + elif not os.path.getsize(fname): + raise ValueError(f'{fname} is an empty file') + if isinstance(fname, configparser.RawConfigParser): cp = fname else: - cp = configparser.ConfigParser(defaults) - if hasattr(fname, 'readline'): - cp.read_file(fname) - else: - encoding = io.text_encoding(encoding) - cp.read(fname, encoding=encoding) + try: + cp = configparser.ConfigParser(defaults) + if hasattr(fname, 'readline'): + cp.read_file(fname) + else: + encoding = io.text_encoding(encoding) + cp.read(fname, encoding=encoding) + except configparser.ParsingError as e: + raise ValueError(f'{fname} is invalid: {e}') formatters = _create_formatters(cp) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 9176d8eeb56d..ba836a7d9ea3 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1756,6 +1756,42 @@ def test_config_set_handler_names(self): self.apply_config(test_config) self.assertEqual(logging.getLogger().handlers[0].name, 'hand1') + def test_exception_if_confg_file_is_invalid(self): + test_config = """ + [loggers] + keys=root + + [handlers] + keys=hand1 + + [formatters] + keys=form1 + + [logger_root] + handlers=hand1 + + [handler_hand1] + class=StreamHandler + formatter=form1 + + [formatter_form1] + format=%(levelname)s ++ %(message)s + + prince + """ + + file = io.StringIO(textwrap.dedent(test_config)) + self.assertRaises(ValueError, logging.config.fileConfig, file) + + def test_exception_if_confg_file_is_empty(self): + fd, fn = tempfile.mkstemp(prefix='test_empty_', suffix='.ini') + os.close(fd) + self.assertRaises(ValueError, logging.config.fileConfig, fn) + os.remove(fn) + + def test_exception_if_config_file_does_not_exist(self): + self.assertRaises(FileNotFoundError, logging.config.fileConfig, 'filenotfound') + def test_defaults_do_no_interpolation(self): """bpo-33802 defaults should not get interpolated""" ini = textwrap.dedent(""" From webhook-mailer at python.org Thu May 18 01:22:25 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 18 May 2023 05:22:25 -0000 Subject: [Python-checkins] gh-104374: Remove access to class scopes for inlined comprehensions (#104528) Message-ID: <mailman.425.1684387346.13550.python-checkins@python.org> https://github.com/python/cpython/commit/662aede68b0ea222cf3db4715b310e91c51b665f commit: 662aede68b0ea222cf3db4715b310e91c51b665f branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-18T05:22:17Z summary: gh-104374: Remove access to class scopes for inlined comprehensions (#104528) Co-authored-by: Carl Meyer <carl at oddbird.net> files: M Lib/test/test_listcomps.py M Python/compile.c M Python/symtable.c diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 23e1b8c1ce31..985274dfd6cb 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -200,7 +200,8 @@ def f(): y = [g for x in [1]] """ outputs = {"y": [2]} - self._check_in_scopes(code, outputs) + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + self._check_in_scopes(code, scopes=["class"], raises=NameError) def test_inner_cell_shadows_outer_redefined(self): code = """ @@ -328,7 +329,8 @@ def test_nested_2(self): y = [x for [x ** x for x in range(x)][x - 1] in l] """ outputs = {"y": [3, 3, 3]} - self._check_in_scopes(code, outputs) + self._check_in_scopes(code, outputs, scopes=["module", "function"]) + self._check_in_scopes(code, scopes=["class"], raises=NameError) def test_nested_3(self): code = """ @@ -379,6 +381,109 @@ def f(): with self.assertRaises(UnboundLocalError): f() + def test_name_error_in_class_scope(self): + code = """ + y = 1 + [x + y for x in range(2)] + """ + self._check_in_scopes(code, raises=NameError, scopes=["class"]) + + def test_global_in_class_scope(self): + code = """ + y = 2 + vals = [(x, y) for x in range(2)] + """ + outputs = {"vals": [(0, 1), (1, 1)]} + self._check_in_scopes(code, outputs, ns={"y": 1}, scopes=["class"]) + + def test_in_class_scope_inside_function_1(self): + code = """ + class C: + y = 2 + vals = [(x, y) for x in range(2)] + vals = C.vals + """ + outputs = {"vals": [(0, 1), (1, 1)]} + self._check_in_scopes(code, outputs, ns={"y": 1}, scopes=["function"]) + + def test_in_class_scope_inside_function_2(self): + code = """ + y = 1 + class C: + y = 2 + vals = [(x, y) for x in range(2)] + vals = C.vals + """ + outputs = {"vals": [(0, 1), (1, 1)]} + self._check_in_scopes(code, outputs, scopes=["function"]) + + def test_in_class_scope_with_global(self): + code = """ + y = 1 + class C: + global y + y = 2 + # Ensure the listcomp uses the global, not the value in the + # class namespace + locals()['y'] = 3 + vals = [(x, y) for x in range(2)] + vals = C.vals + """ + outputs = {"vals": [(0, 2), (1, 2)]} + self._check_in_scopes(code, outputs, scopes=["module", "class"]) + outputs = {"vals": [(0, 1), (1, 1)]} + self._check_in_scopes(code, outputs, scopes=["function"]) + + def test_in_class_scope_with_nonlocal(self): + code = """ + y = 1 + class C: + nonlocal y + y = 2 + # Ensure the listcomp uses the global, not the value in the + # class namespace + locals()['y'] = 3 + vals = [(x, y) for x in range(2)] + vals = C.vals + """ + outputs = {"vals": [(0, 2), (1, 2)]} + self._check_in_scopes(code, outputs, scopes=["function"]) + + def test_nested_has_free_var(self): + code = """ + items = [a for a in [1] if [a for _ in [0]]] + """ + outputs = {"items": [1]} + self._check_in_scopes(code, outputs, scopes=["class"]) + + def test_nested_free_var_not_bound_in_outer_comp(self): + code = """ + z = 1 + items = [a for a in [1] if [x for x in [1] if z]] + """ + self._check_in_scopes(code, {"items": [1]}, scopes=["module", "function"]) + self._check_in_scopes(code, {"items": []}, ns={"z": 0}, scopes=["class"]) + + def test_nested_free_var_in_iter(self): + code = """ + items = [_C for _C in [1] for [0, 1][[x for x in [1] if _C][0]] in [2]] + """ + self._check_in_scopes(code, {"items": [1]}) + + def test_nested_free_var_in_expr(self): + code = """ + items = [(_C, [x for x in [1] if _C]) for _C in [0, 1]] + """ + self._check_in_scopes(code, {"items": [(0, []), (1, [1])]}) + + def test_nested_listcomp_in_lambda(self): + code = """ + f = [(z, lambda y: [(x, y, z) for x in [3]]) for z in [1]] + (z, func), = f + out = func(2) + """ + self._check_in_scopes(code, {"z": 1, "out": [(3, 2, 1)]}) + __test__ = {'doctests' : doctests} diff --git a/Python/compile.c b/Python/compile.c index 60c845a821b6..07f8d6684770 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -388,6 +388,8 @@ struct compiler_unit { instr_sequence u_instr_sequence; /* codegen output */ int u_nfblocks; + int u_in_inlined_comp; + struct fblockinfo u_fblock[CO_MAXBLOCKS]; _PyCompile_CodeUnitMetadata u_metadata; @@ -1290,6 +1292,7 @@ compiler_enter_scope(struct compiler *c, identifier name, } u->u_nfblocks = 0; + u->u_in_inlined_comp = 0; u->u_metadata.u_firstlineno = lineno; u->u_metadata.u_consts = PyDict_New(); if (!u->u_metadata.u_consts) { @@ -4137,7 +4140,7 @@ compiler_nameop(struct compiler *c, location loc, case OP_DEREF: switch (ctx) { case Load: - if (c->u->u_ste->ste_type == ClassBlock) { + if (c->u->u_ste->ste_type == ClassBlock && !c->u->u_in_inlined_comp) { op = LOAD_FROM_DICT_OR_DEREF; // First load the locals if (codegen_addop_noarg(INSTR_SEQUENCE(c), LOAD_LOCALS, loc) < 0) { @@ -4188,7 +4191,12 @@ compiler_nameop(struct compiler *c, location loc, break; case OP_NAME: switch (ctx) { - case Load: op = LOAD_NAME; break; + case Load: + op = (c->u->u_ste->ste_type == ClassBlock + && c->u->u_in_inlined_comp) + ? LOAD_GLOBAL + : LOAD_NAME; + break; case Store: op = STORE_NAME; break; case Del: op = DELETE_NAME; break; } @@ -5415,6 +5423,8 @@ push_inlined_comprehension_state(struct compiler *c, location loc, PySTEntryObject *entry, inlined_comprehension_state *state) { + int in_class_block = (c->u->u_ste->ste_type == ClassBlock) && !c->u->u_in_inlined_comp; + c->u->u_in_inlined_comp++; // iterate over names bound in the comprehension and ensure we isolate // them from the outer scope as needed PyObject *k, *v; @@ -5426,7 +5436,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc, // at all; DEF_LOCAL | DEF_NONLOCAL can occur in the case of an // assignment expression to a nonlocal in the comprehension, these don't // need handling here since they shouldn't be isolated - if (symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) { + if ((symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) || in_class_block) { if (!_PyST_IsFunctionLike(c->u->u_ste)) { // non-function scope: override this name to use fast locals PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k); @@ -5448,8 +5458,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc, long scope = (symbol >> SCOPE_OFFSET) & SCOPE_MASK; PyObject *outv = PyDict_GetItemWithError(c->u->u_ste->ste_symbols, k); if (outv == NULL) { - assert(PyErr_Occurred()); - return ERROR; + outv = _PyLong_GetZero(); } assert(PyLong_Check(outv)); long outsc = (PyLong_AS_LONG(outv) >> SCOPE_OFFSET) & SCOPE_MASK; @@ -5523,6 +5532,7 @@ static int pop_inlined_comprehension_state(struct compiler *c, location loc, inlined_comprehension_state state) { + c->u->u_in_inlined_comp--; PyObject *k, *v; Py_ssize_t pos = 0; if (state.temp_symbols) { diff --git a/Python/symtable.c b/Python/symtable.c index f896f7cbe338..a319c239d99b 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -674,8 +674,9 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, } // free vars in comprehension that are locals in outer scope can - // now simply be locals, unless they are free in comp children - if (!is_free_in_any_child(comp, k)) { + // now simply be locals, unless they are free in comp children, + // or if the outer scope is a class block + if (!is_free_in_any_child(comp, k) && ste->ste_type != ClassBlock) { if (PySet_Discard(comp_free, k) < 0) { return 0; } From webhook-mailer at python.org Thu May 18 05:09:15 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 18 May 2023 09:09:15 -0000 Subject: [Python-checkins] GH-104580: Don't cache eval breaker in interpreter (GH-104581) Message-ID: <mailman.426.1684400957.13550.python-checkins@python.org> https://github.com/python/cpython/commit/68b5f08b72e02f62ec787bfbb7aa99bac661daec commit: 68b5f08b72e02f62ec787bfbb7aa99bac661daec branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-18T10:08:33+01:00 summary: GH-104580: Don't cache eval breaker in interpreter (GH-104581) Move eval-breaker to the front of the interpreter state. files: M Include/internal/pycore_ceval_state.h M Include/internal/pycore_interp.h M Python/bytecodes.c M Python/ceval.c M Python/ceval_macros.h M Python/generated_cases.c.h diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index b352801673c4..95d1fa16ba40 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -81,14 +81,14 @@ struct _pending_calls { }; struct _ceval_state { - int recursion_limit; - struct _gil_runtime_state *gil; - int own_gil; /* This single variable consolidates all requests to break out of the fast path in the eval loop. */ _Py_atomic_int eval_breaker; /* Request for dropping the GIL */ _Py_atomic_int gil_drop_request; + int recursion_limit; + struct _gil_runtime_state *gil; + int own_gil; /* The GC is ready to be executed */ _Py_atomic_int gc_scheduled; struct _pending_calls pending; diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index edc076fc04f6..04474c1da885 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -48,6 +48,7 @@ struct _Py_long_state { */ struct _is { + struct _ceval_state ceval; PyInterpreterState *next; uint64_t monitoring_version; @@ -92,7 +93,6 @@ struct _is { struct _obmalloc_state obmalloc; - struct _ceval_state ceval; struct _gc_runtime_state gc; struct _import_state imports; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e92c5d8b6f3b..f71a62e051a3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -70,7 +70,6 @@ dummy_func( _PyInterpreterFrame *frame, unsigned char opcode, unsigned int oparg, - _Py_atomic_int * const eval_breaker, _PyCFrame cframe, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, @@ -143,7 +142,7 @@ dummy_func( ERROR_IF(err, error); next_instr--; } - else if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } @@ -170,7 +169,7 @@ dummy_func( next_instr = frame->prev_instr; DISPATCH(); } - if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } diff --git a/Python/ceval.c b/Python/ceval.c index e8534ec6598e..df997e1ed283 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -652,7 +652,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int // for the big switch below (in combination with the EXTRA_CASES macro). uint8_t opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ - _Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker; #ifdef LLTRACE int lltrace = 0; #endif diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index e92ff0bd6fba..fccf9088cbd1 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -116,7 +116,7 @@ #define CHECK_EVAL_BREAKER() \ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \ - if (_Py_atomic_load_relaxed_int32(eval_breaker)) { \ + if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { \ goto handle_eval_breaker; \ } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 32fe7bcef428..055fb5a0611b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 138 "Python/bytecodes.c" + #line 137 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -17,7 +17,7 @@ if (err) goto error; next_instr--; } - else if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } #line 24 "Python/generated_cases.c.h" @@ -25,7 +25,7 @@ } TARGET(INSTRUMENTED_RESUME) { - #line 152 "Python/bytecodes.c" + #line 151 "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? @@ -47,7 +47,7 @@ next_instr = frame->prev_instr; DISPATCH(); } - if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { goto handle_eval_breaker; } } @@ -57,7 +57,7 @@ TARGET(LOAD_CLOSURE) { PyObject *value; - #line 180 "Python/bytecodes.c" + #line 179 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; @@ -70,7 +70,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 187 "Python/bytecodes.c" + #line 186 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -82,7 +82,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -94,7 +94,7 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 199 "Python/bytecodes.c" + #line 198 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -107,7 +107,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - #line 205 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 114 "Python/generated_cases.c.h" @@ -118,7 +118,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 210 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 124 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -130,7 +130,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -140,7 +140,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -158,7 +158,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -168,7 +168,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 205 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 175 "Python/generated_cases.c.h" @@ -184,14 +184,14 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; - #line 210 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 190 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -207,14 +207,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 210 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 213 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; - #line 210 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 220 "Python/generated_cases.c.h" } @@ -227,7 +227,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 205 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 234 "Python/generated_cases.c.h" @@ -236,7 +236,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -251,7 +251,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 220 "Python/bytecodes.c" + #line 219 "Python/bytecodes.c" #line 256 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -260,7 +260,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 224 "Python/bytecodes.c" + #line 223 "Python/bytecodes.c" res = NULL; #line 266 "Python/generated_cases.c.h" STACK_GROW(1); @@ -273,13 +273,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 220 "Python/bytecodes.c" + #line 219 "Python/bytecodes.c" #line 278 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 220 "Python/bytecodes.c" + #line 219 "Python/bytecodes.c" #line 284 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -290,7 +290,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 230 "Python/bytecodes.c" + #line 229 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -310,7 +310,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 243 "Python/bytecodes.c" + #line 242 "Python/bytecodes.c" Py_DECREF(receiver); #line 316 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -321,7 +321,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 247 "Python/bytecodes.c" + #line 246 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -339,11 +339,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 258 "Python/bytecodes.c" + #line 257 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 345 "Python/generated_cases.c.h" Py_DECREF(value); - #line 260 "Python/bytecodes.c" + #line 259 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 349 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -353,11 +353,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 264 "Python/bytecodes.c" + #line 263 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 359 "Python/generated_cases.c.h" Py_DECREF(value); - #line 266 "Python/bytecodes.c" + #line 265 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -373,11 +373,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 276 "Python/bytecodes.c" + #line 275 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 379 "Python/generated_cases.c.h" Py_DECREF(value); - #line 278 "Python/bytecodes.c" + #line 277 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 383 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -388,7 +388,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 295 "Python/bytecodes.c" + #line 294 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -407,7 +407,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 305 "Python/bytecodes.c" + #line 304 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -425,7 +425,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 314 "Python/bytecodes.c" + #line 313 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -444,7 +444,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 324 "Python/bytecodes.c" + #line 323 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); @@ -461,7 +461,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 332 "Python/bytecodes.c" + #line 331 "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); @@ -479,7 +479,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 348 "Python/bytecodes.c" + #line 347 "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]; @@ -515,7 +515,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 377 "Python/bytecodes.c" + #line 376 "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); @@ -533,7 +533,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 386 "Python/bytecodes.c" + #line 385 "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); @@ -554,7 +554,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 404 "Python/bytecodes.c" + #line 403 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -569,7 +569,7 @@ #line 570 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 416 "Python/bytecodes.c" + #line 415 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 575 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -583,7 +583,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 420 "Python/bytecodes.c" + #line 419 "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. @@ -607,7 +607,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 435 "Python/bytecodes.c" + #line 434 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -629,7 +629,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 450 "Python/bytecodes.c" + #line 449 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -654,7 +654,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 466 "Python/bytecodes.c" + #line 465 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -679,7 +679,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 482 "Python/bytecodes.c" + #line 481 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -690,7 +690,7 @@ #line 691 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 490 "Python/bytecodes.c" + #line 489 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -706,7 +706,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 497 "Python/bytecodes.c" + #line 496 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -735,7 +735,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 522 "Python/bytecodes.c" + #line 521 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 741 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -746,11 +746,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 527 "Python/bytecodes.c" + #line 526 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 752 "Python/generated_cases.c.h" Py_DECREF(v); - #line 529 "Python/bytecodes.c" + #line 528 "Python/bytecodes.c" if (err) goto pop_1_error; #line 756 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -765,7 +765,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 540 "Python/bytecodes.c" + #line 539 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -784,7 +784,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 555 "Python/bytecodes.c" + #line 554 "Python/bytecodes.c" if (err) goto pop_3_error; #line 790 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -796,7 +796,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 559 "Python/bytecodes.c" + #line 558 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -823,7 +823,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 578 "Python/bytecodes.c" + #line 577 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -838,13 +838,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 586 "Python/bytecodes.c" + #line 585 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 845 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 589 "Python/bytecodes.c" + #line 588 "Python/bytecodes.c" if (err) goto pop_2_error; #line 850 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -854,12 +854,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 593 "Python/bytecodes.c" + #line 592 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 861 "Python/generated_cases.c.h" Py_DECREF(value); - #line 596 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 865 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -870,13 +870,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 600 "Python/bytecodes.c" + #line 599 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 877 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 603 "Python/bytecodes.c" + #line 602 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 882 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -886,7 +886,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 607 "Python/bytecodes.c" + #line 606 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -909,7 +909,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 627 "Python/bytecodes.c" + #line 626 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -925,7 +925,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 640 "Python/bytecodes.c" + #line 639 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -943,7 +943,7 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 655 "Python/bytecodes.c" + #line 654 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -964,7 +964,7 @@ } TARGET(RETURN_CONST) { - #line 674 "Python/bytecodes.c" + #line 673 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -982,7 +982,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 690 "Python/bytecodes.c" + #line 689 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1006,7 +1006,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 710 "Python/bytecodes.c" + #line 709 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1021,14 +1021,14 @@ type->tp_name); #line 1023 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 723 "Python/bytecodes.c" + #line 722 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1030 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 728 "Python/bytecodes.c" + #line 727 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1049,7 +1049,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 743 "Python/bytecodes.c" + #line 742 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1104,7 +1104,7 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 790 "Python/bytecodes.c" + #line 789 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -1113,7 +1113,7 @@ #line 1115 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 797 "Python/bytecodes.c" + #line 796 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1143,7 +1143,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 823 "Python/bytecodes.c" + #line 822 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1199,7 +1199,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 872 "Python/bytecodes.c" + #line 871 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1220,7 +1220,7 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 890 "Python/bytecodes.c" + #line 889 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1242,7 +1242,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 909 "Python/bytecodes.c" + #line 908 "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. @@ -1263,7 +1263,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 927 "Python/bytecodes.c" + #line 926 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1270 "Python/generated_cases.c.h" @@ -1274,7 +1274,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 932 "Python/bytecodes.c" + #line 931 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1298,13 +1298,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 952 "Python/bytecodes.c" + #line 951 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1305 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 955 "Python/bytecodes.c" + #line 954 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1322,7 +1322,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 964 "Python/bytecodes.c" + #line 963 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1331,7 +1331,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 969 "Python/bytecodes.c" + #line 968 "Python/bytecodes.c" none = Py_None; } else { @@ -1347,7 +1347,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 978 "Python/bytecodes.c" + #line 977 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1353 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1357,7 +1357,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 982 "Python/bytecodes.c" + #line 981 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1387,7 +1387,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1007 "Python/bytecodes.c" + #line 1006 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1396,7 +1396,7 @@ "no locals found when storing %R", name); #line 1398 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1014 "Python/bytecodes.c" + #line 1013 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1405,7 +1405,7 @@ err = PyObject_SetItem(ns, name, v); #line 1407 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1021 "Python/bytecodes.c" + #line 1020 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1411 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1413,7 +1413,7 @@ } TARGET(DELETE_NAME) { - #line 1025 "Python/bytecodes.c" + #line 1024 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1438,7 +1438,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1051 "Python/bytecodes.c" + #line 1050 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1453,7 +1453,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1455 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1064 "Python/bytecodes.c" + #line 1063 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1459 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1465,7 +1465,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1068 "Python/bytecodes.c" + #line 1067 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1483,7 +1483,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1078 "Python/bytecodes.c" + #line 1077 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1502,7 +1502,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1089 "Python/bytecodes.c" + #line 1088 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1520,13 +1520,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1100 "Python/bytecodes.c" + #line 1099 "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 1528 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1104 "Python/bytecodes.c" + #line 1103 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1532 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1539,7 +1539,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1115 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1558,7 +1558,7 @@ #line 1559 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1131 "Python/bytecodes.c" + #line 1130 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1564 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1568,12 +1568,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1135 "Python/bytecodes.c" + #line 1134 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1575 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1138 "Python/bytecodes.c" + #line 1137 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1579 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1582,12 +1582,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1142 "Python/bytecodes.c" + #line 1141 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1589 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1145 "Python/bytecodes.c" + #line 1144 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1593 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1595,7 +1595,7 @@ } TARGET(DELETE_GLOBAL) { - #line 1149 "Python/bytecodes.c" + #line 1148 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1615,7 +1615,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1163 "Python/bytecodes.c" + #line 1162 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1635,7 +1635,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1163 "Python/bytecodes.c" + #line 1162 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1649,7 +1649,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1175 "Python/bytecodes.c" + #line 1174 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1719,7 +1719,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1175 "Python/bytecodes.c" + #line 1174 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1788,7 +1788,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1244 "Python/bytecodes.c" + #line 1243 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1854,7 +1854,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1298 "Python/bytecodes.c" + #line 1297 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1880,7 +1880,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 1311 "Python/bytecodes.c" + #line 1310 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1905,7 +1905,7 @@ } TARGET(DELETE_FAST) { - #line 1328 "Python/bytecodes.c" + #line 1327 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -1914,7 +1914,7 @@ } TARGET(MAKE_CELL) { - #line 1334 "Python/bytecodes.c" + #line 1333 "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); @@ -1928,7 +1928,7 @@ } TARGET(DELETE_DEREF) { - #line 1345 "Python/bytecodes.c" + #line 1344 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1946,7 +1946,7 @@ TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1358 "Python/bytecodes.c" + #line 1357 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1988,7 +1988,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1395 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2004,7 +2004,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1405 "Python/bytecodes.c" + #line 1404 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -2015,7 +2015,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1412 "Python/bytecodes.c" + #line 1411 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2033,13 +2033,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1425 "Python/bytecodes.c" + #line 1424 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 2039 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1427 "Python/bytecodes.c" + #line 1426 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 2045 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2051,7 +2051,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1431 "Python/bytecodes.c" + #line 1430 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 2058 "Python/generated_cases.c.h" @@ -2064,7 +2064,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1436 "Python/bytecodes.c" + #line 1435 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 2071 "Python/generated_cases.c.h" @@ -2077,7 +2077,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1441 "Python/bytecodes.c" + #line 1440 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2090,7 +2090,7 @@ } #line 2092 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1452 "Python/bytecodes.c" + #line 1451 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -2103,11 +2103,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1459 "Python/bytecodes.c" + #line 1458 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 2109 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1461 "Python/bytecodes.c" + #line 1460 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 2113 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2117,7 +2117,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1465 "Python/bytecodes.c" + #line 1464 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2142,7 +2142,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1482 "Python/bytecodes.c" + #line 1481 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2154,7 +2154,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1490 "Python/bytecodes.c" + #line 1489 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 2160 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -2164,7 +2164,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1494 "Python/bytecodes.c" + #line 1493 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2212,7 +2212,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1536 "Python/bytecodes.c" + #line 1535 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2227,7 +2227,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1546 "Python/bytecodes.c" + #line 1545 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 2233 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2237,7 +2237,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1550 "Python/bytecodes.c" + #line 1549 "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)) { @@ -2247,7 +2247,7 @@ } #line 2249 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1558 "Python/bytecodes.c" + #line 1557 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2254 "Python/generated_cases.c.h" @@ -2258,14 +2258,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1564 "Python/bytecodes.c" + #line 1563 "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 2267 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1569 "Python/bytecodes.c" + #line 1568 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2272 "Python/generated_cases.c.h" @@ -2278,7 +2278,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1576 "Python/bytecodes.c" + #line 1575 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2291,7 +2291,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1585 "Python/bytecodes.c" + #line 1584 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -2308,7 +2308,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1599 "Python/bytecodes.c" + #line 1598 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2354,7 +2354,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1641 "Python/bytecodes.c" + #line 1640 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); @@ -2374,7 +2374,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1648 "Python/bytecodes.c" + #line 1647 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2385,7 +2385,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1655 "Python/bytecodes.c" + #line 1654 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 2391 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -2402,7 +2402,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1659 "Python/bytecodes.c" + #line 1658 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2437,7 +2437,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1696 "Python/bytecodes.c" + #line 1695 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2473,7 +2473,7 @@ */ #line 2475 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1730 "Python/bytecodes.c" + #line 1729 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2484,7 +2484,7 @@ res = PyObject_GetAttr(owner, name); #line 2486 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1739 "Python/bytecodes.c" + #line 1738 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2491 "Python/generated_cases.c.h" @@ -2501,7 +2501,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1744 "Python/bytecodes.c" + #line 1743 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2529,7 +2529,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1760 "Python/bytecodes.c" + #line 1759 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2557,7 +2557,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1776 "Python/bytecodes.c" + #line 1775 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2599,7 +2599,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1806 "Python/bytecodes.c" + #line 1805 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2624,7 +2624,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1819 "Python/bytecodes.c" + #line 1818 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2650,7 +2650,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 1834 "Python/bytecodes.c" + #line 1833 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2682,7 +2682,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 1860 "Python/bytecodes.c" + #line 1859 "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); @@ -2716,7 +2716,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 1888 "Python/bytecodes.c" + #line 1887 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2745,7 +2745,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 1908 "Python/bytecodes.c" + #line 1907 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2795,7 +2795,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 1949 "Python/bytecodes.c" + #line 1948 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2817,7 +2817,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1968 "Python/bytecodes.c" + #line 1967 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2833,7 +2833,7 @@ #line 2834 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1981 "Python/bytecodes.c" + #line 1980 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2839 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2846,7 +2846,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1985 "Python/bytecodes.c" + #line 1984 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2868,7 +2868,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1999 "Python/bytecodes.c" + #line 1998 "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); @@ -2894,7 +2894,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2017 "Python/bytecodes.c" + #line 2016 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2917,12 +2917,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2031 "Python/bytecodes.c" + #line 2030 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2923 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2033 "Python/bytecodes.c" + #line 2032 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2934,12 +2934,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2037 "Python/bytecodes.c" + #line 2036 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2940 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2039 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 2946 "Python/generated_cases.c.h" @@ -2953,12 +2953,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2044 "Python/bytecodes.c" + #line 2043 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2959 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2046 "Python/bytecodes.c" + #line 2045 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2969,7 +2969,7 @@ #line 2970 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2054 "Python/bytecodes.c" + #line 2053 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2988,19 +2988,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2065 "Python/bytecodes.c" + #line 2064 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 2995 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2068 "Python/bytecodes.c" + #line 2067 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3002 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2073 "Python/bytecodes.c" + #line 2072 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3006 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -3011,13 +3011,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2077 "Python/bytecodes.c" + #line 2076 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3018 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2080 "Python/bytecodes.c" + #line 2079 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3023 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3028,7 +3028,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2084 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -3039,7 +3039,7 @@ } TARGET(JUMP_FORWARD) { - #line 2090 "Python/bytecodes.c" + #line 2089 "Python/bytecodes.c" JUMPBY(oparg); #line 3045 "Python/generated_cases.c.h" DISPATCH(); @@ -3047,7 +3047,7 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 2094 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); #line 3054 "Python/generated_cases.c.h" @@ -3058,7 +3058,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 2100 "Python/bytecodes.c" + #line 2099 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } @@ -3066,7 +3066,7 @@ int err = PyObject_IsTrue(cond); #line 3068 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2106 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3081,7 +3081,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2116 "Python/bytecodes.c" + #line 2115 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } @@ -3089,7 +3089,7 @@ int err = PyObject_IsTrue(cond); #line 3091 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2122 "Python/bytecodes.c" + #line 2121 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3104,11 +3104,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2132 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3110 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2134 "Python/bytecodes.c" + #line 2133 "Python/bytecodes.c" JUMPBY(oparg); } #line 3115 "Python/generated_cases.c.h" @@ -3118,14 +3118,14 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2139 "Python/bytecodes.c" + #line 2138 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3127 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2144 "Python/bytecodes.c" + #line 2143 "Python/bytecodes.c" } #line 3131 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3133,7 +3133,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2148 "Python/bytecodes.c" + #line 2147 "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. @@ -3147,7 +3147,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2157 "Python/bytecodes.c" + #line 2156 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -3164,7 +3164,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2165 "Python/bytecodes.c" + #line 2164 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -3173,7 +3173,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2170 "Python/bytecodes.c" + #line 2169 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3190,7 +3190,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2180 "Python/bytecodes.c" + #line 2179 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3197 "Python/generated_cases.c.h" @@ -3203,7 +3203,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2186 "Python/bytecodes.c" + #line 2185 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3210 "Python/generated_cases.c.h" @@ -3217,7 +3217,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2192 "Python/bytecodes.c" + #line 2191 "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; @@ -3230,12 +3230,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2198 "Python/bytecodes.c" + #line 2197 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3237 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2201 "Python/bytecodes.c" + #line 2200 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3241 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3245,7 +3245,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2205 "Python/bytecodes.c" + #line 2204 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3270,7 +3270,7 @@ } #line 3272 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2228 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" } #line 3276 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3283,7 +3283,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2247 "Python/bytecodes.c" + #line 2246 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3322,7 +3322,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2280 "Python/bytecodes.c" + #line 2279 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3355,7 +3355,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2308 "Python/bytecodes.c" + #line 2307 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3385,7 +3385,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2330 "Python/bytecodes.c" + #line 2329 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3415,7 +3415,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2352 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3442,7 +3442,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2372 "Python/bytecodes.c" + #line 2371 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3465,7 +3465,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2390 "Python/bytecodes.c" + #line 2389 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3490,7 +3490,7 @@ } #line 3492 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2413 "Python/bytecodes.c" + #line 2412 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3509,7 +3509,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2423 "Python/bytecodes.c" + #line 2422 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3537,7 +3537,7 @@ } #line 3539 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2449 "Python/bytecodes.c" + #line 2448 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3556,7 +3556,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2458 "Python/bytecodes.c" + #line 2457 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3586,7 +3586,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2481 "Python/bytecodes.c" + #line 2480 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3610,7 +3610,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 2493 "Python/bytecodes.c" + #line 2492 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3641,7 +3641,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2512 "Python/bytecodes.c" + #line 2511 "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); @@ -3665,7 +3665,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2524 "Python/bytecodes.c" + #line 2523 "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; @@ -3688,7 +3688,7 @@ } TARGET(KW_NAMES) { - #line 2540 "Python/bytecodes.c" + #line 2539 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); @@ -3697,7 +3697,7 @@ } TARGET(INSTRUMENTED_CALL) { - #line 2546 "Python/bytecodes.c" + #line 2545 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3720,7 +3720,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2591 "Python/bytecodes.c" + #line 2590 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3814,7 +3814,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2679 "Python/bytecodes.c" + #line 2678 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3833,7 +3833,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2691 "Python/bytecodes.c" + #line 2690 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3867,7 +3867,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2719 "Python/bytecodes.c" + #line 2718 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3911,7 +3911,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2757 "Python/bytecodes.c" + #line 2756 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3934,7 +3934,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2769 "Python/bytecodes.c" + #line 2768 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3959,7 +3959,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2783 "Python/bytecodes.c" + #line 2782 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3984,7 +3984,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2797 "Python/bytecodes.c" + #line 2796 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4020,7 +4020,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2822 "Python/bytecodes.c" + #line 2821 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4062,7 +4062,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2853 "Python/bytecodes.c" + #line 2852 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4108,7 +4108,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2888 "Python/bytecodes.c" + #line 2887 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4154,7 +4154,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2923 "Python/bytecodes.c" + #line 2922 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4192,7 +4192,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2950 "Python/bytecodes.c" + #line 2949 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4231,7 +4231,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2980 "Python/bytecodes.c" + #line 2979 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4256,7 +4256,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3000 "Python/bytecodes.c" + #line 2999 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4300,7 +4300,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3034 "Python/bytecodes.c" + #line 3033 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4342,7 +4342,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3066 "Python/bytecodes.c" + #line 3065 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4384,7 +4384,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3098 "Python/bytecodes.c" + #line 3097 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4422,7 +4422,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3129 "Python/bytecodes.c" + #line 3128 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4428 "Python/generated_cases.c.h" } @@ -4433,7 +4433,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3133 "Python/bytecodes.c" + #line 3132 "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)); @@ -4499,7 +4499,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3195 "Python/bytecodes.c" + #line 3194 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4506 "Python/generated_cases.c.h" @@ -4517,7 +4517,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 3205 "Python/bytecodes.c" + #line 3204 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4553,7 +4553,7 @@ } TARGET(RETURN_GENERATOR) { - #line 3236 "Python/bytecodes.c" + #line 3235 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4582,13 +4582,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3259 "Python/bytecodes.c" + #line 3258 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4588 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3261 "Python/bytecodes.c" + #line 3260 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4594 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4601,7 +4601,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 3265 "Python/bytecodes.c" + #line 3264 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4645,7 +4645,7 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3302 "Python/bytecodes.c" + #line 3301 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4652 "Python/generated_cases.c.h" @@ -4660,7 +4660,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3307 "Python/bytecodes.c" + #line 3306 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4678,7 +4678,7 @@ #line 4679 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3322 "Python/bytecodes.c" + #line 3321 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4684 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -4690,7 +4690,7 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3327 "Python/bytecodes.c" + #line 3326 "Python/bytecodes.c" assert(oparg >= 2); #line 4696 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; @@ -4699,7 +4699,7 @@ } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3331 "Python/bytecodes.c" + #line 3330 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4715,14 +4715,14 @@ } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3345 "Python/bytecodes.c" + #line 3344 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); #line 4721 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3349 "Python/bytecodes.c" + #line 3348 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP); #line 4728 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); @@ -4730,7 +4730,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3354 "Python/bytecodes.c" + #line 3353 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4744,7 +4744,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3365 "Python/bytecodes.c" + #line 3364 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4758,7 +4758,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3376 "Python/bytecodes.c" + #line 3375 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4775,7 +4775,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3390 "Python/bytecodes.c" + #line 3389 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4792,7 +4792,7 @@ } TARGET(EXTENDED_ARG) { - #line 3404 "Python/bytecodes.c" + #line 3403 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; @@ -4802,14 +4802,14 @@ } TARGET(CACHE) { - #line 3412 "Python/bytecodes.c" + #line 3411 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); #line 4809 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3417 "Python/bytecodes.c" + #line 3416 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); #line 4816 "Python/generated_cases.c.h" From webhook-mailer at python.org Thu May 18 05:10:24 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 18 May 2023 09:10:24 -0000 Subject: [Python-checkins] GH-96803: Document and test new unstable internal frame API functions (GH-104211) Message-ID: <mailman.427.1684401024.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cfa517d5a68bae24cbe8d9fe6b8e0d4935e507d2 commit: cfa517d5a68bae24cbe8d9fe6b8e0d4935e507d2 branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-18T10:10:15+01:00 summary: GH-96803: Document and test new unstable internal frame API functions (GH-104211) Weaken contract of PyUnstable_InterpreterFrame_GetCode to return PyObject*. files: M Doc/c-api/frame.rst M Include/cpython/frameobject.h M Lib/test/test_capi/test_misc.py M Modules/_testinternalcapi.c M Python/frame.c diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst index 1ac8f03d6e48..9f7addfbbf3c 100644 --- a/Doc/c-api/frame.rst +++ b/Doc/c-api/frame.rst @@ -130,3 +130,38 @@ See also :ref:`Reflection <reflection>`. .. c:function:: int PyFrame_GetLineNumber(PyFrameObject *frame) Return the line number that *frame* is currently executing. + + + +Internal Frames +--------------- + +Unless using :pep:`523`, you will not need this. + +.. c:struct:: _PyInterpreterFrame + + The interpreter's internal frame representation. + + .. versionadded:: 3.11 + +.. c:function:: PyObject* PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); + + Return a :term:`strong reference` to the code object for the frame. + + .. versionadded:: 3.12 + + +.. c:function:: int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame); + + Return the byte offset into the last executed instruction. + + .. versionadded:: 3.12 + + +.. c:function:: int PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame); + + Return the currently executing line number, or -1 if there is no line number. + + .. versionadded:: 3.12 + + diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h index 6f3efe36ede5..a3dc66617864 100644 --- a/Include/cpython/frameobject.h +++ b/Include/cpython/frameobject.h @@ -35,7 +35,7 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); /* Returns the code object of the frame (strong reference). * Does not raise an exception. */ -PyAPI_FUNC(PyCodeObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); +PyAPI_FUNC(PyObject *) PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame); /* Returns a byte ofsset into the last executed instruction. * Does not raise an exception. */ diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 0ef0b5d8b658..dc3441e4496a 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1744,6 +1744,30 @@ class Subclass(BaseException, self.module.StateAccessType): self.assertIs(Subclass().get_defining_module(), self.module) +class TestInternalFrameApi(unittest.TestCase): + + @staticmethod + def func(): + return sys._getframe() + + def test_code(self): + frame = self.func() + code = _testinternalcapi.iframe_getcode(frame) + self.assertIs(code, self.func.__code__) + + def test_lasti(self): + frame = self.func() + lasti = _testinternalcapi.iframe_getlasti(frame) + self.assertGreater(lasti, 0) + self.assertLess(lasti, len(self.func.__code__.co_code)) + + def test_line(self): + frame = self.func() + line = _testinternalcapi.iframe_getline(frame) + firstline = self.func.__code__.co_firstlineno + self.assertEqual(line, firstline + 2) + + SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100 class Test_Pep523API(unittest.TestCase): diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index ea9b6e72b3c9..5802f1d4ff5f 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -12,6 +12,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "frameobject.h" #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble @@ -757,6 +758,38 @@ clear_extension(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +iframe_getcode(PyObject *self, PyObject *frame) +{ + if (!PyFrame_Check(frame)) { + PyErr_SetString(PyExc_TypeError, "argument must be a frame"); + return NULL; + } + struct _PyInterpreterFrame *f = ((PyFrameObject *)frame)->f_frame; + return PyUnstable_InterpreterFrame_GetCode(f); +} + +static PyObject * +iframe_getline(PyObject *self, PyObject *frame) +{ + if (!PyFrame_Check(frame)) { + PyErr_SetString(PyExc_TypeError, "argument must be a frame"); + return NULL; + } + struct _PyInterpreterFrame *f = ((PyFrameObject *)frame)->f_frame; + return PyLong_FromLong(PyUnstable_InterpreterFrame_GetLine(f)); +} + +static PyObject * +iframe_getlasti(PyObject *self, PyObject *frame) +{ + if (!PyFrame_Check(frame)) { + PyErr_SetString(PyExc_TypeError, "argument must be a frame"); + return NULL; + } + struct _PyInterpreterFrame *f = ((PyFrameObject *)frame)->f_frame; + return PyLong_FromLong(PyUnstable_InterpreterFrame_GetLasti(f)); +} static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, @@ -781,6 +814,9 @@ static PyMethodDef module_functions[] = { _TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF {"get_interp_settings", get_interp_settings, METH_VARARGS, NULL}, {"clear_extension", clear_extension, METH_VARARGS, NULL}, + {"iframe_getcode", iframe_getcode, METH_O, NULL}, + {"iframe_getline", iframe_getline, METH_O, NULL}, + {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Python/frame.c b/Python/frame.c index d792b92fa575..b84fd9b6a938 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -146,10 +146,10 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) /* Unstable API functions */ -PyCodeObject * +PyObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) { - PyCodeObject *code = frame->f_code; + PyObject *code = (PyObject *)frame->f_code; Py_INCREF(code); return code; } From webhook-mailer at python.org Thu May 18 13:54:51 2023 From: webhook-mailer at python.org (terryjreedy) Date: Thu, 18 May 2023 17:54:51 -0000 Subject: [Python-checkins] [3.11] gh-104499: Fix typo. (GH-104598) (#104599) Message-ID: <mailman.428.1684432492.13550.python-checkins@python.org> https://github.com/python/cpython/commit/99a162a9a9e02a40c334a7411cf0e1ed636015d7 commit: 99a162a9a9e02a40c334a7411cf0e1ed636015d7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-18T13:54:45-04:00 summary: [3.11] gh-104499: Fix typo. (GH-104598) (#104599) gh-104499: Fix typo. (GH-104598) (cherry picked from commit c5b670efd1e6dabc94b6308734d63f762480b80f) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: M Lib/idlelib/autocomplete_w.py diff --git a/Lib/idlelib/autocomplete_w.py b/Lib/idlelib/autocomplete_w.py index 5bd7ce7f5e5a..24320b5a3bff 100644 --- a/Lib/idlelib/autocomplete_w.py +++ b/Lib/idlelib/autocomplete_w.py @@ -186,7 +186,7 @@ def show_window(self, comp_lists, index, complete, mode, userWantsWin): acw.withdraw() acw.wm_overrideredirect(1) try: - # Prevent grabbing focus on maxOS. + # Prevent grabbing focus on macOS. acw.tk.call("::tk::unsupported::MacWindowStyle", "style", acw._w, "help", "noActivates") except TclError: From webhook-mailer at python.org Thu May 18 13:59:38 2023 From: webhook-mailer at python.org (barneygale) Date: Thu, 18 May 2023 17:59:38 -0000 Subject: [Python-checkins] GH-104484: Add case_sensitive argument to `pathlib.PurePath.match()` (GH-104565) Message-ID: <mailman.429.1684432779.13550.python-checkins@python.org> https://github.com/python/cpython/commit/dcdc90d384723920e8dea0ee04eae8c219333634 commit: dcdc90d384723920e8dea0ee04eae8c219333634 branch: main author: thirumurugan <67573527+thirumurugan-git at users.noreply.github.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-18T18:59:31+01:00 summary: GH-104484: Add case_sensitive argument to `pathlib.PurePath.match()` (GH-104565) Co-authored-by: Barney Gale <barney.gale at gmail.com> files: A Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst M Doc/library/pathlib.rst M Doc/whatsnew/3.12.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 93af07ae5ac1..627f2df9263d 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -546,7 +546,7 @@ Pure paths provide the following methods and properties: PureWindowsPath('c:/Program Files') -.. method:: PurePath.match(pattern) +.. method:: PurePath.match(pattern, *, case_sensitive=None) Match this path against the provided glob-style pattern. Return ``True`` if matching is successful, ``False`` otherwise. @@ -576,6 +576,11 @@ Pure paths provide the following methods and properties: >>> PureWindowsPath('b.py').match('*.PY') True + Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. + + .. versionadded:: 3.12 + The *case_sensitive* argument. + .. method:: PurePath.relative_to(other, walk_up=False) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 3e55b3fa0f47..25f0a4c3ca26 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -395,6 +395,9 @@ pathlib * Add :meth:`pathlib.Path.is_junction` as a proxy to :func:`os.path.isjunction`. (Contributed by Charles Machalow in :gh:`99547`.) +* Add *case_sensitive* optional parameter to :meth:`pathlib.Path.glob`, + :meth:`pathlib.Path.rglob` and :meth:`pathlib.PurePath.match` for matching + the path's case sensitivity, allowing for more precise control over the matching process. dis --- diff --git a/Lib/pathlib.py b/Lib/pathlib.py index ef7c47c9e775..3d68c161603d 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -86,6 +86,12 @@ def _make_selector(pattern_parts, flavour, case_sensitive): return cls(pat, child_parts, flavour, case_sensitive) + at functools.lru_cache(maxsize=256) +def _compile_pattern(pat, case_sensitive): + flags = re.NOFLAG if case_sensitive else re.IGNORECASE + return re.compile(fnmatch.translate(pat), flags).match + + class _Selector: """A selector matches a specific glob pattern part against the children of a given path.""" @@ -133,8 +139,7 @@ def __init__(self, pat, child_parts, flavour, case_sensitive): if case_sensitive is None: # TODO: evaluate case-sensitivity of each directory in _select_from() case_sensitive = _is_case_sensitive(flavour) - flags = re.NOFLAG if case_sensitive else re.IGNORECASE - self.match = re.compile(fnmatch.translate(pat), flags=flags).fullmatch + self.match = _compile_pattern(pat, case_sensitive) def _select_from(self, parent_path, scandir): try: @@ -680,22 +685,25 @@ def is_reserved(self): name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ') return name.upper() in _WIN_RESERVED_NAMES - def match(self, path_pattern): + def match(self, path_pattern, *, case_sensitive=None): """ Return True if this path matches the given pattern. """ + if case_sensitive is None: + case_sensitive = _is_case_sensitive(self._flavour) pat = self.with_segments(path_pattern) if not pat.parts: raise ValueError("empty pattern") - pat_parts = pat._parts_normcase - parts = self._parts_normcase + pat_parts = pat.parts + parts = self.parts if pat.drive or pat.root: if len(pat_parts) != len(parts): return False elif len(pat_parts) > len(parts): return False for part, pat in zip(reversed(parts), reversed(pat_parts)): - if not fnmatch.fnmatchcase(part, pat): + match = _compile_pattern(pat, case_sensitive) + if not match(part): return False return True diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 46a5248499c5..ab2c2b232a04 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -312,6 +312,11 @@ def test_match_common(self): # Multi-part glob-style pattern. self.assertFalse(P('/a/b/c.py').match('/**/*.py')) self.assertTrue(P('/a/b/c.py').match('/a/**/*.py')) + # Case-sensitive flag + self.assertFalse(P('A.py').match('a.PY', case_sensitive=True)) + self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) + self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) + self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) def test_ordering_common(self): # Ordering is tuple-alike. @@ -916,7 +921,7 @@ def test_as_uri(self): self.assertEqual(P('//some/share/a/b%#c\xe9').as_uri(), 'file://some/share/a/b%25%23c%C3%A9') - def test_match_common(self): + def test_match(self): P = self.cls # Absolute patterns. self.assertTrue(P('c:/b.py').match('*:/*.py')) diff --git a/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst b/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst new file mode 100644 index 000000000000..6d42078c35dd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst @@ -0,0 +1 @@ +Added *case_sensitive* argument to :meth:`pathlib.PurePath.match` From webhook-mailer at python.org Thu May 18 17:22:22 2023 From: webhook-mailer at python.org (carljm) Date: Thu, 18 May 2023 21:22:22 -0000 Subject: [Python-checkins] gh-104615: don't make unsafe swaps in apply_static_swaps (#104620) Message-ID: <mailman.430.1684444942.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0589c6a4d3d822cace42050198cb9a5e99c879ad commit: 0589c6a4d3d822cace42050198cb9a5e99c879ad branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-18T21:22:03Z summary: gh-104615: don't make unsafe swaps in apply_static_swaps (#104620) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst M Include/internal/pycore_compile.h M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/test/support/bytecode_helper.py M Lib/test/test_compile.py M Lib/test/test_listcomps.py M Lib/test/test_peepholer.py M Modules/_testinternalcapi.c M Modules/clinic/_testinternalcapi.c.h M Python/compile.c M Python/flowgraph.c diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 499f55f3e276..80a637e5bf9a 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -105,7 +105,8 @@ PyAPI_FUNC(PyObject*) _PyCompile_CodeGen( PyAPI_FUNC(PyObject*) _PyCompile_OptimizeCfg( PyObject *instructions, - PyObject *consts); + PyObject *consts, + int nlocals); PyAPI_FUNC(PyCodeObject*) _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename, diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 24a268ac8c43..eeaa2ad96c90 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1071,6 +1071,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(newline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(newlines)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(next)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(nlocals)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(node_depth)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(node_offset)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ns)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index c1005d051552..5cc790d126be 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -559,6 +559,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(newline) STRUCT_FOR_ID(newlines) STRUCT_FOR_ID(next) + STRUCT_FOR_ID(nlocals) STRUCT_FOR_ID(node_depth) STRUCT_FOR_ID(node_offset) STRUCT_FOR_ID(ns) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index ff1dee6eacfe..0cb24a92dffa 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1065,6 +1065,7 @@ extern "C" { INIT_ID(newline), \ INIT_ID(newlines), \ INIT_ID(next), \ + INIT_ID(nlocals), \ INIT_ID(node_depth), \ INIT_ID(node_offset), \ INIT_ID(ns), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index ba6b37f1bf55..fe2479beb8a3 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1518,6 +1518,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(next); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(nlocals); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(node_depth); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/test/support/bytecode_helper.py b/Lib/test/support/bytecode_helper.py index 7b577f54b8ad..388d1266773c 100644 --- a/Lib/test/support/bytecode_helper.py +++ b/Lib/test/support/bytecode_helper.py @@ -130,10 +130,10 @@ def generate_code(self, ast): class CfgOptimizationTestCase(CompilationStepTestCase): - def get_optimized(self, insts, consts): + def get_optimized(self, insts, consts, nlocals=0): insts = self.normalize_insts(insts) insts = self.complete_insts_info(insts) - insts = optimize_cfg(insts, consts) + insts = optimize_cfg(insts, consts, nlocals) return insts, consts class AssemblerTestCase(CompilationStepTestCase): diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index c68b9ce38846..784c0550cc09 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1168,6 +1168,24 @@ def foo(param, lambda_exp): """) compile(code, "<test>", "exec") + def test_apply_static_swaps(self): + def f(x, y): + a, a = x, y + return a + self.assertEqual(f("x", "y"), "y") + + def test_apply_static_swaps_2(self): + def f(x, y, z): + a, b, a = x, y, z + return a + self.assertEqual(f("x", "y", "z"), "z") + + def test_apply_static_swaps_3(self): + def f(x, y, z): + a, a, b = x, y, z + return a + self.assertEqual(f("x", "y", "z"), "y") + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 985274dfd6cb..ae63f4a35394 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -484,6 +484,12 @@ def test_nested_listcomp_in_lambda(self): """ self._check_in_scopes(code, {"z": 1, "out": [(3, 2, 1)]}) + def test_assign_to_comp_iter_var_in_outer_function(self): + code = """ + a = [1 for a in [0]] + """ + self._check_in_scopes(code, {"a": [1]}, scopes=["function"]) + __test__ = {'doctests' : doctests} diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index bf7fc421a9df..255e92804214 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -971,13 +971,14 @@ def trace(frame, event, arg): self.assertNotInBytecode(f, "LOAD_FAST_CHECK") -class DirectiCfgOptimizerTests(CfgOptimizationTestCase): +class DirectCfgOptimizerTests(CfgOptimizationTestCase): def cfg_optimization_test(self, insts, expected_insts, - consts=None, expected_consts=None): + consts=None, expected_consts=None, + nlocals=0): if expected_consts is None: expected_consts = consts - opt_insts, opt_consts = self.get_optimized(insts, consts) + opt_insts, opt_consts = self.get_optimized(insts, consts, nlocals) expected_insts = self.normalize_insts(expected_insts) self.assertInstructionsMatch(opt_insts, expected_insts) self.assertEqual(opt_consts, expected_consts) @@ -1058,6 +1059,19 @@ def test_conditional_jump_backward_const_condition(self): ] self.cfg_optimization_test(insts, expected_insts, consts=list(range(5))) + def test_no_unsafe_static_swap(self): + # We can't change order of two stores to the same location + insts = [ + ('LOAD_CONST', 0, 1), + ('LOAD_CONST', 1, 2), + ('LOAD_CONST', 2, 3), + ('SWAP', 3, 4), + ('STORE_FAST', 1, 4), + ('STORE_FAST', 1, 4), + ('POP_TOP', 0, 4), + ('RETURN_VALUE', 5) + ] + self.cfg_optimization_test(insts, insts, consts=list(range(3)), nlocals=1) if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst new file mode 100644 index 000000000000..447291a619dd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst @@ -0,0 +1,2 @@ +Fix wrong ordering of assignments in code like ``a, a = x, y``. Contributed by +Carl Meyer. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 5802f1d4ff5f..3ee332393083 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -616,16 +616,17 @@ _testinternalcapi.optimize_cfg -> object instructions: object consts: object + nlocals: int Apply compiler optimizations to an instruction list. [clinic start generated code]*/ static PyObject * _testinternalcapi_optimize_cfg_impl(PyObject *module, PyObject *instructions, - PyObject *consts) -/*[clinic end generated code: output=5412aeafca683c8b input=7e8a3de86ebdd0f9]*/ + PyObject *consts, int nlocals) +/*[clinic end generated code: output=57c53c3a3dfd1df0 input=6a96d1926d58d7e5]*/ { - return _PyCompile_OptimizeCfg(instructions, consts); + return _PyCompile_OptimizeCfg(instructions, consts, nlocals); } static int diff --git a/Modules/clinic/_testinternalcapi.c.h b/Modules/clinic/_testinternalcapi.c.h index 41dd50437956..f51241258745 100644 --- a/Modules/clinic/_testinternalcapi.c.h +++ b/Modules/clinic/_testinternalcapi.c.h @@ -83,7 +83,7 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s } PyDoc_STRVAR(_testinternalcapi_optimize_cfg__doc__, -"optimize_cfg($module, /, instructions, consts)\n" +"optimize_cfg($module, /, instructions, consts, nlocals)\n" "--\n" "\n" "Apply compiler optimizations to an instruction list."); @@ -93,7 +93,7 @@ PyDoc_STRVAR(_testinternalcapi_optimize_cfg__doc__, static PyObject * _testinternalcapi_optimize_cfg_impl(PyObject *module, PyObject *instructions, - PyObject *consts); + PyObject *consts, int nlocals); static PyObject * _testinternalcapi_optimize_cfg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -101,14 +101,14 @@ _testinternalcapi_optimize_cfg(PyObject *module, PyObject *const *args, Py_ssize PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 2 + #define NUM_KEYWORDS 3 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(instructions), &_Py_ID(consts), }, + .ob_item = { &_Py_ID(instructions), &_Py_ID(consts), &_Py_ID(nlocals), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -117,24 +117,29 @@ _testinternalcapi_optimize_cfg(PyObject *module, PyObject *const *args, Py_ssize # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"instructions", "consts", NULL}; + static const char * const _keywords[] = {"instructions", "consts", "nlocals", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "optimize_cfg", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; + PyObject *argsbuf[3]; PyObject *instructions; PyObject *consts; + int nlocals; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); if (!args) { goto exit; } instructions = args[0]; consts = args[1]; - return_value = _testinternalcapi_optimize_cfg_impl(module, instructions, consts); + nlocals = _PyLong_AsInt(args[2]); + if (nlocals == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _testinternalcapi_optimize_cfg_impl(module, instructions, consts, nlocals); exit: return return_value; @@ -201,4 +206,4 @@ _testinternalcapi_assemble_code_object(PyObject *module, PyObject *const *args, exit: return return_value; } -/*[clinic end generated code: output=ab661d56a14b1a1c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2965f1578b986218 input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index 07f8d6684770..96cd6daa29fa 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7996,7 +7996,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, } PyObject * -_PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) +_PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts, int nlocals) { PyObject *res = NULL; PyObject *const_cache = PyDict_New(); @@ -8008,7 +8008,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (instructions_to_cfg(instructions, &g) < 0) { goto error; } - int code_flags = 0, nlocals = 0, nparams = 0, firstlineno = 1; + int code_flags = 0, nparams = 0, firstlineno = 1; if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams, firstlineno) < 0) { goto error; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 7f790b79d284..f8039a4985d9 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1293,6 +1293,11 @@ swaptimize(basicblock *block, int *ix) (opcode) == STORE_FAST_MAYBE_NULL || \ (opcode) == POP_TOP) +#define STORES_TO(instr) \ + (((instr).i_opcode == STORE_FAST || \ + (instr).i_opcode == STORE_FAST_MAYBE_NULL) \ + ? (instr).i_oparg : -1) + static int next_swappable_instruction(basicblock *block, int i, int lineno) { @@ -1344,6 +1349,23 @@ apply_static_swaps(basicblock *block, int i) return; } } + // The reordering is not safe if the two instructions to be swapped + // store to the same location, or if any intervening instruction stores + // to the same location as either of them. + int store_j = STORES_TO(block->b_instr[j]); + int store_k = STORES_TO(block->b_instr[k]); + if (store_j >= 0 || store_k >= 0) { + if (store_j == store_k) { + return; + } + for (int idx = j + 1; idx < k; idx++) { + int store_idx = STORES_TO(block->b_instr[idx]); + if (store_idx >= 0 && (store_idx == store_j || store_idx == store_k)) { + return; + } + } + } + // Success! INSTR_SET_OP0(swap, NOP); cfg_instr temp = block->b_instr[j]; From webhook-mailer at python.org Thu May 18 17:53:26 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 18 May 2023 21:53:26 -0000 Subject: [Python-checkins] gh-104146: Remove unused vars from Argument Clinic (#104627) Message-ID: <mailman.431.1684446807.13550.python-checkins@python.org> https://github.com/python/cpython/commit/61027c0211adf50e81b202075246509775808482 commit: 61027c0211adf50e81b202075246509775808482 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-18T21:52:59Z summary: gh-104146: Remove unused vars from Argument Clinic (#104627) Remove 'in_classes' and 'so_far' from DSLParser.directive_module() files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 5fcf2bf485fc..ebee97829394 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4230,10 +4230,8 @@ def directive_module(self, name): def directive_class(self, name, typedef, type_object): fields = name.split('.') - in_classes = False parent = self name = fields.pop() - so_far = [] module, cls = self.clinic._module_and_class(fields) parent = cls or module From webhook-mailer at python.org Thu May 18 17:58:49 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 18 May 2023 21:58:49 -0000 Subject: [Python-checkins] gh-104050: Improve some typing around `default`s and sentinel values (#104626) Message-ID: <mailman.432.1684447129.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1c55e8d00728ceabd97cd1a5bd4906c9875a80c6 commit: 1c55e8d00728ceabd97cd1a5bd4906c9875a80c6 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-18T21:58:42Z summary: gh-104050: Improve some typing around `default`s and sentinel values (#104626) - Convert `unspecified` and `unknown` to be members of a `Sentinels` enum, rather than instances of bespoke classes. - An enum feels more idiomatic here, and works better with type checkers. - Convert some `==` and `!=` checks for these values to identity checks, which are more idiomatic with sentinels. - _Don't_ do the same for `Null`, as this needs to be a distinct type due to its usage in `clinic.py`. - Use `object` as the annotation for `default` across `clinic.py`. `default` can be literally any object, so `object` is the correct annotation here. --- Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index ebee97829394..42aac7eb17f2 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -12,6 +12,7 @@ import contextlib import copy import cpp +import enum import functools import hashlib import inspect @@ -28,7 +29,7 @@ from collections.abc import Callable from types import FunctionType, NoneType -from typing import Any, NamedTuple, NoReturn, Literal, overload +from typing import Any, Final, NamedTuple, NoReturn, Literal, overload # TODO: # @@ -58,25 +59,26 @@ "return_value", } -class Unspecified: + +class Sentinels(enum.Enum): + unspecified = "unspecified" + unknown = "unknown" + def __repr__(self) -> str: - return '<Unspecified>' + return f"<{self.value.capitalize()}>" + -unspecified = Unspecified() +unspecified: Final = Sentinels.unspecified +unknown: Final = Sentinels.unknown +# This one needs to be a distinct class, unlike the other two class Null: def __repr__(self) -> str: return '<Null>' -NULL = Null() - -class Unknown: - def __repr__(self) -> str: - return '<Unknown>' - -unknown = Unknown() +NULL = Null() sig_end_marker = '--' @@ -2600,7 +2602,7 @@ class CConverter(metaclass=CConverterAutoRegister): # Or the magic value "unknown" if this value is a cannot be evaluated # at Argument-Clinic-preprocessing time (but is presumed to be valid # at runtime). - default: bool | Unspecified = unspecified + default: object = unspecified # If not None, default must be isinstance() of this type. # (You can also specify a tuple of types.) @@ -2686,11 +2688,11 @@ def __init__(self, name: str, py_name: str, function, - default=unspecified, + default: object = unspecified, *, # Keyword only args: c_default: str | None = None, py_default: str | None = None, - annotation: str | Unspecified = unspecified, + annotation: str | Literal[Sentinels.unspecified] = unspecified, unused: bool = False, **kwargs ): @@ -2699,7 +2701,10 @@ def __init__(self, self.unused = unused if default is not unspecified: - if self.default_type and not isinstance(default, (self.default_type, Unknown)): + if (self.default_type + and default is not unknown + and not isinstance(default, self.default_type) + ): if isinstance(self.default_type, type): types_str = self.default_type.__name__ else: @@ -2713,7 +2718,7 @@ def __init__(self, if py_default: self.py_default = py_default - if annotation != unspecified: + if annotation is not unspecified: fail("The 'annotation' parameter is not currently permitted.") # this is deliberate, to prevent you from caching information @@ -3967,7 +3972,7 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister): # The Python default value for this parameter, as a Python value. # Or the magic value "unspecified" if there is no default. - default = None + default: object = None def __init__(self, *, py_default=None, **kwargs): self.py_default = py_default @@ -4767,7 +4772,7 @@ def bad_node(self, node): # but at least make an attempt at ensuring it's a valid expression. try: value = eval(default) - if value == unspecified: + if value is unspecified: fail("'unspecified' is not a legal default value!") except NameError: pass # probably a named constant From webhook-mailer at python.org Thu May 18 18:56:27 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 18 May 2023 22:56:27 -0000 Subject: [Python-checkins] gh-104549: Set __module__ on TypeAliasType (#104550) Message-ID: <mailman.433.1684450589.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b9dce3aec46bf5190400bd8239fdd4ea9e64d674 commit: b9dce3aec46bf5190400bd8239fdd4ea9e64d674 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-18T15:56:15-07:00 summary: gh-104549: Set __module__ on TypeAliasType (#104550) files: M Include/internal/pycore_global_objects.h M Include/internal/pycore_typevarobject.h M Lib/test/mod_generics_cache.py M Lib/test/test_type_aliases.py M Modules/_typingmodule.c M Objects/object.c M Objects/typevarobject.c M Objects/unionobject.c M Tools/c-analyzer/cpython/globals-to-fix.tsv diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 40cc04d5d170..5a3fb132c745 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -75,7 +75,6 @@ struct _Py_interp_cached_objects { PyTypeObject *paramspec_type; PyTypeObject *paramspecargs_type; PyTypeObject *paramspeckwargs_type; - PyTypeObject *typealias_type; }; #define _Py_INTERP_STATIC_OBJECT(interp, NAME) \ diff --git a/Include/internal/pycore_typevarobject.h b/Include/internal/pycore_typevarobject.h index 2035e47e9230..c9fa97d68207 100644 --- a/Include/internal/pycore_typevarobject.h +++ b/Include/internal/pycore_typevarobject.h @@ -16,6 +16,8 @@ extern PyObject *_Py_subscript_generic(PyThreadState *, PyObject *); extern int _Py_initialize_generic(PyInterpreterState *); extern void _Py_clear_generic_types(PyInterpreterState *); +extern PyTypeObject _PyTypeAlias_Type; + #ifdef __cplusplus } #endif diff --git a/Lib/test/mod_generics_cache.py b/Lib/test/mod_generics_cache.py index 9d8b56cf03c3..6c1ee2fec837 100644 --- a/Lib/test/mod_generics_cache.py +++ b/Lib/test/mod_generics_cache.py @@ -1,6 +1,6 @@ """Module for testing the behavior of generics across different modules.""" -from typing import TypeVar, Generic, Optional +from typing import TypeVar, Generic, Optional, TypeAliasType default_a: Optional['A'] = None default_b: Optional['B'] = None @@ -19,3 +19,6 @@ class A(Generic[T]): my_inner_a1: 'B.A' my_inner_a2: A my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__ + +type Alias = int +OldStyle = TypeAliasType("OldStyle", int) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index d2abb932f589..56d150d67afb 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -1,6 +1,8 @@ +import pickle import types import unittest from test.support import check_syntax_error, run_code +from test import mod_generics_cache from typing import Callable, TypeAliasType, TypeVar, get_args @@ -155,6 +157,7 @@ def test_basic(self): self.assertEqual(TA.__name__, "TA") self.assertIs(TA.__value__, int) self.assertEqual(TA.__type_params__, ()) + self.assertEqual(TA.__module__, __name__) def test_generic(self): T = TypeVar("T") @@ -162,12 +165,14 @@ def test_generic(self): self.assertEqual(TA.__name__, "TA") self.assertEqual(TA.__value__, list[T]) self.assertEqual(TA.__type_params__, (T,)) + self.assertEqual(TA.__module__, __name__) def test_keywords(self): TA = TypeAliasType(name="TA", value=int) self.assertEqual(TA.__name__, "TA") self.assertIs(TA.__value__, int) self.assertEqual(TA.__type_params__, ()) + self.assertEqual(TA.__module__, __name__) def test_errors(self): with self.assertRaises(TypeError): @@ -202,3 +207,18 @@ def test_union(self): union3 = list[range] | Alias1 self.assertIsInstance(union3, types.UnionType) self.assertEqual(get_args(union3), (list[range], Alias1)) + + def test_module(self): + self.assertEqual(TypeAliasType.__module__, "typing") + type Alias = int + self.assertEqual(Alias.__module__, __name__) + self.assertEqual(mod_generics_cache.Alias.__module__, + mod_generics_cache.__name__) + self.assertEqual(mod_generics_cache.OldStyle.__module__, + mod_generics_cache.__name__) + + def test_pickling(self): + pickled = pickle.dumps(mod_generics_cache.Alias) + self.assertIs(pickle.loads(pickled), mod_generics_cache.Alias) + pickled = pickle.dumps(mod_generics_cache.OldStyle) + self.assertIs(pickle.loads(pickled), mod_generics_cache.OldStyle) diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c index ed2999c0b68b..39a124a26adf 100644 --- a/Modules/_typingmodule.c +++ b/Modules/_typingmodule.c @@ -6,6 +6,7 @@ #include "Python.h" #include "internal/pycore_interp.h" +#include "internal/pycore_typevarobject.h" #include "clinic/_typingmodule.c.h" /*[clinic input] @@ -56,9 +57,11 @@ _typing_exec(PyObject *m) EXPORT_TYPE("ParamSpec", paramspec_type); EXPORT_TYPE("ParamSpecArgs", paramspecargs_type); EXPORT_TYPE("ParamSpecKwargs", paramspeckwargs_type); - EXPORT_TYPE("TypeAliasType", typealias_type); EXPORT_TYPE("Generic", generic_type); #undef EXPORT_TYPE + if (PyModule_AddObjectRef(m, "TypeAliasType", (PyObject *)&_PyTypeAlias_Type) < 0) { + return -1; + } return 0; } diff --git a/Objects/object.c b/Objects/object.c index f3118665430d..ece0c5e21e77 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -14,7 +14,7 @@ #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntry_Type -#include "pycore_typevarobject.h" // _PyTypeVar_Type etc., _Py_initialize_generic +#include "pycore_typevarobject.h" // _PyTypeAlias_Type, _Py_initialize_generic #include "pycore_typeobject.h" // _PyBufferWrapper_Type #include "pycore_unionobject.h" // _PyUnion_Type #include "pycore_interpreteridobject.h" // _PyInterpreterID_Type @@ -2112,6 +2112,7 @@ static PyTypeObject* static_types[] = { &_PyWeakref_CallableProxyType, &_PyWeakref_ProxyType, &_PyWeakref_RefType, + &_PyTypeAlias_Type, // subclasses: _PyTypes_FiniTypes() deallocates them before their base // class diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 4464e7a9da89..6730ebfc064e 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -48,6 +48,7 @@ typedef struct { PyObject *type_params; PyObject *compute_value; PyObject *value; + PyObject *module; } typealiasobject; #include "clinic/typevarobject.c.h" @@ -1252,6 +1253,7 @@ typealias_dealloc(PyObject *self) Py_XDECREF(ta->type_params); Py_XDECREF(ta->compute_value); Py_XDECREF(ta->value); + Py_XDECREF(ta->module); Py_TYPE(self)->tp_free(self); Py_DECREF(tp); } @@ -1309,19 +1311,33 @@ typealias_type_params(PyObject *self, void *unused) return Py_NewRef(ta->type_params); } +static PyObject * +typealias_module(PyObject *self, void *unused) +{ + typealiasobject *ta = (typealiasobject *)self; + if (ta->module != NULL) { + return Py_NewRef(ta->module); + } + if (ta->compute_value != NULL) { + // PyFunction_GetModule() returns a borrowed reference + return Py_NewRef(PyFunction_GetModule(ta->compute_value)); + } + Py_RETURN_NONE; +} + static PyGetSetDef typealias_getset[] = { {"__parameters__", typealias_parameters, (setter)NULL, NULL, NULL}, {"__type_params__", typealias_type_params, (setter)NULL, NULL, NULL}, {"__value__", typealias_value, (setter)NULL, NULL, NULL}, + {"__module__", typealias_module, (setter)NULL, NULL, NULL}, {0} }; static typealiasobject * typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, - PyObject *value) + PyObject *value, PyObject *module) { - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typealias_type; - typealiasobject *ta = PyObject_GC_New(typealiasobject, tp); + typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type); if (ta == NULL) { return NULL; } @@ -1329,6 +1345,7 @@ typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value, ta->type_params = Py_IsNone(type_params) ? NULL : Py_XNewRef(type_params); ta->compute_value = Py_XNewRef(compute_value); ta->value = Py_XNewRef(value); + ta->module = Py_XNewRef(module); _PyObject_GC_TRACK(ta); return ta; } @@ -1339,6 +1356,7 @@ typealias_traverse(typealiasobject *self, visitproc visit, void *arg) Py_VISIT(self->type_params); Py_VISIT(self->compute_value); Py_VISIT(self->value); + Py_VISIT(self->module); return 0; } @@ -1348,6 +1366,7 @@ typealias_clear(typealiasobject *self) Py_CLEAR(self->type_params); Py_CLEAR(self->compute_value); Py_CLEAR(self->value); + Py_CLEAR(self->module); return 0; } @@ -1401,7 +1420,14 @@ typealias_new_impl(PyTypeObject *type, PyObject *name, PyObject *value, PyErr_SetString(PyExc_TypeError, "type_params must be a tuple"); return NULL; } - return (PyObject *)typealias_alloc(name, type_params, NULL, value); + PyObject *module = caller(); + if (module == NULL) { + return NULL; + } + PyObject *ta = (PyObject *)typealias_alloc(name, type_params, NULL, value, + module); + Py_DECREF(module); + return ta; } PyDoc_STRVAR(typealias_doc, @@ -1412,28 +1438,32 @@ Type aliases are created through the type statement:\n\ type Alias = int\n\ "); -static PyType_Slot typealias_slots[] = { - {Py_tp_doc, (void *)typealias_doc}, - {Py_tp_members, typealias_members}, - {Py_tp_methods, typealias_methods}, - {Py_tp_getset, typealias_getset}, - {Py_mp_subscript, typealias_subscript}, - {Py_tp_dealloc, typealias_dealloc}, - {Py_tp_alloc, PyType_GenericAlloc}, - {Py_tp_new, typealias_new}, - {Py_tp_free, PyObject_GC_Del}, - {Py_tp_traverse, (traverseproc)typealias_traverse}, - {Py_tp_clear, (inquiry)typealias_clear}, - {Py_tp_repr, typealias_repr}, - {Py_nb_or, _Py_union_type_or}, - {0, 0}, +static PyNumberMethods typealias_as_number = { + .nb_or = _Py_union_type_or, +}; + +static PyMappingMethods typealias_as_mapping = { + .mp_subscript = typealias_subscript, }; -PyType_Spec typealias_spec = { - .name = "typing.TypeAliasType", - .basicsize = sizeof(typealiasobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC, - .slots = typealias_slots, +PyTypeObject _PyTypeAlias_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "typing.TypeAliasType", + .tp_basicsize = sizeof(typealiasobject), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_GC, + .tp_doc = typealias_doc, + .tp_members = typealias_members, + .tp_methods = typealias_methods, + .tp_getset = typealias_getset, + .tp_alloc = PyType_GenericAlloc, + .tp_dealloc = typealias_dealloc, + .tp_new = typealias_new, + .tp_free = PyObject_GC_Del, + .tp_traverse = (traverseproc)typealias_traverse, + .tp_clear = (inquiry)typealias_clear, + .tp_repr = typealias_repr, + .tp_as_number = &typealias_as_number, + .tp_as_mapping = &typealias_as_mapping, }; PyObject * @@ -1445,7 +1475,8 @@ _Py_make_typealias(PyThreadState* unused, PyObject *args) assert(PyUnicode_Check(name)); PyObject *type_params = PyTuple_GET_ITEM(args, 1); PyObject *compute_value = PyTuple_GET_ITEM(args, 2); - return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL); + assert(PyFunction_Check(compute_value)); + return (PyObject *)typealias_alloc(name, type_params, compute_value, NULL, NULL); } PyDoc_STRVAR(generic_doc, @@ -1603,7 +1634,6 @@ int _Py_initialize_generic(PyInterpreterState *interp) MAKE_TYPE(paramspec); MAKE_TYPE(paramspecargs); MAKE_TYPE(paramspeckwargs); - MAKE_TYPE(typealias); #undef MAKE_TYPE return 0; } @@ -1616,5 +1646,4 @@ void _Py_clear_generic_types(PyInterpreterState *interp) Py_CLEAR(interp->cached_objects.paramspec_type); Py_CLEAR(interp->cached_objects.paramspecargs_type); Py_CLEAR(interp->cached_objects.paramspeckwargs_type); - Py_CLEAR(interp->cached_objects.typealias_type); } diff --git a/Objects/unionobject.c b/Objects/unionobject.c index 9806678b8048..f509a161bb95 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -1,6 +1,7 @@ // types.UnionType -- used to represent e.g. Union[int, str], int | str #include "Python.h" #include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK +#include "pycore_typevarobject.h" // _PyTypeAlias_Type #include "pycore_unionobject.h" #include "structmember.h" @@ -150,11 +151,11 @@ is_unionable(PyObject *obj) if (obj == Py_None || PyType_Check(obj) || _PyGenericAlias_Check(obj) || - _PyUnion_Check(obj)) { + _PyUnion_Check(obj) || + Py_IS_TYPE(obj, &_PyTypeAlias_Type)) { return 1; } - PyInterpreterState *interp = PyInterpreterState_Get(); - return Py_IS_TYPE(obj, interp->cached_objects.typealias_type); + return 0; } PyObject * diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index e2b93a3a2ec2..622c98d16283 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -90,6 +90,7 @@ Objects/typeobject.c - _PyBufferWrapper_Type - Objects/typeobject.c - PyBaseObject_Type - Objects/typeobject.c - PySuper_Type - Objects/typeobject.c - PyType_Type - +Objects/typevarobject.c - _PyTypeAlias_Type - Objects/unicodeobject.c - PyUnicodeIter_Type - Objects/unicodeobject.c - PyUnicode_Type - Objects/weakrefobject.c - _PyWeakref_CallableProxyType - From webhook-mailer at python.org Thu May 18 18:56:41 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 18 May 2023 22:56:41 -0000 Subject: [Python-checkins] gh-104629: Don't skip test_clinic if _testclinic is missing (#104630) Message-ID: <mailman.434.1684450602.13550.python-checkins@python.org> https://github.com/python/cpython/commit/86ee49f469b84e4b746526a00d8191d0e374a268 commit: 86ee49f469b84e4b746526a00d8191d0e374a268 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-19T00:56:34+02:00 summary: gh-104629: Don't skip test_clinic if _testclinic is missing (#104630) Just skip the tests that depend on the _testclinic extension module; we can still run the Python tests. files: M Lib/test/test_clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 28d9f6509264..f72cb0442f35 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -868,9 +868,12 @@ def test_external(self): self.assertEqual(new_mtime_ns, old_mtime_ns) -ac_tester = import_helper.import_module('_testclinic') - +try: + import _testclinic as ac_tester +except ImportError: + ac_tester = None + at unittest.skipIf(ac_tester is None, "_testclinic is missing") class ClinicFunctionalTest(unittest.TestCase): locals().update((name, getattr(ac_tester, name)) for name in dir(ac_tester) if name.startswith('test_')) From webhook-mailer at python.org Thu May 18 18:57:33 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 18 May 2023 22:57:33 -0000 Subject: [Python-checkins] gh-104050: Add more type annotations to Argument Clinic (#104628) Message-ID: <mailman.435.1684450654.13550.python-checkins@python.org> https://github.com/python/cpython/commit/94c8edabd3d6c8739aaae9b1cb0be822c754c742 commit: 94c8edabd3d6c8739aaae9b1cb0be822c754c742 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-18T22:57:26Z summary: gh-104050: Add more type annotations to Argument Clinic (#104628) Annotate the following: - methods of class Class - methods of class Module - methods of class PythonParser - function compute_checksum() - function parse_file() - global variable unsupported_special_methods files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 42aac7eb17f2..3d4961e6e7d7 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2229,7 +2229,12 @@ def _module_and_class(self, fields): return module, cls -def parse_file(filename, *, verify=True, output=None): +def parse_file( + filename: str, + *, + verify: bool = True, + output: str | None = None +) -> None: if not output: output = filename @@ -2261,7 +2266,10 @@ def parse_file(filename, *, verify=True, output=None): write_file(fn, data) -def compute_checksum(input, length=None): +def compute_checksum( + input: str | None, + length: int | None = None +) -> str: input = input or '' s = hashlib.sha1(input.encode('utf-8')).hexdigest() if length: @@ -2272,30 +2280,46 @@ def compute_checksum(input, length=None): class PythonParser: - def __init__(self, clinic): + def __init__(self, clinic: Clinic) -> None: pass - def parse(self, block): + def parse(self, block: Block) -> None: s = io.StringIO() with OverrideStdioWith(s): exec(block.input) block.output = s.getvalue() +ModuleDict = dict[str, "Module"] + class Module: - def __init__(self, name, module=None): + def __init__( + self, + name: str, + module = None + ) -> None: self.name = name self.module = self.parent = module - self.modules = collections.OrderedDict() - self.classes = collections.OrderedDict() - self.functions = [] + self.modules: ModuleDict = collections.OrderedDict() + self.classes: ClassDict = collections.OrderedDict() + self.functions: list[Function] = [] - def __repr__(self): + def __repr__(self) -> str: return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">" + +ClassDict = dict[str, "Class"] + class Class: - def __init__(self, name, module=None, cls=None, typedef=None, type_object=None): + def __init__( + self, + name: str, + module: Module | None = None, + cls = None, + typedef: str | None = None, + type_object: str | None = None + ) -> None: self.name = name self.module = module self.cls = cls @@ -2303,13 +2327,14 @@ def __init__(self, name, module=None, cls=None, typedef=None, type_object=None): self.type_object = type_object self.parent = cls or module - self.classes = collections.OrderedDict() - self.functions = [] + self.classes: ClassDict = collections.OrderedDict() + self.functions: list[Function] = [] - def __repr__(self): + def __repr__(self) -> str: return "<clinic.Class " + repr(self.name) + " at " + str(id(self)) + ">" -unsupported_special_methods = set(""" + +unsupported_special_methods: set[str] = set(""" __abs__ __add__ From webhook-mailer at python.org Thu May 18 18:59:47 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 18 May 2023 22:59:47 -0000 Subject: [Python-checkins] gh-104623: Update Windows installer to use SQLite 3.42.0 (#104625) Message-ID: <mailman.436.1684450787.13550.python-checkins@python.org> https://github.com/python/cpython/commit/aab2a366b7d6a5c123bc8d23d66db4d2277dfa09 commit: aab2a366b7d6a5c123bc8d23d66db4d2277dfa09 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-19T00:59:40+02:00 summary: gh-104623: Update Windows installer to use SQLite 3.42.0 (#104625) files: A Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst b/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst new file mode 100644 index 000000000000..3ffe8261e5a1 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.42.0. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 30ee873af9af..39003d954d70 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t -set libraries=%libraries% sqlite-3.41.2.0 +set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index 29add07795f9..1d959699f3cf 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -68,7 +68,7 @@ <Import Project="$(ExternalProps)" Condition="$(ExternalProps) != '' and Exists('$(ExternalProps)')" /> <PropertyGroup> - <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.41.2.0\</sqlite3Dir> + <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.42.0.0\</sqlite3Dir> <bz2Dir Condition="$(bz2Dir) == ''">$(ExternalsDir)bzip2-1.0.8\</bz2Dir> <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.2.5\</lzmaDir> <libffiDir Condition="$(libffiDir) == ''">$(ExternalsDir)libffi-3.4.4\</libffiDir> diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 9df56685b76a..3629525e33d5 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -188,7 +188,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.41.2, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.42.0, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Thu May 18 19:20:42 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 18 May 2023 23:20:42 -0000 Subject: [Python-checkins] [3.11] gh-104629: Don't skip test_clinic if _testclinic is missing (GH-104630) (#104632) Message-ID: <mailman.437.1684452042.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3d52f7e60c8217e24f6e3ba9ec3a2723c221d5f8 commit: 3d52f7e60c8217e24f6e3ba9ec3a2723c221d5f8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-18T23:20:35Z summary: [3.11] gh-104629: Don't skip test_clinic if _testclinic is missing (GH-104630) (#104632) gh-104629: Don't skip test_clinic if _testclinic is missing (GH-104630) Just skip the tests that depend on the _testclinic extension module; we can still run the Python tests. (cherry picked from commit 86ee49f469b84e4b746526a00d8191d0e374a268) Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: M Lib/test/test_clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index a84d24a79844..02a54bf154ee 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -829,9 +829,12 @@ def test_external(self): self.assertEqual(new_mtime_ns, old_mtime_ns) -ac_tester = import_helper.import_module('_testclinic') - +try: + import _testclinic as ac_tester +except ImportError: + ac_tester = None + at unittest.skipIf(ac_tester is None, "_testclinic is missing") class ClinicFunctionalTest(unittest.TestCase): locals().update((name, getattr(ac_tester, name)) for name in dir(ac_tester) if name.startswith('test_')) From webhook-mailer at python.org Thu May 18 19:34:05 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 18 May 2023 23:34:05 -0000 Subject: [Python-checkins] [3.11] gh-104623: Update Windows installer to use SQLite 3.42.0 (#104625) (#104633) Message-ID: <mailman.438.1684452846.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ba39ea48d5b12ec34ee6c7b81696e994c0d8436c commit: ba39ea48d5b12ec34ee6c7b81696e994c0d8436c branch: 3.11 author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-18T23:33:58Z summary: [3.11] gh-104623: Update Windows installer to use SQLite 3.42.0 (#104625) (#104633) files: A Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt diff --git a/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst b/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst new file mode 100644 index 000000000000..3ffe8261e5a1 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst @@ -0,0 +1 @@ +Update Windows installer to use SQLite 3.42.0. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 329f2a2ade23..cda58f1c4497 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -54,7 +54,7 @@ set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t -set libraries=%libraries% sqlite-3.41.2.0 +set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.12.1 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tix-8.4.3.6 diff --git a/PCbuild/python.props b/PCbuild/python.props index 29add07795f9..1d959699f3cf 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -68,7 +68,7 @@ <Import Project="$(ExternalProps)" Condition="$(ExternalProps) != '' and Exists('$(ExternalProps)')" /> <PropertyGroup> - <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.41.2.0\</sqlite3Dir> + <sqlite3Dir Condition="$(sqlite3Dir) == ''">$(ExternalsDir)sqlite-3.42.0.0\</sqlite3Dir> <bz2Dir Condition="$(bz2Dir) == ''">$(ExternalsDir)bzip2-1.0.8\</bz2Dir> <lzmaDir Condition="$(lzmaDir) == ''">$(ExternalsDir)xz-5.2.5\</lzmaDir> <libffiDir Condition="$(libffiDir) == ''">$(ExternalsDir)libffi-3.4.4\</libffiDir> diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index b73196510dcd..f9742426e7c4 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -187,7 +187,7 @@ _ssl again when building. _sqlite3 - Wraps SQLite 3.41.2, which is itself built by sqlite3.vcxproj + Wraps SQLite 3.42.0, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ _tkinter From webhook-mailer at python.org Thu May 18 19:34:48 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 18 May 2023 23:34:48 -0000 Subject: [Python-checkins] gh-74690: Don't set special protocol attributes on non-protocol subclasses of protocols (#104622) Message-ID: <mailman.439.1684452889.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f7835fc7e9617cefd87e72002916e258f589c857 commit: f7835fc7e9617cefd87e72002916e258f589c857 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-19T00:34:40+01:00 summary: gh-74690: Don't set special protocol attributes on non-protocol subclasses of protocols (#104622) Don't set special protocol attributes on non-protocol subclasses of protocols files: 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 bf038bf143a6..450c85967dd7 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3167,6 +3167,21 @@ def meth(self): pass self.assertIsInstance(NonPR(), PR) self.assertIsSubclass(NonPR, PR) + self.assertNotIn("__protocol_attrs__", vars(NonP)) + self.assertNotIn("__protocol_attrs__", vars(NonPR)) + self.assertNotIn("__callable_proto_members_only__", vars(NonP)) + self.assertNotIn("__callable_proto_members_only__", vars(NonPR)) + + acceptable_extra_attrs = { + '_is_protocol', '_is_runtime_protocol', '__parameters__', + '__subclasshook__', '__abstractmethods__', '_abc_impl', + '__init__', '__annotations__', + } + self.assertLessEqual(vars(NonP).keys(), vars(C).keys() | acceptable_extra_attrs) + self.assertLessEqual( + vars(NonPR).keys(), vars(D).keys() | acceptable_extra_attrs + ) + def test_custom_subclasshook(self): class P(Protocol): x = 1 diff --git a/Lib/typing.py b/Lib/typing.py index 91b5fe5b87e6..b60eb94351f9 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1779,12 +1779,13 @@ class _ProtocolMeta(ABCMeta): # but is necessary for several reasons... 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__ - ) + if getattr(cls, "_is_protocol", False): + 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 __subclasscheck__(cls, other): if ( From webhook-mailer at python.org Thu May 18 19:45:44 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 18 May 2023 23:45:44 -0000 Subject: [Python-checkins] gh-104600: Make function.__type_params__ writable (#104601) Message-ID: <mailman.440.1684453544.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3fadd7d5857842fc5cddd4c496b73161b0bcb421 commit: 3fadd7d5857842fc5cddd4c496b73161b0bcb421 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-18T16:45:37-07:00 summary: gh-104600: Make function.__type_params__ writable (#104601) files: A Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst M Lib/functools.py M Lib/test/test_funcattrs.py M Lib/test/test_functools.py M Lib/test/test_type_params.py M Objects/funcobject.c diff --git a/Lib/functools.py b/Lib/functools.py index aaf4291150fb..72b2103e7a55 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -30,7 +30,7 @@ # wrapper functions that can handle naive introspection WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__', - '__annotations__') + '__annotations__', '__type_params__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 77977d0ae966..e08d72877d8a 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -1,5 +1,6 @@ import textwrap import types +import typing import unittest @@ -190,6 +191,20 @@ def test___qualname__(self): # __qualname__ must be a string self.cannot_set_attr(self.b, '__qualname__', 7, TypeError) + def test___type_params__(self): + def generic[T](): pass + def not_generic(): pass + T, = generic.__type_params__ + self.assertIsInstance(T, typing.TypeVar) + self.assertEqual(generic.__type_params__, (T,)) + self.assertEqual(not_generic.__type_params__, ()) + with self.assertRaises(TypeError): + del not_generic.__type_params__ + with self.assertRaises(TypeError): + not_generic.__type_params__ = 42 + not_generic.__type_params__ = (T,) + self.assertEqual(not_generic.__type_params__, (T,)) + def test___code__(self): num_one, num_two = 7, 8 def a(): pass diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index af286052a7d5..d668fa4c3adf 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -617,7 +617,7 @@ def check_wrapper(self, wrapper, wrapped, def _default_update(self): - def f(a:'This is a new annotation'): + def f[T](a:'This is a new annotation'): """This is a test""" pass f.attr = 'This is also a test' @@ -630,12 +630,14 @@ def wrapper(b:'This is the prior annotation'): def test_default_update(self): wrapper, f = self._default_update() self.check_wrapper(wrapper, f) + T, = f.__type_params__ self.assertIs(wrapper.__wrapped__, f) self.assertEqual(wrapper.__name__, 'f') self.assertEqual(wrapper.__qualname__, f.__qualname__) self.assertEqual(wrapper.attr, 'This is also a test') self.assertEqual(wrapper.__annotations__['a'], 'This is a new annotation') self.assertNotIn('b', wrapper.__annotations__) + self.assertEqual(wrapper.__type_params__, (T,)) @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 96bd1fa0bab9..466e3bd43a68 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -843,5 +843,5 @@ def func[A](): func.__type_params__ = () """ - with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'function' objects is not writable"): - run_code(code) + ns = run_code(code) + self.assertEqual(ns["func"].__type_params__, ()) diff --git a/Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst b/Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst new file mode 100644 index 000000000000..64f81e140d96 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst @@ -0,0 +1,2 @@ +:func:`functools.update_wrapper` now sets the ``__type_params__`` attribute +(added by :pep:`695`). diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 69898bf722d6..753038600aa8 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -665,6 +665,20 @@ func_get_type_params(PyFunctionObject *op, void *Py_UNUSED(ignored)) return Py_NewRef(op->func_typeparams); } +static int +func_set_type_params(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +{ + /* Not legal to del f.__type_params__ or to set it to anything + * other than a tuple object. */ + if (value == NULL || !PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__type_params__ must be set to a tuple"); + return -1; + } + Py_XSETREF(op->func_typeparams, Py_NewRef(value)); + return 0; +} + PyObject * _Py_set_function_type_params(PyThreadState *Py_UNUSED(ignored), PyObject *func, PyObject *type_params) @@ -687,7 +701,8 @@ static PyGetSetDef func_getsetlist[] = { {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, {"__name__", (getter)func_get_name, (setter)func_set_name}, {"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname}, - {"__type_params__", (getter)func_get_type_params, NULL}, + {"__type_params__", (getter)func_get_type_params, + (setter)func_set_type_params}, {NULL} /* Sentinel */ }; From webhook-mailer at python.org Thu May 18 20:07:44 2023 From: webhook-mailer at python.org (carljm) Date: Fri, 19 May 2023 00:07:44 -0000 Subject: [Python-checkins] gh-104602: ensure all cellvars are known up front (#104603) Message-ID: <mailman.441.1684454865.13550.python-checkins@python.org> https://github.com/python/cpython/commit/86e6f16ccb97f66f2b9a31191ce347dca499d48c commit: 86e6f16ccb97f66f2b9a31191ce347dca499d48c branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-19T00:07:35Z summary: gh-104602: ensure all cellvars are known up front (#104603) Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Include/internal/pycore_symtable.h M Lib/test/test_listcomps.py M Python/compile.c M Python/symtable.c diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 3fa825d0a837..c8e0578a2317 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -120,14 +120,15 @@ extern PyObject* _Py_Mangle(PyObject *p, PyObject *name); #define DEF_ANNOT 2<<7 /* this name is annotated */ #define DEF_COMP_ITER 2<<8 /* this name is a comprehension iteration variable */ #define DEF_TYPE_PARAM 2<<9 /* this name is a type parameter */ +#define DEF_COMP_CELL 2<<10 /* this name is a cell in an inlined comprehension */ #define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT) /* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol table. GLOBAL is returned from PyST_GetScope() for either of them. - It is stored in ste_symbols at bits 12-15. + It is stored in ste_symbols at bits 13-16. */ -#define SCOPE_OFFSET 11 +#define SCOPE_OFFSET 12 #define SCOPE_MASK (DEF_GLOBAL | DEF_LOCAL | DEF_PARAM | DEF_NONLOCAL) #define LOCAL 1 diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index ae63f4a35394..fdd2d66b49e0 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -381,6 +381,32 @@ def f(): with self.assertRaises(UnboundLocalError): f() + def test_global_outside_cellvar_inside_plus_freevar(self): + code = """ + a = 1 + def f(): + func, = [(lambda: b) for b in [a]] + return b, func() + x = f() + """ + self._check_in_scopes( + code, {"x": (2, 1)}, ns={"b": 2}, scopes=["function", "module"]) + # inside a class, the `a = 1` assignment is not visible + self._check_in_scopes(code, raises=NameError, scopes=["class"]) + + def test_cell_in_nested_comprehension(self): + code = """ + a = 1 + def f(): + (func, inner_b), = [[lambda: b for b in c] + [b] for c in [[a]]] + return b, inner_b, func() + x = f() + """ + self._check_in_scopes( + code, {"x": (2, 2, 1)}, ns={"b": 2}, scopes=["function", "module"]) + # inside a class, the `a = 1` assignment is not visible + self._check_in_scopes(code, raises=NameError, scopes=["class"]) + def test_name_error_in_class_scope(self): code = """ y = 1 diff --git a/Python/compile.c b/Python/compile.c index 96cd6daa29fa..2db03f7176ea 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1252,7 +1252,7 @@ compiler_enter_scope(struct compiler *c, identifier name, } 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); + u->u_metadata.u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, DEF_COMP_CELL, 0); if (!u->u_metadata.u_varnames || !u->u_metadata.u_cellvars) { compiler_unit_free(u); return ERROR; diff --git a/Python/symtable.c b/Python/symtable.c index a319c239d99b..bd523f0cdd74 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -632,7 +632,7 @@ is_free_in_any_child(PySTEntryObject *entry, PyObject *key) static int inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, PyObject *scopes, PyObject *comp_free, - PyObject *promote_to_cell) + PyObject *inlined_cells) { PyObject *k, *v; Py_ssize_t pos = 0; @@ -645,6 +645,11 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, } int scope = (comp_flags >> SCOPE_OFFSET) & SCOPE_MASK; int only_flags = comp_flags & ((1 << SCOPE_OFFSET) - 1); + if (scope == CELL || only_flags & DEF_COMP_CELL) { + if (PySet_Add(inlined_cells, k) < 0) { + return 0; + } + } PyObject *existing = PyDict_GetItemWithError(ste->ste_symbols, k); if (existing == NULL && PyErr_Occurred()) { return 0; @@ -665,14 +670,6 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, } else { if (PyLong_AsLong(existing) & DEF_BOUND) { - // cell vars in comprehension that are locals in outer scope - // must be promoted to cell so u_cellvars isn't wrong - if (scope == CELL && _PyST_IsFunctionLike(ste)) { - if (PySet_Add(promote_to_cell, k) < 0) { - return 0; - } - } - // free vars in comprehension that are locals in outer scope can // now simply be locals, unless they are free in comp children, // or if the outer scope is a class block @@ -698,7 +695,7 @@ inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp, */ static int -analyze_cells(PyObject *scopes, PyObject *free, PyObject *promote_to_cell) +analyze_cells(PyObject *scopes, PyObject *free, PyObject *inlined_cells) { PyObject *name, *v, *v_cell; int success = 0; @@ -713,7 +710,7 @@ analyze_cells(PyObject *scopes, PyObject *free, PyObject *promote_to_cell) scope = PyLong_AS_LONG(v); if (scope != LOCAL) continue; - if (!PySet_Contains(free, name) && !PySet_Contains(promote_to_cell, name)) + if (!PySet_Contains(free, name) && !PySet_Contains(inlined_cells, name)) continue; /* Replace LOCAL with CELL for this name, and remove from free. It is safe to replace the value of name @@ -753,7 +750,8 @@ drop_class_free(PySTEntryObject *ste, PyObject *free) */ static int update_symbols(PyObject *symbols, PyObject *scopes, - PyObject *bound, PyObject *free, int classflag) + PyObject *bound, PyObject *free, + PyObject *inlined_cells, int classflag) { PyObject *name = NULL, *itr = NULL; PyObject *v = NULL, *v_scope = NULL, *v_new = NULL, *v_free = NULL; @@ -764,6 +762,9 @@ update_symbols(PyObject *symbols, PyObject *scopes, long scope, flags; assert(PyLong_Check(v)); flags = PyLong_AS_LONG(v); + if (PySet_Contains(inlined_cells, name)) { + flags |= DEF_COMP_CELL; + } v_scope = PyDict_GetItemWithError(scopes, name); assert(v_scope && PyLong_Check(v_scope)); scope = PyLong_AS_LONG(v_scope); @@ -870,7 +871,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, PySTEntryObject *class_entry) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; - PyObject *newglobal = NULL, *newfree = NULL, *promote_to_cell = NULL; + PyObject *newglobal = NULL, *newfree = NULL, *inlined_cells = NULL; PyObject *temp; int success = 0; Py_ssize_t i, pos = 0; @@ -902,8 +903,8 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, newbound = PySet_New(NULL); if (!newbound) goto error; - promote_to_cell = PySet_New(NULL); - if (!promote_to_cell) + inlined_cells = PySet_New(NULL); + if (!inlined_cells) goto error; /* Class namespace has no effect on names visible in @@ -997,7 +998,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, goto error; } if (inline_comp) { - if (!inline_comprehension(ste, entry, scopes, child_free, promote_to_cell)) { + if (!inline_comprehension(ste, entry, scopes, child_free, inlined_cells)) { Py_DECREF(child_free); goto error; } @@ -1028,12 +1029,12 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, } /* Check if any local variables must be converted to cell variables */ - if (_PyST_IsFunctionLike(ste) && !analyze_cells(scopes, newfree, promote_to_cell)) + if (_PyST_IsFunctionLike(ste) && !analyze_cells(scopes, newfree, inlined_cells)) goto error; else if (ste->ste_type == ClassBlock && !drop_class_free(ste, newfree)) goto error; /* Records the results of the analysis in the symbol table entry */ - if (!update_symbols(ste->ste_symbols, scopes, bound, newfree, + if (!update_symbols(ste->ste_symbols, scopes, bound, newfree, inlined_cells, ste->ste_type == ClassBlock)) goto error; @@ -1048,7 +1049,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, Py_XDECREF(newbound); Py_XDECREF(newglobal); Py_XDECREF(newfree); - Py_XDECREF(promote_to_cell); + Py_XDECREF(inlined_cells); if (!success) assert(PyErr_Occurred()); return success; From webhook-mailer at python.org Thu May 18 21:50:31 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 19 May 2023 01:50:31 -0000 Subject: [Python-checkins] gh-104619: never leak comprehension locals to outer locals() (#104637) Message-ID: <mailman.442.1684461031.13550.python-checkins@python.org> https://github.com/python/cpython/commit/70c77964778817907fbcc2a047a2abad4eb6e127 commit: 70c77964778817907fbcc2a047a2abad4eb6e127 branch: main author: Carl Meyer <carl at oddbird.net> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-18T18:50:24-07:00 summary: gh-104619: never leak comprehension locals to outer locals() (#104637) files: M Lib/test/test_listcomps.py M Python/compile.c diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index fdd2d66b49e0..185658ab5a4c 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -516,6 +516,19 @@ def test_assign_to_comp_iter_var_in_outer_function(self): """ self._check_in_scopes(code, {"a": [1]}, scopes=["function"]) + def test_no_leakage_to_locals(self): + code = """ + def b(): + [a for b in [1] for _ in []] + return b, locals() + r, s = b() + x = r is b + y = list(s.keys()) + """ + self._check_in_scopes(code, {"x": True, "y": []}, scopes=["module"]) + self._check_in_scopes(code, {"x": True, "y": ["b"]}, scopes=["function"]) + self._check_in_scopes(code, raises=NameError, scopes=["class"]) + __test__ = {'doctests' : doctests} diff --git a/Python/compile.c b/Python/compile.c index 2db03f7176ea..cfe8224a7e27 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5490,31 +5490,29 @@ push_inlined_comprehension_state(struct compiler *c, location loc, } Py_DECREF(outv); } - if (outsc == LOCAL || outsc == CELL || outsc == FREE) { - // local names bound in comprehension must be isolated from - // outer scope; push existing value (which may be NULL if - // not defined) on stack + // local names bound in comprehension must be isolated from + // outer scope; push existing value (which may be NULL if + // not defined) on stack + if (state->pushed_locals == NULL) { + state->pushed_locals = PyList_New(0); if (state->pushed_locals == NULL) { - state->pushed_locals = PyList_New(0); - if (state->pushed_locals == NULL) { - return ERROR; - } - } - // in the case of a cell, this will actually push the cell - // itself to the stack, then we'll create a new one for the - // comprehension and restore the original one after - ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames); - if (scope == CELL) { - if (outsc == FREE) { - ADDOP_NAME(c, loc, MAKE_CELL, k, freevars); - } else { - ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars); - } - } - if (PyList_Append(state->pushed_locals, k) < 0) { return ERROR; } } + // in the case of a cell, this will actually push the cell + // itself to the stack, then we'll create a new one for the + // comprehension and restore the original one after + ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames); + if (scope == CELL) { + if (outsc == FREE) { + ADDOP_NAME(c, loc, MAKE_CELL, k, freevars); + } else { + ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars); + } + } + if (PyList_Append(state->pushed_locals, k) < 0) { + return ERROR; + } } } if (state->pushed_locals) { From webhook-mailer at python.org Fri May 19 02:52:58 2023 From: webhook-mailer at python.org (ned-deily) Date: Fri, 19 May 2023 06:52:58 -0000 Subject: [Python-checkins] gh-104623: Update macOS installer to SQLite 3.42.0 (GH-104624) Message-ID: <mailman.443.1684479179.13550.python-checkins@python.org> https://github.com/python/cpython/commit/fd04bfeaf7a4531120ad450dbd1afc121a2523ee commit: fd04bfeaf7a4531120ad450dbd1afc121a2523ee branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: ned-deily <nad at python.org> date: 2023-05-19T02:52:24-04:00 summary: gh-104623: Update macOS installer to SQLite 3.42.0 (GH-104624) files: A Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 2f5937489ac0..5474f87fd6cb 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -359,9 +359,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.41.2", - url="https://sqlite.org/2023/sqlite-autoconf-3410200.tar.gz", - checksum="862075fd1c38324878ef809eda39edfe", + name="SQLite 3.42.0", + url="https://sqlite.org/2023/sqlite-autoconf-3420000.tar.gz", + checksum="0c5a92bc51cf07cae45b4a1e94653dea", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst b/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst new file mode 100644 index 000000000000..ffb124631c21 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.42.0. From webhook-mailer at python.org Fri May 19 03:15:36 2023 From: webhook-mailer at python.org (ronaldoussoren) Date: Fri, 19 May 2023 07:15:36 -0000 Subject: [Python-checkins] GH-103545: Add macOS specific constants for ``os.setpriority`` to ``os`` (#104606) Message-ID: <mailman.444.1684480537.13550.python-checkins@python.org> https://github.com/python/cpython/commit/616fcad6e2e10b0d0252e7f3688e61c468c54e6e commit: 616fcad6e2e10b0d0252e7f3688e61c468c54e6e branch: main author: Ronald Oussoren <ronaldoussoren at mac.com> committer: ronaldoussoren <ronaldoussoren at mac.com> date: 2023-05-19T09:15:11+02:00 summary: GH-103545: Add macOS specific constants for ``os.setpriority`` to ``os`` (#104606) This adds a number of PRIO_DARWIN_* constants to the os module for use with os.setpriority. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> files: A Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst M Doc/library/os.rst M Modules/posixmodule.c diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 641e289e77c5..83abb5d5ca1e 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -493,6 +493,17 @@ process and user. .. versionadded:: 3.3 +.. data:: PRIO_DARWIN_THREAD + PRIO_DARWIN_PROCESS + PRIO_DARWIN_BG + PRIO_DARWIN_NONUI + + Parameters for the :func:`getpriority` and :func:`setpriority` functions. + + .. availability:: macOS + + .. versionadded:: 3.12 + .. function:: getresuid() Return a tuple (ruid, euid, suid) denoting the current process's diff --git a/Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst b/Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst new file mode 100644 index 000000000000..c40f9460508d --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst @@ -0,0 +1 @@ +Add ``os.PRIO_DARWIN_THREAD``, ``os.PRIO_DARWIN_PROCESS``, ``os.PRIO_DARWIN_BG`` and ``os.PRIO_DARWIN_NONUI``. These can be used with ``os.setpriority`` to run the process at a lower priority and make use of the efficiency cores on Apple Silicon systems. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 5022fdeb0370..531f26ba8bc8 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -15917,6 +15917,18 @@ all_ins(PyObject *m) #ifdef PRIO_USER if (PyModule_AddIntMacro(m, PRIO_USER)) return -1; #endif +#ifdef PRIO_DARWIN_THREAD + if (PyModule_AddIntMacro(m, PRIO_DARWIN_THREAD)) return -1; +#endif +#ifdef PRIO_DARWIN_PROCESS + if (PyModule_AddIntMacro(m, PRIO_DARWIN_PROCESS)) return -1; +#endif +#ifdef PRIO_DARWIN_BG + if (PyModule_AddIntMacro(m, PRIO_DARWIN_BG)) return -1; +#endif +#ifdef PRIO_DARWIN_NONUI + if (PyModule_AddIntMacro(m, PRIO_DARWIN_NONUI)) return -1; +#endif #ifdef O_CLOEXEC if (PyModule_AddIntMacro(m, O_CLOEXEC)) return -1; #endif From webhook-mailer at python.org Fri May 19 03:16:50 2023 From: webhook-mailer at python.org (ned-deily) Date: Fri, 19 May 2023 07:16:50 -0000 Subject: [Python-checkins] [3.11] gh-104623: Update macOS installer to SQLite 3.42.0 (GH-104643) Message-ID: <mailman.445.1684480611.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d1bfefd8de5c1fd51baec9e86e5f3bcc9ce28943 commit: d1bfefd8de5c1fd51baec9e86e5f3bcc9ce28943 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily <nad at python.org> date: 2023-05-19T07:16:43Z summary: [3.11] gh-104623: Update macOS installer to SQLite 3.42.0 (GH-104643) (cherry picked from commit fd04bfeaf7a4531120ad450dbd1afc121a2523ee) Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: A Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 8748b205ed7d..a4d62e509b37 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -358,9 +358,9 @@ def library_recipes(): ), ), dict( - name="SQLite 3.41.2", - url="https://sqlite.org/2023/sqlite-autoconf-3410200.tar.gz", - checksum="862075fd1c38324878ef809eda39edfe", + name="SQLite 3.42.0", + url="https://sqlite.org/2023/sqlite-autoconf-3420000.tar.gz", + checksum="0c5a92bc51cf07cae45b4a1e94653dea", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' diff --git a/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst b/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst new file mode 100644 index 000000000000..ffb124631c21 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst @@ -0,0 +1 @@ +Update macOS installer to SQLite 3.42.0. From webhook-mailer at python.org Fri May 19 07:41:24 2023 From: webhook-mailer at python.org (markshannon) Date: Fri, 19 May 2023 11:41:24 -0000 Subject: [Python-checkins] GH-102818: Do not call `PyTraceBack_Here` in sys.settrace trampoline. (GH-104579) Message-ID: <mailman.446.1684496485.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c26d03d5d6da94367c7f9cd93185616f2385db30 commit: c26d03d5d6da94367c7f9cd93185616f2385db30 branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-19T12:40:48+01:00 summary: GH-102818: Do not call `PyTraceBack_Here` in sys.settrace trampoline. (GH-104579) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst M Lib/test/test_sys_settrace.py M Modules/_testcapimodule.c M Python/sysmodule.c diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 4411603af18c..0571919066bb 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1568,6 +1568,62 @@ def func(): self.run_and_compare(func, EXPECTED_EVENTS) + def test_settrace_error(self): + + raised = False + def error_once(frame, event, arg): + nonlocal raised + if not raised: + raised = True + raise Exception + return error + + try: + sys._getframe().f_trace = error_once + sys.settrace(error_once) + len([]) + except Exception as ex: + count = 0 + tb = ex.__traceback__ + print(tb) + while tb: + if tb.tb_frame.f_code.co_name == "test_settrace_error": + count += 1 + tb = tb.tb_next + if count == 0: + self.fail("Traceback is missing frame") + elif count > 1: + self.fail("Traceback has frame more than once") + else: + self.fail("No exception raised") + finally: + sys.settrace(None) + + @support.cpython_only + def test_testcapi_settrace_error(self): + + # Skip this test if the _testcapi module isn't available. + _testcapi = import_helper.import_module('_testcapi') + + try: + _testcapi.settrace_to_error([]) + len([]) + except Exception as ex: + count = 0 + tb = ex.__traceback__ + while tb: + if tb.tb_frame.f_code.co_name == "test_testcapi_settrace_error": + count += 1 + tb = tb.tb_next + if count == 0: + self.fail("Traceback is missing frame") + elif count > 1: + self.fail("Traceback has frame more than once") + else: + self.fail("No exception raised") + finally: + sys.settrace(None) + def test_very_large_function(self): # There is a separate code path when the number of lines > (1 << 15). d = {} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst new file mode 100644 index 000000000000..5cb77bff792c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst @@ -0,0 +1,5 @@ +Do not add a frame to the traceback in the ``sys.setprofile`` and +``sys.settrace`` trampoline functions. This ensures that frames are not +duplicated if an exception is raised in the callback function, and ensures +that frames are not omitted if a C callback is used and that does not add the +frame. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c29d29c47911..1be1dd617893 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3062,6 +3062,33 @@ settrace_to_record(PyObject *self, PyObject *list) Py_RETURN_NONE; } +static int +error_func(PyObject *obj, PyFrameObject *f, int what, PyObject *arg) +{ + assert(PyList_Check(obj)); + /* Only raise if list is empty, otherwise append None + * This ensures that we only raise once */ + if (PyList_GET_SIZE(obj)) { + return 0; + } + if (PyList_Append(obj, Py_None)) { + return -1; + } + PyErr_SetString(PyExc_Exception, "an exception"); + return -1; +} + +static PyObject * +settrace_to_error(PyObject *self, PyObject *list) +{ + if (!PyList_Check(list)) { + PyErr_SetString(PyExc_TypeError, "argument must be a list"); + return NULL; + } + PyEval_SetTrace(error_func, list); + Py_RETURN_NONE; +} + static PyObject * clear_managed_dict(PyObject *self, PyObject *obj) { @@ -3352,6 +3379,7 @@ static PyMethodDef TestMethods[] = { {"gen_get_code", gen_get_code, METH_O, NULL}, {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, {"test_code_api", test_code_api, METH_NOARGS, NULL}, + {"settrace_to_error", settrace_to_error, METH_O, NULL}, {"settrace_to_record", settrace_to_record, METH_O, NULL}, {"test_macros", test_macros, METH_NOARGS, NULL}, {"clear_managed_dict", clear_managed_dict, METH_O, NULL}, diff --git a/Python/sysmodule.c b/Python/sysmodule.c index c116c40538a2..7510be538caa 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -950,10 +950,6 @@ call_trampoline(PyThreadState *tstate, PyObject* callback, PyObject *result = _PyObject_FastCallTstate(tstate, callback, stack, 3); PyFrame_LocalsToFast(frame, 1); - if (result == NULL) { - PyTraceBack_Here(frame); - } - return result; } From webhook-mailer at python.org Fri May 19 09:23:09 2023 From: webhook-mailer at python.org (ambv) Date: Fri, 19 May 2023 13:23:09 -0000 Subject: [Python-checkins] gh-96522: Fix deadlock in pty.spawn (#96639) Message-ID: <mailman.447.1684502591.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9c5aa8967bd7c1b02fb1da055c6b3afcccbbb251 commit: 9c5aa8967bd7c1b02fb1da055c6b3afcccbbb251 branch: main author: Youfu Zhang <1315097+zhangyoufu at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-19T13:22:43Z summary: gh-96522: Fix deadlock in pty.spawn (#96639) files: A Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst M Lib/pty.py M Lib/test/test_pty.py M Misc/ACKS diff --git a/Lib/pty.py b/Lib/pty.py index 6571050886bd..1d97994abef3 100644 --- a/Lib/pty.py +++ b/Lib/pty.py @@ -115,12 +115,6 @@ def fork(): # Parent and child process. return pid, master_fd -def _writen(fd, data): - """Write all the data to a descriptor.""" - while data: - n = os.write(fd, data) - data = data[n:] - def _read(fd): """Default read function.""" return os.read(fd, 1024) @@ -130,9 +124,42 @@ def _copy(master_fd, master_read=_read, stdin_read=_read): Copies pty master -> standard output (master_read) standard input -> pty master (stdin_read)""" - fds = [master_fd, STDIN_FILENO] - while fds: - rfds, _wfds, _xfds = select(fds, [], []) + if os.get_blocking(master_fd): + # If we write more than tty/ndisc is willing to buffer, we may block + # indefinitely. So we set master_fd to non-blocking temporarily during + # the copy operation. + os.set_blocking(master_fd, False) + try: + _copy(master_fd, master_read=master_read, stdin_read=stdin_read) + finally: + # restore blocking mode for backwards compatibility + os.set_blocking(master_fd, True) + return + high_waterlevel = 4096 + stdin_avail = master_fd != STDIN_FILENO + stdout_avail = master_fd != STDOUT_FILENO + i_buf = b'' + o_buf = b'' + while 1: + rfds = [] + wfds = [] + if stdin_avail and len(i_buf) < high_waterlevel: + rfds.append(STDIN_FILENO) + if stdout_avail and len(o_buf) < high_waterlevel: + rfds.append(master_fd) + if stdout_avail and len(o_buf) > 0: + wfds.append(STDOUT_FILENO) + if len(i_buf) > 0: + wfds.append(master_fd) + + rfds, wfds, _xfds = select(rfds, wfds, []) + + if STDOUT_FILENO in wfds: + try: + n = os.write(STDOUT_FILENO, o_buf) + o_buf = o_buf[n:] + except OSError: + stdout_avail = False if master_fd in rfds: # Some OSes signal EOF by returning an empty byte string, @@ -144,15 +171,18 @@ def _copy(master_fd, master_read=_read, stdin_read=_read): if not data: # Reached EOF. return # Assume the child process has exited and is # unreachable, so we clean up. - else: - os.write(STDOUT_FILENO, data) + o_buf += data + + if master_fd in wfds: + n = os.write(master_fd, i_buf) + i_buf = i_buf[n:] - if STDIN_FILENO in rfds: + if stdin_avail and STDIN_FILENO in rfds: data = stdin_read(STDIN_FILENO) if not data: - fds.remove(STDIN_FILENO) + stdin_avail = False else: - _writen(master_fd, data) + i_buf += data def spawn(argv, master_read=_read, stdin_read=_read): """Create a spawned process.""" diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index c723bb362c5d..c9c2b42861c6 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -312,8 +312,8 @@ def setUp(self): self.orig_pty_waitpid = pty.waitpid self.fds = [] # A list of file descriptors to close. self.files = [] - self.select_rfds_lengths = [] - self.select_rfds_results = [] + self.select_input = [] + self.select_output = [] self.tcsetattr_mode_setting = None def tearDown(self): @@ -350,8 +350,8 @@ def _socketpair(self): def _mock_select(self, rfds, wfds, xfds): # This will raise IndexError when no more expected calls exist. - self.assertEqual(self.select_rfds_lengths.pop(0), len(rfds)) - return self.select_rfds_results.pop(0), [], [] + self.assertEqual((rfds, wfds, xfds), self.select_input.pop(0)) + return self.select_output.pop(0) def _make_mock_fork(self, pid): def mock_fork(): @@ -374,11 +374,13 @@ def test__copy_to_each(self): os.write(masters[1], b'from master') os.write(write_to_stdin_fd, b'from stdin') - # Expect two select calls, the last one will cause IndexError + # Expect three select calls, the last one will cause IndexError pty.select = self._mock_select - self.select_rfds_lengths.append(2) - self.select_rfds_results.append([mock_stdin_fd, masters[0]]) - self.select_rfds_lengths.append(2) + self.select_input.append(([mock_stdin_fd, masters[0]], [], [])) + self.select_output.append(([mock_stdin_fd, masters[0]], [], [])) + self.select_input.append(([mock_stdin_fd, masters[0]], [mock_stdout_fd, masters[0]], [])) + self.select_output.append(([], [mock_stdout_fd, masters[0]], [])) + self.select_input.append(([mock_stdin_fd, masters[0]], [], [])) with self.assertRaises(IndexError): pty._copy(masters[0]) diff --git a/Misc/ACKS b/Misc/ACKS index 42ec059a7c4e..be8755637ffa 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -2060,6 +2060,7 @@ Yuxiao Zeng Uwe Zessin Cheng Zhang George Zhang +Youfu Zhang Charlie Zhao Kai Zhu Tarek Ziad? diff --git a/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst b/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst new file mode 100644 index 000000000000..12ed52f97129 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst @@ -0,0 +1 @@ +Fix potential deadlock in pty.spawn() From webhook-mailer at python.org Fri May 19 09:30:10 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 19 May 2023 13:30:10 -0000 Subject: [Python-checkins] Improve readability of `typing._ProtocolMeta.__instancecheck__` (#104649) Message-ID: <mailman.448.1684503011.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a412fc58ccb8c6739b179137321cbbb1abebcd2f commit: a412fc58ccb8c6739b179137321cbbb1abebcd2f branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-19T14:30:02+01:00 summary: Improve readability of `typing._ProtocolMeta.__instancecheck__` (#104649) files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index b60eb94351f9..96393d6a0281 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1801,9 +1801,11 @@ def __subclasscheck__(cls, other): def __instancecheck__(cls, instance): # We need this method for situations where attributes are # assigned in __init__. - is_protocol_cls = getattr(cls, "_is_protocol", False) + if not getattr(cls, "_is_protocol", False): + # i.e., it's a concrete subclass of a protocol + return super().__instancecheck__(instance) + if ( - is_protocol_cls and not getattr(cls, '_is_runtime_protocol', False) and not _allow_reckless_class_checks(depth=2) ): @@ -1813,17 +1815,16 @@ def __instancecheck__(cls, instance): if super().__instancecheck__(instance): return True - if is_protocol_cls: - getattr_static = _lazy_load_getattr_static() - for attr in cls.__protocol_attrs__: - try: - val = getattr_static(instance, attr) - except AttributeError: - break - if val is None and callable(getattr(cls, attr, None)): - break - else: - return True + getattr_static = _lazy_load_getattr_static() + for attr in cls.__protocol_attrs__: + try: + val = getattr_static(instance, attr) + except AttributeError: + break + if val is None and callable(getattr(cls, attr, None)): + break + else: + return True return False From webhook-mailer at python.org Fri May 19 09:50:41 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 19 May 2023 13:50:41 -0000 Subject: [Python-checkins] gh-103921: Rename "type" header in argparse docs (#104654) Message-ID: <mailman.449.1684504243.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ab8f54668b0c49186f1da8e127e303ca73220017 commit: ab8f54668b0c49186f1da8e127e303ca73220017 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-19T06:50:34-07:00 summary: gh-103921: Rename "type" header in argparse docs (#104654) This allows :keyword:`type` to link to docs for the new `type` statement (being written in gh-104642) instead of to this header in the argparse docs. files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 33e367f3ccda..fbffa71d2007 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -57,20 +57,20 @@ the extracted data in a :class:`argparse.Namespace` object:: Quick Links for add_argument() ------------------------------ -====================== =========================================================== ========================================================================================================================== -Name Description Values -====================== =========================================================== ========================================================================================================================== -action_ Specify how an argument should be handled ``'store'``, ``'store_const'``, ``'store_true'``, ``'append'``, ``'append_const'``, ``'count'``, ``'help'``, ``'version'`` -choices_ Limit values to a specific set of choices ``['foo', 'bar']``, ``range(1, 10)``, or :class:`~collections.abc.Container` instance -const_ Store a constant value -default_ Default value used when an argument is not provided Defaults to ``None`` -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 ``'+'`` -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 -====================== =========================================================== ========================================================================================================================== +============================ =========================================================== ========================================================================================================================== +Name Description Values +============================ =========================================================== ========================================================================================================================== +action_ Specify how an argument should be handled ``'store'``, ``'store_const'``, ``'store_true'``, ``'append'``, ``'append_const'``, ``'count'``, ``'help'``, ``'version'`` +choices_ Limit values to a specific set of choices ``['foo', 'bar']``, ``range(1, 10)``, or :class:`~collections.abc.Container` instance +const_ Store a constant value +default_ Default value used when an argument is not provided Defaults to ``None`` +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 ``'+'`` +required_ Indicate whether an argument is required or optional ``True`` or ``False`` +:ref:`type <argparse-type>` Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function +============================ =========================================================== ========================================================================================================================== Example @@ -1132,7 +1132,7 @@ command-line argument was not present:: Namespace(foo='1') -.. _type: +.. _argparse-type: type ^^^^ From webhook-mailer at python.org Fri May 19 09:57:59 2023 From: webhook-mailer at python.org (ambv) Date: Fri, 19 May 2023 13:57:59 -0000 Subject: [Python-checkins] [3.11] gh-85984: Utilize new "winsize" functions from termios in pty tests. (GH-101831) (#104652) Message-ID: <mailman.450.1684504681.13550.python-checkins@python.org> https://github.com/python/cpython/commit/aaeaf01cc29fed595c7ebfbf05e1d9f7a913bdb4 commit: aaeaf01cc29fed595c7ebfbf05e1d9f7a913bdb4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-19T15:57:52+02:00 summary: [3.11] gh-85984: Utilize new "winsize" functions from termios in pty tests. (GH-101831) (#104652) Utilize new functions termios.tcgetwinsize() and termios.tcsetwinsize in test_pty.py. (cherry picked from commit da2fb9264315dc30ac3012b4dbf5ba76d3f34433) Co-authored-by: Soumendra Ganguly <67527439+8vasu at users.noreply.github.com> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst M Lib/test/test_pty.py diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index fa0dbcc16f3c..c723bb362c5d 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -3,6 +3,8 @@ # Skip these tests if termios or fcntl are not available import_module('termios') +# fcntl is a proxy for not being one of the wasm32 platforms even though we +# don't use this module... a proper check for what crashes those is needed. import_module("fcntl") import errno @@ -15,20 +17,12 @@ import socket import io # readline import unittest - -import struct -import fcntl import warnings TEST_STRING_1 = b"I wish to buy a fish license.\n" TEST_STRING_2 = b"For my pet fish, Eric.\n" -try: - _TIOCGWINSZ = tty.TIOCGWINSZ - _TIOCSWINSZ = tty.TIOCSWINSZ - _HAVE_WINSZ = True -except AttributeError: - _HAVE_WINSZ = False +_HAVE_WINSZ = hasattr(tty, "TIOCGWINSZ") and hasattr(tty, "TIOCSWINSZ") if verbose: def debug(msg): @@ -82,14 +76,6 @@ def expectedFailureIfStdinIsTTY(fun): pass return fun -def _get_term_winsz(fd): - s = struct.pack("HHHH", 0, 0, 0, 0) - return fcntl.ioctl(fd, _TIOCGWINSZ, s) - -def _set_term_winsz(fd, winsz): - fcntl.ioctl(fd, _TIOCSWINSZ, winsz) - - # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing # because pty code is not too portable. class PtyTest(unittest.TestCase): @@ -105,18 +91,14 @@ def setUp(self): self.addCleanup(signal.alarm, 0) signal.alarm(10) - # Save original stdin window size - self.stdin_rows = None - self.stdin_cols = None + # Save original stdin window size. + self.stdin_dim = None if _HAVE_WINSZ: try: - stdin_dim = os.get_terminal_size(pty.STDIN_FILENO) - self.stdin_rows = stdin_dim.lines - self.stdin_cols = stdin_dim.columns - old_stdin_winsz = struct.pack("HHHH", self.stdin_rows, - self.stdin_cols, 0, 0) - self.addCleanup(_set_term_winsz, pty.STDIN_FILENO, old_stdin_winsz) - except OSError: + self.stdin_dim = tty.tcgetwinsize(pty.STDIN_FILENO) + self.addCleanup(tty.tcsetwinsize, pty.STDIN_FILENO, + self.stdin_dim) + except tty.error: pass def handle_sig(self, sig, frame): @@ -131,41 +113,40 @@ def test_openpty(self): try: mode = tty.tcgetattr(pty.STDIN_FILENO) except tty.error: - # not a tty or bad/closed fd + # Not a tty or bad/closed fd. debug("tty.tcgetattr(pty.STDIN_FILENO) failed") mode = None - new_stdin_winsz = None - if self.stdin_rows is not None and self.stdin_cols is not None: + new_dim = None + if self.stdin_dim: try: # Modify pty.STDIN_FILENO window size; we need to # check if pty.openpty() is able to set pty slave # window size accordingly. - debug("Setting pty.STDIN_FILENO window size") - debug(f"original size: (rows={self.stdin_rows}, cols={self.stdin_cols})") - target_stdin_rows = self.stdin_rows + 1 - target_stdin_cols = self.stdin_cols + 1 - debug(f"target size: (rows={target_stdin_rows}, cols={target_stdin_cols})") - target_stdin_winsz = struct.pack("HHHH", target_stdin_rows, - target_stdin_cols, 0, 0) - _set_term_winsz(pty.STDIN_FILENO, target_stdin_winsz) + debug("Setting pty.STDIN_FILENO window size.") + debug(f"original size: (row, col) = {self.stdin_dim}") + target_dim = (self.stdin_dim[0] + 1, self.stdin_dim[1] + 1) + debug(f"target size: (row, col) = {target_dim}") + tty.tcsetwinsize(pty.STDIN_FILENO, target_dim) # Were we able to set the window size # of pty.STDIN_FILENO successfully? - new_stdin_winsz = _get_term_winsz(pty.STDIN_FILENO) - self.assertEqual(new_stdin_winsz, target_stdin_winsz, + new_dim = tty.tcgetwinsize(pty.STDIN_FILENO) + self.assertEqual(new_dim, target_dim, "pty.STDIN_FILENO window size unchanged") except OSError: - warnings.warn("Failed to set pty.STDIN_FILENO window size") + warnings.warn("Failed to set pty.STDIN_FILENO window size.") pass try: debug("Calling pty.openpty()") try: - master_fd, slave_fd = pty.openpty(mode, new_stdin_winsz) + master_fd, slave_fd, slave_name = pty.openpty(mode, new_dim, + True) except TypeError: master_fd, slave_fd = pty.openpty() - debug(f"Got master_fd '{master_fd}', slave_fd '{slave_fd}'") + slave_name = None + debug(f"Got {master_fd=}, {slave_fd=}, {slave_name=}") except OSError: # " An optional feature could not be imported " ... ? raise unittest.SkipTest("Pseudo-terminals (seemingly) not functional.") @@ -181,8 +162,8 @@ def test_openpty(self): if mode: self.assertEqual(tty.tcgetattr(slave_fd), mode, "openpty() failed to set slave termios") - if new_stdin_winsz: - self.assertEqual(_get_term_winsz(slave_fd), new_stdin_winsz, + if new_dim: + self.assertEqual(tty.tcgetwinsize(slave_fd), new_dim, "openpty() failed to set slave window size") # Ensure the fd is non-blocking in case there's nothing to read. @@ -367,9 +348,8 @@ def _socketpair(self): self.files.extend(socketpair) return socketpair - def _mock_select(self, rfds, wfds, xfds, timeout=0): + def _mock_select(self, rfds, wfds, xfds): # This will raise IndexError when no more expected calls exist. - # This ignores the timeout self.assertEqual(self.select_rfds_lengths.pop(0), len(rfds)) return self.select_rfds_results.pop(0), [], [] @@ -409,28 +389,6 @@ def test__copy_to_each(self): self.assertEqual(os.read(read_from_stdout_fd, 20), b'from master') self.assertEqual(os.read(masters[1], 20), b'from stdin') - def test__copy_eof_on_all(self): - """Test the empty read EOF case on both master_fd and stdin.""" - read_from_stdout_fd, mock_stdout_fd = self._pipe() - pty.STDOUT_FILENO = mock_stdout_fd - mock_stdin_fd, write_to_stdin_fd = self._pipe() - pty.STDIN_FILENO = mock_stdin_fd - socketpair = self._socketpair() - masters = [s.fileno() for s in socketpair] - - socketpair[1].close() - os.close(write_to_stdin_fd) - - pty.select = self._mock_select - self.select_rfds_lengths.append(2) - self.select_rfds_results.append([mock_stdin_fd, masters[0]]) - # We expect that both fds were removed from the fds list as they - # both encountered an EOF before the second select call. - self.select_rfds_lengths.append(0) - - # We expect the function to return without error. - self.assertEqual(pty._copy(masters[0]), None) - def test__restore_tty_mode_normal_return(self): """Test that spawn resets the tty mode no when _copy returns normally.""" diff --git a/Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst b/Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst new file mode 100644 index 000000000000..402f99ea6c6e --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst @@ -0,0 +1 @@ +Utilize new "winsize" functions from termios in pty tests. From webhook-mailer at python.org Fri May 19 10:31:16 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 19 May 2023 14:31:16 -0000 Subject: [Python-checkins] gh-104640: Disallow walrus in comprehension within type scopes (#104641) Message-ID: <mailman.451.1684506677.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8a8853af24b41a73653d07dcc2f44d05b10e0673 commit: 8a8853af24b41a73653d07dcc2f44d05b10e0673 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-19T07:31:09-07:00 summary: gh-104640: Disallow walrus in comprehension within type scopes (#104641) files: M Lib/test/test_type_params.py M Python/symtable.c diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 466e3bd43a68..d4f5de573f51 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -136,6 +136,9 @@ def test_disallowed_expressions(self): check_syntax_error(self, "class X[T: (y := 3)]: pass") check_syntax_error(self, "class X[T](y := Sequence[T]): pass") check_syntax_error(self, "def f[T](y: (x := Sequence[T])): pass") + check_syntax_error(self, "class X[T]([(x := 3) for _ in range(2)] and B): pass") + check_syntax_error(self, "def f[T: [(x := 3) for _ in range(2)]](): pass") + check_syntax_error(self, "type T = [(x := 3) for _ in range(2)]") class TypeParamsNonlocalTest(unittest.TestCase): diff --git a/Python/symtable.c b/Python/symtable.c index bd523f0cdd74..73cbb2b8e995 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -35,6 +35,15 @@ #define NAMED_EXPR_COMP_IN_CLASS \ "assignment expression within a comprehension cannot be used in a class body" +#define NAMED_EXPR_COMP_IN_TYPEVAR_BOUND \ +"assignment expression within a comprehension cannot be used in a TypeVar bound" + +#define NAMED_EXPR_COMP_IN_TYPEALIAS \ +"assignment expression within a comprehension cannot be used in a type alias" + +#define NAMED_EXPR_COMP_IN_TYPEPARAM \ +"assignment expression within a comprehension cannot be used within the definition of a generic" + #define NAMED_EXPR_COMP_CONFLICT \ "assignment expression cannot rebind comprehension iteration variable '%U'" @@ -1857,7 +1866,7 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e) } /* If we find a FunctionBlock entry, add as GLOBAL/LOCAL or NONLOCAL/LOCAL */ - if (_PyST_IsFunctionLike(ste)) { + if (ste->ste_type == FunctionBlock) { long target_in_scope = _PyST_GetSymbol(ste, target_name); if (target_in_scope & DEF_GLOBAL) { if (!symtable_add_def(st, target_name, DEF_GLOBAL, LOCATION(e))) @@ -1880,9 +1889,27 @@ symtable_extend_namedexpr_scope(struct symtable *st, expr_ty e) return symtable_add_def_helper(st, target_name, DEF_GLOBAL, ste, LOCATION(e)); } - /* Disallow usage in ClassBlock */ - if (ste->ste_type == ClassBlock) { - PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_CLASS); + /* Disallow usage in ClassBlock and type scopes */ + if (ste->ste_type == ClassBlock || + ste->ste_type == TypeParamBlock || + ste->ste_type == TypeAliasBlock || + ste->ste_type == TypeVarBoundBlock) { + switch (ste->ste_type) { + case ClassBlock: + PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_CLASS); + break; + case TypeParamBlock: + PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEPARAM); + break; + case TypeAliasBlock: + PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEALIAS); + break; + case TypeVarBoundBlock: + PyErr_Format(PyExc_SyntaxError, NAMED_EXPR_COMP_IN_TYPEVAR_BOUND); + break; + default: + Py_UNREACHABLE(); + } PyErr_RangedSyntaxLocationObject(st->st_filename, e->lineno, e->col_offset + 1, From webhook-mailer at python.org Fri May 19 10:54:57 2023 From: webhook-mailer at python.org (ambv) Date: Fri, 19 May 2023 14:54:57 -0000 Subject: [Python-checkins] [3.11] gh-96522: Fix deadlock in pty.spawn (GH-96639) (#104655) Message-ID: <mailman.452.1684508098.13550.python-checkins@python.org> https://github.com/python/cpython/commit/702ce8773691d45094f7131e26edc43505121239 commit: 702ce8773691d45094f7131e26edc43505121239 branch: 3.11 author: ?ukasz Langa <lukasz at langa.pl> committer: ambv <lukasz at langa.pl> date: 2023-05-19T16:54:50+02:00 summary: [3.11] gh-96522: Fix deadlock in pty.spawn (GH-96639) (#104655) (cherry picked from commit 9c5aa8967bd7c1b02fb1da055c6b3afcccbbb251) Co-authored-by: Youfu Zhang <1315097+zhangyoufu at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst M Lib/pty.py M Lib/test/test_pty.py M Misc/ACKS diff --git a/Lib/pty.py b/Lib/pty.py index 8d8ce40df541..fefb63abfb04 100644 --- a/Lib/pty.py +++ b/Lib/pty.py @@ -121,12 +121,6 @@ def fork(): # Parent and child process. return pid, master_fd -def _writen(fd, data): - """Write all the data to a descriptor.""" - while data: - n = os.write(fd, data) - data = data[n:] - def _read(fd): """Default read function.""" return os.read(fd, 1024) @@ -136,9 +130,42 @@ def _copy(master_fd, master_read=_read, stdin_read=_read): Copies pty master -> standard output (master_read) standard input -> pty master (stdin_read)""" - fds = [master_fd, STDIN_FILENO] - while fds: - rfds, _wfds, _xfds = select(fds, [], []) + if os.get_blocking(master_fd): + # If we write more than tty/ndisc is willing to buffer, we may block + # indefinitely. So we set master_fd to non-blocking temporarily during + # the copy operation. + os.set_blocking(master_fd, False) + try: + _copy(master_fd, master_read=master_read, stdin_read=stdin_read) + finally: + # restore blocking mode for backwards compatibility + os.set_blocking(master_fd, True) + return + high_waterlevel = 4096 + stdin_avail = master_fd != STDIN_FILENO + stdout_avail = master_fd != STDOUT_FILENO + i_buf = b'' + o_buf = b'' + while 1: + rfds = [] + wfds = [] + if stdin_avail and len(i_buf) < high_waterlevel: + rfds.append(STDIN_FILENO) + if stdout_avail and len(o_buf) < high_waterlevel: + rfds.append(master_fd) + if stdout_avail and len(o_buf) > 0: + wfds.append(STDOUT_FILENO) + if len(i_buf) > 0: + wfds.append(master_fd) + + rfds, wfds, _xfds = select(rfds, wfds, []) + + if STDOUT_FILENO in wfds: + try: + n = os.write(STDOUT_FILENO, o_buf) + o_buf = o_buf[n:] + except OSError: + stdout_avail = False if master_fd in rfds: # Some OSes signal EOF by returning an empty byte string, @@ -150,15 +177,18 @@ def _copy(master_fd, master_read=_read, stdin_read=_read): if not data: # Reached EOF. return # Assume the child process has exited and is # unreachable, so we clean up. - else: - os.write(STDOUT_FILENO, data) + o_buf += data + + if master_fd in wfds: + n = os.write(master_fd, i_buf) + i_buf = i_buf[n:] - if STDIN_FILENO in rfds: + if stdin_avail and STDIN_FILENO in rfds: data = stdin_read(STDIN_FILENO) if not data: - fds.remove(STDIN_FILENO) + stdin_avail = False else: - _writen(master_fd, data) + i_buf += data def spawn(argv, master_read=_read, stdin_read=_read): """Create a spawned process.""" diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py index c723bb362c5d..c9c2b42861c6 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py @@ -312,8 +312,8 @@ def setUp(self): self.orig_pty_waitpid = pty.waitpid self.fds = [] # A list of file descriptors to close. self.files = [] - self.select_rfds_lengths = [] - self.select_rfds_results = [] + self.select_input = [] + self.select_output = [] self.tcsetattr_mode_setting = None def tearDown(self): @@ -350,8 +350,8 @@ def _socketpair(self): def _mock_select(self, rfds, wfds, xfds): # This will raise IndexError when no more expected calls exist. - self.assertEqual(self.select_rfds_lengths.pop(0), len(rfds)) - return self.select_rfds_results.pop(0), [], [] + self.assertEqual((rfds, wfds, xfds), self.select_input.pop(0)) + return self.select_output.pop(0) def _make_mock_fork(self, pid): def mock_fork(): @@ -374,11 +374,13 @@ def test__copy_to_each(self): os.write(masters[1], b'from master') os.write(write_to_stdin_fd, b'from stdin') - # Expect two select calls, the last one will cause IndexError + # Expect three select calls, the last one will cause IndexError pty.select = self._mock_select - self.select_rfds_lengths.append(2) - self.select_rfds_results.append([mock_stdin_fd, masters[0]]) - self.select_rfds_lengths.append(2) + self.select_input.append(([mock_stdin_fd, masters[0]], [], [])) + self.select_output.append(([mock_stdin_fd, masters[0]], [], [])) + self.select_input.append(([mock_stdin_fd, masters[0]], [mock_stdout_fd, masters[0]], [])) + self.select_output.append(([], [mock_stdout_fd, masters[0]], [])) + self.select_input.append(([mock_stdin_fd, masters[0]], [], [])) with self.assertRaises(IndexError): pty._copy(masters[0]) diff --git a/Misc/ACKS b/Misc/ACKS index 288985c7edde..d0f32281d899 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -2034,6 +2034,7 @@ Yuxiao Zeng Uwe Zessin Cheng Zhang George Zhang +Youfu Zhang Charlie Zhao Kai Zhu Tarek Ziad? diff --git a/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst b/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst new file mode 100644 index 000000000000..12ed52f97129 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst @@ -0,0 +1 @@ +Fix potential deadlock in pty.spawn() From webhook-mailer at python.org Fri May 19 11:16:49 2023 From: webhook-mailer at python.org (carljm) Date: Fri, 19 May 2023 15:16:49 -0000 Subject: [Python-checkins] gh-104602: Add additional test for listcomp with lambda (#104639) Message-ID: <mailman.453.1684509410.13550.python-checkins@python.org> https://github.com/python/cpython/commit/dbe171e6098fbb96beed81db2c34f6428109e005 commit: dbe171e6098fbb96beed81db2c34f6428109e005 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: carljm <carl at oddbird.net> date: 2023-05-19T09:16:39-06:00 summary: gh-104602: Add additional test for listcomp with lambda (#104639) This threw a SystemError before #104603. Adding a separate test because this was a different failure mode than the other two new tests from #104603, both of which used to segfault. files: M Lib/test/test_listcomps.py diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 185658ab5a4c..c2cf058c321f 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -510,6 +510,16 @@ def test_nested_listcomp_in_lambda(self): """ self._check_in_scopes(code, {"z": 1, "out": [(3, 2, 1)]}) + def test_lambda_in_iter(self): + code = """ + (func, c), = [(a, b) for b in [1] for a in [lambda : a]] + d = func() + assert d is func + # must use "a" in this scope + e = a if False else None + """ + self._check_in_scopes(code, {"c": 1, "e": None}) + def test_assign_to_comp_iter_var_in_outer_function(self): code = """ a = [1 for a in [0]] From webhook-mailer at python.org Fri May 19 12:04:57 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 19 May 2023 16:04:57 -0000 Subject: [Python-checkins] gh-104600: Make type.__type_params__ writable (#104634) Message-ID: <mailman.454.1684512298.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8f1f3b9abdaa3e9d19aad22d6c310eb1f05ae5c2 commit: 8f1f3b9abdaa3e9d19aad22d6c310eb1f05ae5c2 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-19T09:04:47-07:00 summary: gh-104600: Make type.__type_params__ writable (#104634) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Lib/test/test_builtin.py M Lib/test/test_type_params.py M Lib/test/test_typing.py M Objects/typeobject.c diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 821710a7fa32..1257b529038a 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -18,6 +18,7 @@ import sys import traceback import types +import typing import unittest import warnings from contextlib import ExitStack @@ -2485,6 +2486,17 @@ def test_type_qualname(self): A.__qualname__ = b'B' self.assertEqual(A.__qualname__, 'D.E') + def test_type_typeparams(self): + class A[T]: + pass + T, = A.__type_params__ + self.assertIsInstance(T, typing.TypeVar) + A.__type_params__ = "whatever" + self.assertEqual(A.__type_params__, "whatever") + with self.assertRaises(TypeError): + del A.__type_params__ + self.assertEqual(A.__type_params__, "whatever") + def test_type_doc(self): for doc in 'x', '\xc4', '\U0001f40d', 'x\x00y', b'x', 42, None: A = type('A', (), {'__doc__': doc}) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index d4f5de573f51..7b7b6122c028 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -816,10 +816,11 @@ def test_typeparams_dunder_class_03(self): class ClassA[A](): pass ClassA.__type_params__ = () + params = ClassA.__type_params__ """ - with self.assertRaisesRegex(AttributeError, "attribute '__type_params__' of 'type' objects is not writable"): - run_code(code) + ns = run_code(code) + self.assertEqual(ns["params"], ()) def test_typeparams_dunder_function_01(self): def outer[A, B](): diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 450c85967dd7..6459fa3eb96a 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -6810,6 +6810,19 @@ class Y(Generic[T], NamedTuple): with self.assertRaises(TypeError): G[int, str] + def test_generic_pep695(self): + class X[T](NamedTuple): + x: T + T, = X.__type_params__ + self.assertIsInstance(T, TypeVar) + self.assertEqual(T.__name__, 'T') + self.assertEqual(X.__bases__, (tuple, Generic)) + self.assertEqual(X.__orig_bases__, (NamedTuple, Generic[T])) + self.assertEqual(X.__mro__, (X, tuple, Generic, object)) + self.assertEqual(X.__parameters__, (T,)) + self.assertEqual(X[str].__args__, (str,)) + self.assertEqual(X[str].__parameters__, ()) + def test_non_generic_subscript(self): # For backward compatibility, subscription works # on arbitrary NamedTuple types. @@ -7220,6 +7233,20 @@ class FooBarGeneric(BarGeneric[int]): {'a': typing.Optional[T], 'b': int, 'c': str} ) + def test_pep695_generic_typeddict(self): + class A[T](TypedDict): + a: T + + T, = A.__type_params__ + self.assertIsInstance(T, TypeVar) + self.assertEqual(T.__name__, 'T') + self.assertEqual(A.__bases__, (Generic, dict)) + self.assertEqual(A.__orig_bases__, (TypedDict, Generic[T])) + self.assertEqual(A.__mro__, (A, Generic, dict, object)) + self.assertEqual(A.__parameters__, (T,)) + self.assertEqual(A[str].__parameters__, ()) + self.assertEqual(A[str].__args__, (str,)) + def test_generic_inheritance(self): class A(TypedDict, Generic[T]): a: T diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 624dc63ce82c..2fbcafe91aad 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1460,18 +1460,6 @@ type_get_annotations(PyTypeObject *type, void *context) return annotations; } -static PyObject * -type_get_type_params(PyTypeObject *type, void *context) -{ - PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__)); - - if (params) { - return Py_NewRef(params); - } - - return PyTuple_New(0); -} - static int type_set_annotations(PyTypeObject *type, PyObject *value, void *context) { @@ -1502,6 +1490,34 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context) return result; } +static PyObject * +type_get_type_params(PyTypeObject *type, void *context) +{ + PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__)); + + if (params) { + return Py_NewRef(params); + } + + return PyTuple_New(0); +} + +static int +type_set_type_params(PyTypeObject *type, PyObject *value, void *context) +{ + if (!check_set_special_type_attr(type, value, "__type_params__")) { + return -1; + } + + PyObject *dict = lookup_tp_dict(type); + int result = PyDict_SetItem(dict, &_Py_ID(__type_params__), value); + + if (result == 0) { + PyType_Modified(type); + } + return result; +} + /*[clinic input] type.__instancecheck__ -> bool @@ -1548,7 +1564,7 @@ static PyGetSetDef type_getsets[] = { {"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL}, {"__text_signature__", (getter)type_get_text_signature, NULL, NULL}, {"__annotations__", (getter)type_get_annotations, (setter)type_set_annotations, NULL}, - {"__type_params__", (getter)type_get_type_params, NULL, NULL}, + {"__type_params__", (getter)type_get_type_params, (setter)type_set_type_params, NULL}, {0} }; From webhook-mailer at python.org Fri May 19 12:24:04 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 19 May 2023 16:24:04 -0000 Subject: [Python-checkins] gh-104645: fix error handling in marshal tests (#104646) Message-ID: <mailman.455.1684513445.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ac56a854b418d35ad3838f3072604227dc718fca commit: ac56a854b418d35ad3838f3072604227dc718fca branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-19T17:23:57+01:00 summary: gh-104645: fix error handling in marshal tests (#104646) files: M Modules/_testcapimodule.c diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 1be1dd617893..aff09aac80c6 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1808,10 +1808,9 @@ pymarshal_write_long_to_file(PyObject* self, PyObject *args) } PyMarshal_WriteLongToFile(value, fp, version); + assert(!PyErr_Occurred()); fclose(fp); - if (PyErr_Occurred()) - return NULL; Py_RETURN_NONE; } @@ -1834,10 +1833,9 @@ pymarshal_write_object_to_file(PyObject* self, PyObject *args) } PyMarshal_WriteObjectToFile(obj, fp, version); + assert(!PyErr_Occurred()); fclose(fp); - if (PyErr_Occurred()) - return NULL; Py_RETURN_NONE; } @@ -1895,48 +1893,46 @@ pymarshal_read_long_from_file(PyObject* self, PyObject *args) static PyObject* pymarshal_read_last_object_from_file(PyObject* self, PyObject *args) { - PyObject *obj; - long pos; PyObject *filename; - FILE *fp; - if (!PyArg_ParseTuple(args, "O:pymarshal_read_last_object_from_file", &filename)) return NULL; - fp = _Py_fopen_obj(filename, "rb"); + FILE *fp = _Py_fopen_obj(filename, "rb"); if (fp == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - obj = PyMarshal_ReadLastObjectFromFile(fp); - pos = ftell(fp); + PyObject *obj = PyMarshal_ReadLastObjectFromFile(fp); + long pos = ftell(fp); fclose(fp); + if (obj == NULL) { + return NULL; + } return Py_BuildValue("Nl", obj, pos); } static PyObject* pymarshal_read_object_from_file(PyObject* self, PyObject *args) { - PyObject *obj; - long pos; PyObject *filename; - FILE *fp; - if (!PyArg_ParseTuple(args, "O:pymarshal_read_object_from_file", &filename)) return NULL; - fp = _Py_fopen_obj(filename, "rb"); + FILE *fp = _Py_fopen_obj(filename, "rb"); if (fp == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - obj = PyMarshal_ReadObjectFromFile(fp); - pos = ftell(fp); + PyObject *obj = PyMarshal_ReadObjectFromFile(fp); + long pos = ftell(fp); fclose(fp); + if (obj == NULL) { + return NULL; + } return Py_BuildValue("Nl", obj, pos); } From webhook-mailer at python.org Fri May 19 12:45:04 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 19 May 2023 16:45:04 -0000 Subject: [Python-checkins] gh-92248: Deprecate `type`, `choices`, `metavar` parameters of `argparse.BooleanOptionalAction` (#103678) Message-ID: <mailman.456.1684514705.13550.python-checkins@python.org> https://github.com/python/cpython/commit/27a7d5e1cd5b937d5f164fce572d442672f53065 commit: 27a7d5e1cd5b937d5f164fce572d442672f53065 branch: main author: Nikita Sobolev <mail at sobolevn.me> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-19T16:44:43Z summary: gh-92248: Deprecate `type`, `choices`, `metavar` parameters of `argparse.BooleanOptionalAction` (#103678) Co-authored-by: Kirill <80244920+Eclips4 at users.noreply.github.com> Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: A Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst M Doc/whatsnew/3.12.rst M Lib/argparse.py M Lib/test/test_argparse.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 25f0a4c3ca26..8a0a59ba7301 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -870,6 +870,11 @@ Pending Removal in Python 3.14 * The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, and will be removed in 3.14. +* The *type*, *choices*, and *metavar* parameters + of :class:`!argparse.BooleanOptionalAction` are deprecated + and will be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`92248`.) + * :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` now raise :exc:`DeprecationWarning`; use :func:`importlib.util.find_spec` instead. diff --git a/Lib/argparse.py b/Lib/argparse.py index f5f44ff02c0d..543d9944f9ed 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -883,16 +883,19 @@ def __call__(self, parser, namespace, values, option_string=None): raise NotImplementedError(_('.__call__() not defined')) +# FIXME: remove together with `BooleanOptionalAction` deprecated arguments. +_deprecated_default = object() + class BooleanOptionalAction(Action): def __init__(self, option_strings, dest, default=None, - type=None, - choices=None, + type=_deprecated_default, + choices=_deprecated_default, required=False, help=None, - metavar=None): + metavar=_deprecated_default): _option_strings = [] for option_string in option_strings: @@ -902,6 +905,24 @@ def __init__(self, option_string = '--no-' + option_string[2:] _option_strings.append(option_string) + # We need `_deprecated` special value to ban explicit arguments that + # match default value. Like: + # parser.add_argument('-f', action=BooleanOptionalAction, type=int) + for field_name in ('type', 'choices', 'metavar'): + if locals()[field_name] is not _deprecated_default: + warnings._deprecated( + field_name, + "{name!r} is deprecated as of Python 3.12 and will be " + "removed in Python {remove}.", + remove=(3, 14)) + + if type is _deprecated_default: + type = None + if choices is _deprecated_default: + choices = None + if metavar is _deprecated_default: + metavar = None + super().__init__( option_strings=_option_strings, dest=dest, diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 0659d244d356..3a62a16cee31 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -765,6 +765,49 @@ def test_const(self): self.assertIn("got an unexpected keyword argument 'const'", str(cm.exception)) + def test_deprecated_init_kw(self): + # See gh-92248 + parser = argparse.ArgumentParser() + + with self.assertWarns(DeprecationWarning): + parser.add_argument( + '-a', + action=argparse.BooleanOptionalAction, + type=None, + ) + with self.assertWarns(DeprecationWarning): + parser.add_argument( + '-b', + action=argparse.BooleanOptionalAction, + type=bool, + ) + + with self.assertWarns(DeprecationWarning): + parser.add_argument( + '-c', + action=argparse.BooleanOptionalAction, + metavar=None, + ) + with self.assertWarns(DeprecationWarning): + parser.add_argument( + '-d', + action=argparse.BooleanOptionalAction, + metavar='d', + ) + + with self.assertWarns(DeprecationWarning): + parser.add_argument( + '-e', + action=argparse.BooleanOptionalAction, + choices=None, + ) + with self.assertWarns(DeprecationWarning): + parser.add_argument( + '-f', + action=argparse.BooleanOptionalAction, + choices=(), + ) + class TestBooleanOptionalActionRequired(ParserTestCase): """Tests BooleanOptionalAction required""" diff --git a/Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst b/Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst new file mode 100644 index 000000000000..d4a02d829419 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst @@ -0,0 +1,2 @@ +Deprecate ``type``, ``choices``, and ``metavar`` parameters of +``argparse.BooleanOptionalAction``. From webhook-mailer at python.org Fri May 19 12:46:45 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 19 May 2023 16:46:45 -0000 Subject: [Python-checkins] [3.11] gh-104645: fix error handling in marshal tests (GH-104646) (#104663) Message-ID: <mailman.457.1684514806.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d78c3bcf6f4b616db247377eba4eff39119faa94 commit: d78c3bcf6f4b616db247377eba4eff39119faa94 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-19T16:46:37Z summary: [3.11] gh-104645: fix error handling in marshal tests (GH-104646) (#104663) gh-104645: fix error handling in marshal tests (GH-104646) (cherry picked from commit ac56a854b418d35ad3838f3072604227dc718fca) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Modules/_testcapimodule.c diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 6a38cc17bcc7..dff98e6fea92 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4639,10 +4639,9 @@ pymarshal_write_long_to_file(PyObject* self, PyObject *args) } PyMarshal_WriteLongToFile(value, fp, version); + assert(!PyErr_Occurred()); fclose(fp); - if (PyErr_Occurred()) - return NULL; Py_RETURN_NONE; } @@ -4665,10 +4664,9 @@ pymarshal_write_object_to_file(PyObject* self, PyObject *args) } PyMarshal_WriteObjectToFile(obj, fp, version); + assert(!PyErr_Occurred()); fclose(fp); - if (PyErr_Occurred()) - return NULL; Py_RETURN_NONE; } @@ -4726,48 +4724,46 @@ pymarshal_read_long_from_file(PyObject* self, PyObject *args) static PyObject* pymarshal_read_last_object_from_file(PyObject* self, PyObject *args) { - PyObject *obj; - long pos; PyObject *filename; - FILE *fp; - if (!PyArg_ParseTuple(args, "O:pymarshal_read_last_object_from_file", &filename)) return NULL; - fp = _Py_fopen_obj(filename, "rb"); + FILE *fp = _Py_fopen_obj(filename, "rb"); if (fp == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - obj = PyMarshal_ReadLastObjectFromFile(fp); - pos = ftell(fp); + PyObject *obj = PyMarshal_ReadLastObjectFromFile(fp); + long pos = ftell(fp); fclose(fp); + if (obj == NULL) { + return NULL; + } return Py_BuildValue("Nl", obj, pos); } static PyObject* pymarshal_read_object_from_file(PyObject* self, PyObject *args) { - PyObject *obj; - long pos; PyObject *filename; - FILE *fp; - if (!PyArg_ParseTuple(args, "O:pymarshal_read_object_from_file", &filename)) return NULL; - fp = _Py_fopen_obj(filename, "rb"); + FILE *fp = _Py_fopen_obj(filename, "rb"); if (fp == NULL) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } - obj = PyMarshal_ReadObjectFromFile(fp); - pos = ftell(fp); + PyObject *obj = PyMarshal_ReadObjectFromFile(fp); + long pos = ftell(fp); fclose(fp); + if (obj == NULL) { + return NULL; + } return Py_BuildValue("Nl", obj, pos); } From webhook-mailer at python.org Fri May 19 13:46:28 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 19 May 2023 17:46:28 -0000 Subject: [Python-checkins] gh-104659: Consolidate python examples in enum documentation (#104665) Message-ID: <mailman.458.1684518389.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3ac856e69734491ff8423020c700c9ae86ac9a08 commit: 3ac856e69734491ff8423020c700c9ae86ac9a08 branch: main author: Thomas Hisch <t.hisch at gmail.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-19T11:46:20-06:00 summary: gh-104659: Consolidate python examples in enum documentation (#104665) files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 582e06261afd..e9c4f0e2c5f5 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -406,18 +406,18 @@ Data Types with an *IntEnum* member, the resulting value loses its enumeration status. >>> from enum import IntEnum - >>> class Numbers(IntEnum): + >>> class Number(IntEnum): ... ONE = 1 ... TWO = 2 ... THREE = 3 ... - >>> Numbers.THREE - <Numbers.THREE: 3> - >>> Numbers.ONE + Numbers.TWO + >>> Number.THREE + <Number.THREE: 3> + >>> Number.ONE + Number.TWO 3 - >>> Numbers.THREE + 5 + >>> Number.THREE + 5 8 - >>> Numbers.THREE == 3 + >>> Number.THREE == 3 True .. note:: From webhook-mailer at python.org Fri May 19 14:04:11 2023 From: webhook-mailer at python.org (carljm) Date: Fri, 19 May 2023 18:04:11 -0000 Subject: [Python-checkins] [3.11] gh-104615: don't make unsafe swaps in apply_static_swaps (GH-104620). (#104636) Message-ID: <mailman.459.1684519452.13550.python-checkins@python.org> https://github.com/python/cpython/commit/667e4ece9873146a99fc7c017b8a2be76765a715 commit: 667e4ece9873146a99fc7c017b8a2be76765a715 branch: 3.11 author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-19T12:04:04-06:00 summary: [3.11] gh-104615: don't make unsafe swaps in apply_static_swaps (GH-104620). (#104636) (cherry picked from commit 0589c6a4d3d822cace42050198cb9a5e99c879ad) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst M Lib/test/test_compile.py M Python/compile.c diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index c96ae4375df8..c756d43a3cf3 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1064,6 +1064,24 @@ def test_compare_positions(self): with self.subTest(source): self.assertEqual(actual_positions, expected_positions) + def test_apply_static_swaps(self): + def f(x, y): + a, a = x, y + return a + self.assertEqual(f("x", "y"), "y") + + def test_apply_static_swaps_2(self): + def f(x, y, z): + a, b, a = x, y, z + return a + self.assertEqual(f("x", "y", "z"), "z") + + def test_apply_static_swaps_3(self): + def f(x, y, z): + a, a, b = x, y, z + return a + self.assertEqual(f("x", "y", "z"), "y") + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst new file mode 100644 index 000000000000..447291a619dd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst @@ -0,0 +1,2 @@ +Fix wrong ordering of assignments in code like ``a, a = x, y``. Contributed by +Carl Meyer. diff --git a/Python/compile.c b/Python/compile.c index f87a423acd1f..1c712fba3157 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -8690,6 +8690,9 @@ swaptimize(basicblock *block, int *ix) #define SWAPPABLE(opcode) \ ((opcode) == STORE_FAST || (opcode) == POP_TOP) +#define STORES_TO(instr) \ + (((instr).i_opcode == STORE_FAST) ? (instr).i_oparg : -1) + static int next_swappable_instruction(basicblock *block, int i, int lineno) { @@ -8741,6 +8744,23 @@ apply_static_swaps(basicblock *block, int i) return; } } + // The reordering is not safe if the two instructions to be swapped + // store to the same location, or if any intervening instruction stores + // to the same location as either of them. + int store_j = STORES_TO(block->b_instr[j]); + int store_k = STORES_TO(block->b_instr[k]); + if (store_j >= 0 || store_k >= 0) { + if (store_j == store_k) { + return; + } + for (int idx = j + 1; idx < k; idx++) { + int store_idx = STORES_TO(block->b_instr[idx]); + if (store_idx >= 0 && (store_idx == store_j || store_idx == store_k)) { + return; + } + } + } + // Success! swap->i_opcode = NOP; struct instr temp = block->b_instr[j]; From webhook-mailer at python.org Fri May 19 14:08:51 2023 From: webhook-mailer at python.org (markshannon) Date: Fri, 19 May 2023 18:08:51 -0000 Subject: [Python-checkins] [3.11] GH-102818: Do not call PyTraceBack_Here in sys.settrace trampoline (GH-104650) Message-ID: <mailman.460.1684519732.13550.python-checkins@python.org> https://github.com/python/cpython/commit/7b3bc95067b118b31e9781d460b41bf0cd629aab commit: 7b3bc95067b118b31e9781d460b41bf0cd629aab branch: 3.11 author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-19T19:08:43+01:00 summary: [3.11] GH-102818: Do not call PyTraceBack_Here in sys.settrace trampoline (GH-104650) Backport of GH-104579 files: A Misc/NEWS.d/next/Core and Builtins/2023-05-13-06-22-52.gh-issue-102818.HIX1Dr.rst M Lib/test/test_sys_settrace.py M Modules/_testcapimodule.c M Python/sysmodule.c diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index aa61f8b18588..96242bb260a6 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1571,6 +1571,62 @@ def func(): self.run_and_compare(func, EXPECTED_EVENTS) + def test_settrace_error(self): + + raised = False + def error_once(frame, event, arg): + nonlocal raised + if not raised: + raised = True + raise Exception + return error + + try: + sys._getframe().f_trace = error_once + sys.settrace(error_once) + len([]) + except Exception as ex: + count = 0 + tb = ex.__traceback__ + print(tb) + while tb: + if tb.tb_frame.f_code.co_name == "test_settrace_error": + count += 1 + tb = tb.tb_next + if count == 0: + self.fail("Traceback is missing frame") + elif count > 1: + self.fail("Traceback has frame more than once") + else: + self.fail("No exception raised") + finally: + sys.settrace(None) + + @support.cpython_only + def test_testcapi_settrace_error(self): + + # Skip this test if the _testcapi module isn't available. + _testcapi = import_helper.import_module('_testcapi') + + try: + _testcapi.settrace_to_error([]) + len([]) + except Exception as ex: + count = 0 + tb = ex.__traceback__ + while tb: + if tb.tb_frame.f_code.co_name == "test_testcapi_settrace_error": + count += 1 + tb = tb.tb_next + if count == 0: + self.fail("Traceback is missing frame") + elif count > 1: + self.fail("Traceback has frame more than once") + else: + self.fail("No exception raised") + finally: + sys.settrace(None) + def test_very_large_function(self): # There is a separate code path when the number of lines > (1 << 15). d = {} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-13-06-22-52.gh-issue-102818.HIX1Dr.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-13-06-22-52.gh-issue-102818.HIX1Dr.rst new file mode 100644 index 000000000000..f18be9125439 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-13-06-22-52.gh-issue-102818.HIX1Dr.rst @@ -0,0 +1,5 @@ +Do not add a frame to the traceback in the ``sys.setprofile`` and +``sys.settrace`` trampoline functions. This ensures that frames are not +duplicated if an exception is raised in the callback function, and ensures +that frames are not omitted if a C callback is used and that does not add +the frame. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index dff98e6fea92..b40368eb4b34 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -6345,6 +6345,33 @@ settrace_to_record(PyObject *self, PyObject *list) Py_RETURN_NONE; } +static int +error_func(PyObject *obj, PyFrameObject *f, int what, PyObject *arg) +{ + assert(PyList_Check(obj)); + /* Only raise if list is empty, otherwise append None + * This ensures that we only raise once */ + if (PyList_GET_SIZE(obj)) { + return 0; + } + if (PyList_Append(obj, Py_None)) { + return -1; + } + PyErr_SetString(PyExc_Exception, "an exception"); + return -1; +} + +static PyObject * +settrace_to_error(PyObject *self, PyObject *list) +{ + if (!PyList_Check(list)) { + PyErr_SetString(PyExc_TypeError, "argument must be a list"); + return NULL; + } + PyEval_SetTrace(error_func, list); + Py_RETURN_NONE; +} + static PyObject *negative_dictoffset(PyObject *, PyObject *); static PyObject * @@ -6694,6 +6721,7 @@ static PyMethodDef TestMethods[] = { {"eval_get_func_desc", eval_get_func_desc, METH_O, NULL}, {"get_feature_macros", get_feature_macros, METH_NOARGS, NULL}, {"test_code_api", test_code_api, METH_NOARGS, NULL}, + {"settrace_to_error", settrace_to_error, METH_O, NULL}, {"settrace_to_record", settrace_to_record, METH_O, NULL}, {"function_get_code", function_get_code, METH_O, NULL}, {"function_get_globals", function_get_globals, METH_O, NULL}, diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 68a835a30baa..8bab7037138d 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -950,10 +950,6 @@ call_trampoline(PyThreadState *tstate, PyObject* callback, PyObject *result = _PyObject_FastCallTstate(tstate, callback, stack, 3); PyFrame_LocalsToFast(frame, 1); - if (result == NULL) { - PyTraceBack_Here(frame); - } - return result; } From webhook-mailer at python.org Fri May 19 14:13:37 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 19 May 2023 18:13:37 -0000 Subject: [Python-checkins] gh-85984: New additions and improvements to the tty library. (#101832) Message-ID: <mailman.461.1684520018.13550.python-checkins@python.org> https://github.com/python/cpython/commit/486bc8e03019b8edc3cbfc6e64db96d65dbe13b6 commit: 486bc8e03019b8edc3cbfc6e64db96d65dbe13b6 branch: main author: Soumendra Ganguly <67527439+8vasu at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-19T18:13:30Z summary: gh-85984: New additions and improvements to the tty library. (#101832) New additions to the tty library. Functions added: cfmakeraw(), and cfmakecbreak(). The functions setcbreak() and setraw() now return original termios to save an extra tcgetattr() call. --------- Signed-off-by: Soumendra Ganguly <soumendraganguly at gmail.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Gregory P. Smith [Google LLC] <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst M Doc/library/tty.rst M Lib/tty.py diff --git a/Doc/library/tty.rst b/Doc/library/tty.rst index b30bc3c7ac42..fc7f98c7931f 100644 --- a/Doc/library/tty.rst +++ b/Doc/library/tty.rst @@ -20,18 +20,36 @@ Because it requires the :mod:`termios` module, it will work only on Unix. The :mod:`tty` module defines the following functions: +.. function:: cfmakeraw(mode) + + Convert the tty attribute list *mode*, which is a list like the one returned + by :func:`termios.tcgetattr`, to that of a tty in raw mode. + + .. versionadded:: 3.12 + + +.. function:: cfmakecbreak(mode) + + Convert the tty attribute list *mode*, which is a list like the one returned + by :func:`termios.tcgetattr`, to that of a tty in cbreak mode. + + .. versionadded:: 3.12 + + .. function:: setraw(fd, when=termios.TCSAFLUSH) Change the mode of the file descriptor *fd* to raw. If *when* is omitted, it defaults to :const:`termios.TCSAFLUSH`, and is passed to - :func:`termios.tcsetattr`. + :func:`termios.tcsetattr`. The return value of :func:`termios.tcgetattr` + is saved before setting *fd* to raw mode; this value is returned. .. function:: setcbreak(fd, when=termios.TCSAFLUSH) Change the mode of file descriptor *fd* to cbreak. If *when* is omitted, it defaults to :const:`termios.TCSAFLUSH`, and is passed to - :func:`termios.tcsetattr`. + :func:`termios.tcsetattr`. The return value of :func:`termios.tcgetattr` + is saved before setting *fd* to cbreak mode; this value is returned. .. seealso:: diff --git a/Lib/tty.py b/Lib/tty.py index a72eb6755450..7d916029ff2c 100644 --- a/Lib/tty.py +++ b/Lib/tty.py @@ -4,9 +4,9 @@ from termios import * -__all__ = ["setraw", "setcbreak"] +__all__ = ["cfmakeraw", "cfmakecbreak", "setraw", "setcbreak"] -# Indexes for termios list. +# Indices for termios list. IFLAG = 0 OFLAG = 1 CFLAG = 2 @@ -15,22 +15,60 @@ OSPEED = 5 CC = 6 -def setraw(fd, when=TCSAFLUSH): - """Put terminal into a raw mode.""" - mode = tcgetattr(fd) - mode[IFLAG] = mode[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) - mode[OFLAG] = mode[OFLAG] & ~(OPOST) - mode[CFLAG] = mode[CFLAG] & ~(CSIZE | PARENB) - mode[CFLAG] = mode[CFLAG] | CS8 - mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG) +def cfmakeraw(mode): + """Make termios mode raw.""" + # Clear all POSIX.1-2017 input mode flags. + # See chapter 11 "General Terminal Interface" + # of POSIX.1-2017 Base Definitions. + mode[IFLAG] &= ~(IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | + INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF) + + # Do not post-process output. + mode[OFLAG] &= ~OPOST + + # Disable parity generation and detection; clear character size mask; + # let character size be 8 bits. + mode[CFLAG] &= ~(PARENB | CSIZE) + mode[CFLAG] |= CS8 + + # Clear all POSIX.1-2017 local mode flags. + mode[LFLAG] &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | + IEXTEN | ISIG | NOFLSH | TOSTOP) + + # POSIX.1-2017, 11.1.7 Non-Canonical Mode Input Processing, + # Case B: MIN>0, TIME=0 + # A pending read shall block until MIN (here 1) bytes are received, + # or a signal is received. mode[CC][VMIN] = 1 mode[CC][VTIME] = 0 - tcsetattr(fd, when, mode) -def setcbreak(fd, when=TCSAFLUSH): - """Put terminal into a cbreak mode.""" - mode = tcgetattr(fd) - mode[LFLAG] = mode[LFLAG] & ~(ECHO | ICANON) +def cfmakecbreak(mode): + """Make termios mode cbreak.""" + # Do not map CR to NL on input. + mode[IFLAG] &= ~(ICRNL) + + # Do not echo characters; disable canonical input. + mode[LFLAG] &= ~(ECHO | ICANON) + + # POSIX.1-2017, 11.1.7 Non-Canonical Mode Input Processing, + # Case B: MIN>0, TIME=0 + # A pending read shall block until MIN (here 1) bytes are received, + # or a signal is received. mode[CC][VMIN] = 1 mode[CC][VTIME] = 0 - tcsetattr(fd, when, mode) + +def setraw(fd, when=TCSAFLUSH): + """Put terminal into raw mode.""" + mode = tcgetattr(fd) + new = list(mode) + cfmakeraw(new) + tcsetattr(fd, when, new) + return mode + +def setcbreak(fd, when=TCSAFLUSH): + """Put terminal into cbreak mode.""" + mode = tcgetattr(fd) + new = list(mode) + cfmakecbreak(new) + tcsetattr(fd, when, new) + return mode diff --git a/Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst b/Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst new file mode 100644 index 000000000000..246530472165 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst @@ -0,0 +1,3 @@ +Add :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` to :mod:`tty` and +modernize, the behavior of :func:`tty.setraw` and :func:`tty.setcbreak` to use +POSIX.1-2017 Chapter 11 "General Terminal Interface" flag masks by default. From webhook-mailer at python.org Fri May 19 15:10:06 2023 From: webhook-mailer at python.org (ned-deily) Date: Fri, 19 May 2023 19:10:06 -0000 Subject: [Python-checkins] gh-103839: Allow building Tkinter against Tcl 8.7 without external libtommath (GH-103842) Message-ID: <mailman.462.1684523407.13550.python-checkins@python.org> https://github.com/python/cpython/commit/625887e6df5dbebe48be172b424ba519e2ba2ddc commit: 625887e6df5dbebe48be172b424ba519e2ba2ddc branch: main author: Christopher Chavez <chrischavez at gmx.us> committer: ned-deily <nad at python.org> date: 2023-05-19T15:09:59-04:00 summary: gh-103839: Allow building Tkinter against Tcl 8.7 without external libtommath (GH-103842) files: A Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst M Modules/_tkinter.c diff --git a/Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst b/Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst new file mode 100644 index 000000000000..1d40a8fbcd3f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst @@ -0,0 +1,2 @@ +Avoid compilation error due to tommath.h not being found when building +Tkinter against Tcl 8.7 built with bundled libtommath. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 4dada0b28f05..49c94447c723 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -60,6 +60,9 @@ Copyright (C) 1994 Steen Lumholt. #error "Tk older than 8.5.12 not supported" #endif +#ifndef TCL_WITH_EXTERNAL_TOMMATH +#define TCL_NO_TOMMATH_H +#endif #include <tclTomMath.h> #if !(defined(MS_WINDOWS) || defined(__CYGWIN__)) From webhook-mailer at python.org Fri May 19 15:25:58 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 19 May 2023 19:25:58 -0000 Subject: [Python-checkins] gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (#104667) Message-ID: <mailman.463.1684524359.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c3f43bfb4bec39ff8f2c36d861a3c3a243bcb3af commit: c3f43bfb4bec39ff8f2c36d861a3c3a243bcb3af branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-19T19:25:51Z summary: gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (#104667) Skip test_subprocess.ProcessTestCase.test_empty_env if ASAN is enabled. files: M Lib/test/test_subprocess.py diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3880125807f2..92f81eaafb1c 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1,6 +1,7 @@ import unittest from unittest import mock from test import support +from test.support import check_sanitizer from test.support import import_helper from test.support import os_helper from test.support import warnings_helper @@ -790,6 +791,8 @@ def test_env(self): @unittest.skipIf(sysconfig.get_config_var('Py_ENABLE_SHARED') == 1, 'The Python shared library cannot be loaded ' 'with an empty environment.') + @unittest.skipIf(check_sanitizer(address=True), + 'AddressSanitizer adds to the environment.') def test_empty_env(self): """Verify that env={} is as empty as possible.""" From webhook-mailer at python.org Fri May 19 16:03:57 2023 From: webhook-mailer at python.org (mdickinson) Date: Fri, 19 May 2023 20:03:57 -0000 Subject: [Python-checkins] gh-94906: Support multiple steps in math.nextafter (#103881) Message-ID: <mailman.464.1684526638.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6e39fa19555043588910d10f1fe677cf6b04d77e commit: 6e39fa19555043588910d10f1fe677cf6b04d77e branch: main author: Matthias G?rgens <matthias.goergens at gmail.com> committer: mdickinson <dickinsm at gmail.com> date: 2023-05-19T21:03:49+01:00 summary: gh-94906: Support multiple steps in math.nextafter (#103881) This PR updates `math.nextafter` to add a new `steps` argument. The behaviour is as though `math.nextafter` had been called `steps` times in succession. --------- Co-authored-by: Mark Dickinson <mdickinson at enthought.com> files: A Lib/test/test_math_property.py A Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst M Doc/library/math.rst M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/test/test_math.py M Modules/clinic/mathmodule.c.h M Modules/mathmodule.c diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 797f32408eac..9e58b552576c 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -224,11 +224,11 @@ Number-theoretic and representation functions of *x* and are floats. -.. function:: nextafter(x, y) +.. function:: nextafter(x, y, steps=1) - Return the next floating-point value after *x* towards *y*. + Return the floating-point value *steps* steps after *x* towards *y*. - If *x* is equal to *y*, return *y*. + If *x* is equal to *y*, return *y*, unless *steps* is zero. Examples: @@ -239,6 +239,9 @@ Number-theoretic and representation functions See also :func:`math.ulp`. + .. versionchanged:: 3.12 + Added the *steps* argument. + .. versionadded:: 3.9 .. function:: perm(n, k=None) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index eeaa2ad96c90..8ca3545d8b3f 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1193,6 +1193,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stdin)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stdout)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(step)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(steps)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(store_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strategy)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(strftime)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 5cc790d126be..8e429bbfa26f 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -681,6 +681,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(stdin) STRUCT_FOR_ID(stdout) STRUCT_FOR_ID(step) + STRUCT_FOR_ID(steps) STRUCT_FOR_ID(store_name) STRUCT_FOR_ID(strategy) STRUCT_FOR_ID(strftime) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 0cb24a92dffa..3edf076696d9 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1187,6 +1187,7 @@ extern "C" { INIT_ID(stdin), \ INIT_ID(stdout), \ INIT_ID(step), \ + INIT_ID(steps), \ INIT_ID(store_name), \ INIT_ID(strategy), \ INIT_ID(strftime), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index fe2479beb8a3..0e1f71798a6e 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1884,6 +1884,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(step); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(steps); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(store_name); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index f282434c9a33..2bda61012164 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -2296,11 +2296,20 @@ def test_nextafter(self): float.fromhex('0x1.fffffffffffffp-1')) self.assertEqual(math.nextafter(1.0, INF), float.fromhex('0x1.0000000000001p+0')) + self.assertEqual(math.nextafter(1.0, -INF, steps=1), + float.fromhex('0x1.fffffffffffffp-1')) + self.assertEqual(math.nextafter(1.0, INF, steps=1), + float.fromhex('0x1.0000000000001p+0')) + self.assertEqual(math.nextafter(1.0, -INF, steps=3), + float.fromhex('0x1.ffffffffffffdp-1')) + self.assertEqual(math.nextafter(1.0, INF, steps=3), + float.fromhex('0x1.0000000000003p+0')) # x == y: y is returned - self.assertEqual(math.nextafter(2.0, 2.0), 2.0) - self.assertEqualSign(math.nextafter(-0.0, +0.0), +0.0) - self.assertEqualSign(math.nextafter(+0.0, -0.0), -0.0) + for steps in range(1, 5): + self.assertEqual(math.nextafter(2.0, 2.0, steps=steps), 2.0) + self.assertEqualSign(math.nextafter(-0.0, +0.0, steps=steps), +0.0) + self.assertEqualSign(math.nextafter(+0.0, -0.0, steps=steps), -0.0) # around 0.0 smallest_subnormal = sys.float_info.min * sys.float_info.epsilon @@ -2325,6 +2334,11 @@ def test_nextafter(self): self.assertIsNaN(math.nextafter(1.0, NAN)) self.assertIsNaN(math.nextafter(NAN, NAN)) + self.assertEqual(1.0, math.nextafter(1.0, INF, steps=0)) + with self.assertRaises(ValueError): + math.nextafter(1.0, INF, steps=-1) + + @requires_IEEE_754 def test_ulp(self): self.assertEqual(math.ulp(1.0), sys.float_info.epsilon) diff --git a/Lib/test/test_math_property.py b/Lib/test/test_math_property.py new file mode 100644 index 000000000000..7d51aa17b4cc --- /dev/null +++ b/Lib/test/test_math_property.py @@ -0,0 +1,41 @@ +import functools +import unittest +from math import isnan, nextafter +from test.support import requires_IEEE_754 +from test.support.hypothesis_helper import hypothesis + +floats = hypothesis.strategies.floats +integers = hypothesis.strategies.integers + + +def assert_equal_float(x, y): + assert isnan(x) and isnan(y) or x == y + + +def via_reduce(x, y, steps): + return functools.reduce(nextafter, [y] * steps, x) + + +class NextafterTests(unittest.TestCase): + @requires_IEEE_754 + @hypothesis.given( + x=floats(), + y=floats(), + steps=integers(min_value=0, max_value=2**16)) + def test_count(self, x, y, steps): + assert_equal_float(via_reduce(x, y, steps), + nextafter(x, y, steps=steps)) + + @requires_IEEE_754 + @hypothesis.given( + x=floats(), + y=floats(), + a=integers(min_value=0), + b=integers(min_value=0)) + def test_addition_commutes(self, x, y, a, b): + first = nextafter(x, y, steps=a) + second = nextafter(first, y, steps=b) + combined = nextafter(x, y, steps=a+b) + hypothesis.note(f"{first} -> {second} == {combined}") + + assert_equal_float(second, combined) diff --git a/Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst b/Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst new file mode 100644 index 000000000000..663343371d1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst @@ -0,0 +1 @@ +Support multiple steps in :func:`math.nextafter`. Patch by Shantanu Jain and Matthias Gorgens. diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index bc5bbceb4c92..c16c1b083985 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -826,25 +826,59 @@ math_comb(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(math_nextafter__doc__, -"nextafter($module, x, y, /)\n" +"nextafter($module, x, y, /, *, steps=None)\n" "--\n" "\n" -"Return the next floating-point value after x towards y."); +"Return the floating-point value the given number of steps after x towards y.\n" +"\n" +"If steps is not specified or is None, it defaults to 1.\n" +"\n" +"Raises a TypeError, if x or y is not a double, or if steps is not an integer.\n" +"Raises ValueError if steps is negative."); #define MATH_NEXTAFTER_METHODDEF \ - {"nextafter", _PyCFunction_CAST(math_nextafter), METH_FASTCALL, math_nextafter__doc__}, + {"nextafter", _PyCFunction_CAST(math_nextafter), METH_FASTCALL|METH_KEYWORDS, math_nextafter__doc__}, static PyObject * -math_nextafter_impl(PyObject *module, double x, double y); +math_nextafter_impl(PyObject *module, double x, double y, PyObject *steps); static PyObject * -math_nextafter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +math_nextafter(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(steps), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "", "steps", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "nextafter", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; double x; double y; + PyObject *steps = Py_None; - if (!_PyArg_CheckPositional("nextafter", nargs, 2, 2)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf); + if (!args) { goto exit; } if (PyFloat_CheckExact(args[0])) { @@ -867,7 +901,12 @@ math_nextafter(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } } - return_value = math_nextafter_impl(module, x, y); + if (!noptargs) { + goto skip_optional_kwonly; + } + steps = args[2]; +skip_optional_kwonly: + return_value = math_nextafter_impl(module, x, y, steps); exit: return return_value; @@ -911,4 +950,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=a6437a3ba18c486a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=91a0357265a2a553 input=a9049054013a1b77]*/ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index f369b2c45ce3..f26602d5871a 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -3864,13 +3864,20 @@ math.nextafter x: double y: double / + * + steps: object = None + +Return the floating-point value the given number of steps after x towards y. + +If steps is not specified or is None, it defaults to 1. -Return the next floating-point value after x towards y. +Raises a TypeError, if x or y is not a double, or if steps is not an integer. +Raises ValueError if steps is negative. [clinic start generated code]*/ static PyObject * -math_nextafter_impl(PyObject *module, double x, double y) -/*[clinic end generated code: output=750c8266c1c540ce input=02b2d50cd1d9f9b6]*/ +math_nextafter_impl(PyObject *module, double x, double y, PyObject *steps) +/*[clinic end generated code: output=cc6511f02afc099e input=7f2a5842112af2b4]*/ { #if defined(_AIX) if (x == y) { @@ -3885,7 +3892,101 @@ math_nextafter_impl(PyObject *module, double x, double y) return PyFloat_FromDouble(y); } #endif - return PyFloat_FromDouble(nextafter(x, y)); + if (steps == Py_None) { + // fast path: we default to one step. + return PyFloat_FromDouble(nextafter(x, y)); + } + steps = PyNumber_Index(steps); + if (steps == NULL) { + return NULL; + } + assert(PyLong_CheckExact(steps)); + if (_PyLong_IsNegative((PyLongObject *)steps)) { + PyErr_SetString(PyExc_ValueError, + "steps must be a non-negative integer"); + Py_DECREF(steps); + return NULL; + } + + unsigned long long usteps_ull = PyLong_AsUnsignedLongLong(steps); + // Conveniently, uint64_t and double have the same number of bits + // on all the platforms we care about. + // So if an overflow occurs, we can just use UINT64_MAX. + Py_DECREF(steps); + if (usteps_ull >= UINT64_MAX) { + // This branch includes the case where an error occurred, since + // (unsigned long long)(-1) = ULLONG_MAX >= UINT64_MAX. Note that + // usteps_ull can be strictly larger than UINT64_MAX on a machine + // where unsigned long long has width > 64 bits. + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_Clear(); + } + else { + return NULL; + } + } + usteps_ull = UINT64_MAX; + } + assert(usteps_ull <= UINT64_MAX); + uint64_t usteps = (uint64_t)usteps_ull; + + if (usteps == 0) { + return PyFloat_FromDouble(x); + } + if (Py_IS_NAN(x)) { + return PyFloat_FromDouble(x); + } + if (Py_IS_NAN(y)) { + return PyFloat_FromDouble(y); + } + + // We assume that double and uint64_t have the same endianness. + // This is not guaranteed by the C-standard, but it is true for + // all platforms we care about. (The most likely form of violation + // would be a "mixed-endian" double.) + union pun {double f; uint64_t i;}; + union pun ux = {x}, uy = {y}; + if (ux.i == uy.i) { + return PyFloat_FromDouble(x); + } + + const uint64_t sign_bit = 1ULL<<63; + + uint64_t ax = ux.i & ~sign_bit; + uint64_t ay = uy.i & ~sign_bit; + + // opposite signs + if (((ux.i ^ uy.i) & sign_bit)) { + // NOTE: ax + ay can never overflow, because their most significant bit + // ain't set. + if (ax + ay <= usteps) { + return PyFloat_FromDouble(uy.f); + // This comparison has to use <, because <= would get +0.0 vs -0.0 + // wrong. + } else if (ax < usteps) { + union pun result = {.i = (uy.i & sign_bit) | (usteps - ax)}; + return PyFloat_FromDouble(result.f); + } else { + ux.i -= usteps; + return PyFloat_FromDouble(ux.f); + } + // same sign + } else if (ax > ay) { + if (ax - ay >= usteps) { + ux.i -= usteps; + return PyFloat_FromDouble(ux.f); + } else { + return PyFloat_FromDouble(uy.f); + } + } else { + if (ay - ax >= usteps) { + ux.i += usteps; + return PyFloat_FromDouble(ux.f); + } else { + return PyFloat_FromDouble(uy.f); + } + } } From webhook-mailer at python.org Fri May 19 16:11:28 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 19 May 2023 20:11:28 -0000 Subject: [Python-checkins] docs: fix wrong indentation causing rendering error in dis page (#104661) Message-ID: <mailman.465.1684527090.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3bc94e678f2961eafc9d665898d73afc6204d314 commit: 3bc94e678f2961eafc9d665898d73afc6204d314 branch: main author: Nyakku Shigure <sigure.qaq at gmail.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-19T23:11:21+03:00 summary: docs: fix wrong indentation causing rendering error in dis page (#104661) files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 248743b8fa0a..4762fb504374 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -622,8 +622,8 @@ not have to be) the original ``STACK[-2]``. .. versionadded:: 3.8 - .. versionchanged:: 3.11 - Exception representation on the stack now consist of one, not three, items. + .. versionchanged:: 3.11 + Exception representation on the stack now consist of one, not three, items. .. opcode:: CLEANUP_THROW From webhook-mailer at python.org Fri May 19 16:13:03 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 19 May 2023 20:13:03 -0000 Subject: [Python-checkins] [3.11] gh-104659: Consolidate python examples in enum documentation (#104665) (#104666) Message-ID: <mailman.466.1684527184.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cd13f73afd042fddbb4c85a4b0466276e1d53735 commit: cd13f73afd042fddbb4c85a4b0466276e1d53735 branch: 3.11 author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-19T23:12:57+03:00 summary: [3.11] gh-104659: Consolidate python examples in enum documentation (#104665) (#104666) gh-104659: Consolidate python examples in enum documentation (#104665) (cherry picked from commit 3ac856e69734491ff8423020c700c9ae86ac9a08) Co-authored-by: Thomas Hisch <t.hisch at gmail.com> files: M Doc/library/enum.rst diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 27400cf993c0..15b8e2918d75 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -404,17 +404,18 @@ Data Types with an *IntEnum* member, the resulting value loses its enumeration status. >>> from enum import IntEnum - >>> class Numbers(IntEnum): + >>> class Number(IntEnum): ... ONE = 1 ... TWO = 2 ... THREE = 3 - >>> Numbers.THREE - <Numbers.THREE: 3> - >>> Numbers.ONE + Numbers.TWO + ... + >>> Number.THREE + <Number.THREE: 3> + >>> Number.ONE + Number.TWO 3 - >>> Numbers.THREE + 5 + >>> Number.THREE + 5 8 - >>> Numbers.THREE == 3 + >>> Number.THREE == 3 True .. note:: From webhook-mailer at python.org Fri May 19 16:25:50 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 19 May 2023 20:25:50 -0000 Subject: [Python-checkins] [3.11] docs: fix wrong indentation causing rendering error in dis page (GH-104661) (#104670) Message-ID: <mailman.467.1684527951.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e5b6f38df4776b1a1a223040eb265d77ec6367d4 commit: e5b6f38df4776b1a1a223040eb265d77ec6367d4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-19T23:25:43+03:00 summary: [3.11] docs: fix wrong indentation causing rendering error in dis page (GH-104661) (#104670) docs: fix wrong indentation causing rendering error in dis page (GH-104661) (cherry picked from commit 3bc94e678f2961eafc9d665898d73afc6204d314) Co-authored-by: Nyakku Shigure <sigure.qaq at gmail.com> files: M Doc/library/dis.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index aec095dd7601..779793811ef9 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -569,8 +569,8 @@ the original TOS1. .. versionadded:: 3.8 - .. versionchanged:: 3.11 - Exception representation on the stack now consist of one, not three, items. + .. versionchanged:: 3.11 + Exception representation on the stack now consist of one, not three, items. .. opcode:: BEFORE_ASYNC_WITH From webhook-mailer at python.org Fri May 19 17:22:51 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 19 May 2023 21:22:51 -0000 Subject: [Python-checkins] [3.10] gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (GH-104667) (#104669) Message-ID: <mailman.468.1684531372.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f9d2a109bb9a477f79639c0459d32f1c38c67cce commit: f9d2a109bb9a477f79639c0459d32f1c38c67cce branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-19T14:22:44-07:00 summary: [3.10] gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (GH-104667) (#104669) gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (GH-104667) Skip test_subprocess.ProcessTestCase.test_empty_env if ASAN is enabled. (cherry picked from commit c3f43bfb4bec39ff8f2c36d861a3c3a243bcb3af) Co-authored-by: chgnrdv <52372310+chgnrdv at users.noreply.github.com> files: M Lib/test/test_subprocess.py diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 52540acf7e6d..139ef41e5737 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1,6 +1,7 @@ import unittest from unittest import mock from test import support +from test.support import check_sanitizer from test.support import import_helper from test.support import os_helper from test.support import warnings_helper @@ -774,6 +775,8 @@ def test_env(self): @unittest.skipIf(sysconfig.get_config_var('Py_ENABLE_SHARED') == 1, 'The Python shared library cannot be loaded ' 'with an empty environment.') + @unittest.skipIf(check_sanitizer(address=True), + 'AddressSanitizer adds to the environment.') def test_empty_env(self): """Verify that env={} is as empty as possible.""" From webhook-mailer at python.org Fri May 19 17:48:14 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 19 May 2023 21:48:14 -0000 Subject: [Python-checkins] [3.11] gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (GH-104667) (#104673) Message-ID: <mailman.469.1684532895.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2801b3f8f753bae137a974f0de8aee946cb1fca6 commit: 2801b3f8f753bae137a974f0de8aee946cb1fca6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-19T21:48:07Z summary: [3.11] gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (GH-104667) (#104673) gh-104472: Skip `test_subprocess.ProcessTestCase.test_empty_env` if ASAN is enabled (GH-104667) Skip test_subprocess.ProcessTestCase.test_empty_env if ASAN is enabled. (cherry picked from commit c3f43bfb4bec39ff8f2c36d861a3c3a243bcb3af) Co-authored-by: chgnrdv <52372310+chgnrdv at users.noreply.github.com> files: M Lib/test/test_subprocess.py diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 727b0e6dc578..846f76ba6d73 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1,6 +1,7 @@ import unittest from unittest import mock from test import support +from test.support import check_sanitizer from test.support import import_helper from test.support import os_helper from test.support import warnings_helper @@ -789,6 +790,8 @@ def test_env(self): @unittest.skipIf(sysconfig.get_config_var('Py_ENABLE_SHARED') == 1, 'The Python shared library cannot be loaded ' 'with an empty environment.') + @unittest.skipIf(check_sanitizer(address=True), + 'AddressSanitizer adds to the environment.') def test_empty_env(self): """Verify that env={} is as empty as possible.""" From webhook-mailer at python.org Fri May 19 23:34:19 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 20 May 2023 03:34:19 -0000 Subject: [Python-checkins] gh-103987: fix several crashes in mmap module (#103990) Message-ID: <mailman.470.1684553660.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ceaa4c3476ac49b5b31954fec53796c7a3b40349 commit: ceaa4c3476ac49b5b31954fec53796c7a3b40349 branch: main author: Prince Roshan <princekrroshan01 at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-19T20:34:12-07:00 summary: gh-103987: fix several crashes in mmap module (#103990) Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst M Lib/test/test_mmap.py M Modules/mmapmodule.c diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 213a44d56f37..517cbe0cb115 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -407,7 +407,6 @@ def test_move(self): m.move(0, 0, 1) m.move(0, 0, 0) - def test_anonymous(self): # anonymous mmap.mmap(-1, PAGE) m = mmap.mmap(-1, PAGESIZE) @@ -887,6 +886,92 @@ def test_resize_succeeds_with_error_for_second_named_mapping(self): self.assertEqual(m1[:data_length], data) self.assertEqual(m2[:data_length], data) + def test_mmap_closed_by_int_scenarios(self): + """ + gh-103987: Test that mmap objects raise ValueError + for closed mmap files + """ + + class MmapClosedByIntContext: + def __init__(self, access) -> None: + self.access = access + + def __enter__(self): + self.f = open(TESTFN, "w+b") + self.f.write(random.randbytes(100)) + self.f.flush() + + m = mmap.mmap(self.f.fileno(), 100, access=self.access) + + class X: + def __index__(self): + m.close() + return 10 + + return (m, X) + + def __exit__(self, exc_type, exc_value, traceback): + self.f.close() + + read_access_modes = [ + mmap.ACCESS_READ, + mmap.ACCESS_WRITE, + mmap.ACCESS_COPY, + mmap.ACCESS_DEFAULT, + ] + + write_access_modes = [ + mmap.ACCESS_WRITE, + mmap.ACCESS_COPY, + mmap.ACCESS_DEFAULT, + ] + + for access in read_access_modes: + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X()] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20 : 2] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[20 : X() : -2] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.read(X()) + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.find(b"1", 1, X()) + + for access in write_access_modes: + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20] = b"1" * 10 + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20 : 2] = b"1" * 5 + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[20 : X() : -2] = b"1" * 5 + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.move(1, 2, X()) + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.write_byte(X()) + class LargeMmapTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst b/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst new file mode 100644 index 000000000000..48c6d149a8ed --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst @@ -0,0 +1,2 @@ +In :mod:`mmap`, fix several bugs that could lead to access to memory-mapped files after +they have been invalidated. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index a470dd3c2f3b..8e5a0bde8899 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -284,7 +284,8 @@ mmap_read_method(mmap_object *self, CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) - return(NULL); + return NULL; + CHECK_VALID(NULL); /* silently 'adjust' out-of-range requests */ remaining = (self->pos < self->size) ? self->size - self->pos : 0; @@ -325,6 +326,7 @@ mmap_gfind(mmap_object *self, end = self->size; Py_ssize_t res; + CHECK_VALID(NULL); if (reverse) { res = _PyBytes_ReverseFind( self->data + start, end - start, @@ -388,7 +390,7 @@ mmap_write_method(mmap_object *self, CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "y*:write", &data)) - return(NULL); + return NULL; if (!is_writable(self)) { PyBuffer_Release(&data); @@ -401,6 +403,7 @@ mmap_write_method(mmap_object *self, return NULL; } + CHECK_VALID(NULL); memcpy(&self->data[self->pos], data.buf, data.len); self->pos += data.len; PyBuffer_Release(&data); @@ -420,6 +423,7 @@ mmap_write_byte_method(mmap_object *self, if (!is_writable(self)) return NULL; + CHECK_VALID(NULL); if (self->pos < self->size) { self->data[self->pos++] = value; Py_RETURN_NONE; @@ -724,6 +728,7 @@ mmap_move_method(mmap_object *self, PyObject *args) if (self->size - dest < cnt || self->size - src < cnt) goto bounds; + CHECK_VALID(NULL); memmove(&self->data[dest], &self->data[src], cnt); Py_RETURN_NONE; @@ -847,6 +852,7 @@ mmap_madvise_method(mmap_object *self, PyObject *args) length = self->size - start; } + CHECK_VALID(NULL); if (madvise(self->data + start, length, option) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -945,6 +951,7 @@ mmap_subscript(mmap_object *self, PyObject *item) "mmap index out of range"); return NULL; } + CHECK_VALID(NULL); return PyLong_FromLong(Py_CHARMASK(self->data[i])); } else if (PySlice_Check(item)) { @@ -955,6 +962,7 @@ mmap_subscript(mmap_object *self, PyObject *item) } slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step); + CHECK_VALID(NULL); if (slicelen <= 0) return PyBytes_FromStringAndSize("", 0); else if (step == 1) @@ -968,6 +976,7 @@ mmap_subscript(mmap_object *self, PyObject *item) if (result_buf == NULL) return PyErr_NoMemory(); + for (cur = start, i = 0; i < slicelen; cur += step, i++) { result_buf[i] = self->data[cur]; @@ -1052,6 +1061,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) "in range(0, 256)"); return -1; } + CHECK_VALID(-1); self->data[i] = (char) v; return 0; } @@ -1077,6 +1087,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) return -1; } + CHECK_VALID(-1); if (slicelen == 0) { } else if (step == 1) { From webhook-mailer at python.org Sat May 20 00:00:01 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sat, 20 May 2023 04:00:01 -0000 Subject: [Python-checkins] [3.11] gh-103987: fix several crashes in mmap module (GH-103990) (#104677) Message-ID: <mailman.471.1684555202.13550.python-checkins@python.org> https://github.com/python/cpython/commit/dbb011afaed8985da220744be0b3a33175daabcf commit: dbb011afaed8985da220744be0b3a33175daabcf branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-20T03:59:54Z summary: [3.11] gh-103987: fix several crashes in mmap module (GH-103990) (#104677) gh-103987: fix several crashes in mmap module (GH-103990) (cherry picked from commit ceaa4c3476ac49b5b31954fec53796c7a3b40349) Co-authored-by: Prince Roshan <princekrroshan01 at gmail.com> Co-authored-by: sunmy2019 <59365878+sunmy2019 at users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst M Lib/test/test_mmap.py M Modules/mmapmodule.c diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 213a44d56f37..517cbe0cb115 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -407,7 +407,6 @@ def test_move(self): m.move(0, 0, 1) m.move(0, 0, 0) - def test_anonymous(self): # anonymous mmap.mmap(-1, PAGE) m = mmap.mmap(-1, PAGESIZE) @@ -887,6 +886,92 @@ def test_resize_succeeds_with_error_for_second_named_mapping(self): self.assertEqual(m1[:data_length], data) self.assertEqual(m2[:data_length], data) + def test_mmap_closed_by_int_scenarios(self): + """ + gh-103987: Test that mmap objects raise ValueError + for closed mmap files + """ + + class MmapClosedByIntContext: + def __init__(self, access) -> None: + self.access = access + + def __enter__(self): + self.f = open(TESTFN, "w+b") + self.f.write(random.randbytes(100)) + self.f.flush() + + m = mmap.mmap(self.f.fileno(), 100, access=self.access) + + class X: + def __index__(self): + m.close() + return 10 + + return (m, X) + + def __exit__(self, exc_type, exc_value, traceback): + self.f.close() + + read_access_modes = [ + mmap.ACCESS_READ, + mmap.ACCESS_WRITE, + mmap.ACCESS_COPY, + mmap.ACCESS_DEFAULT, + ] + + write_access_modes = [ + mmap.ACCESS_WRITE, + mmap.ACCESS_COPY, + mmap.ACCESS_DEFAULT, + ] + + for access in read_access_modes: + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X()] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20 : 2] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[20 : X() : -2] + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.read(X()) + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.find(b"1", 1, X()) + + for access in write_access_modes: + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20] = b"1" * 10 + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[X() : 20 : 2] = b"1" * 5 + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m[20 : X() : -2] = b"1" * 5 + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.move(1, 2, X()) + + with MmapClosedByIntContext(access) as (m, X): + with self.assertRaisesRegex(ValueError, "mmap closed or invalid"): + m.write_byte(X()) + class LargeMmapTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst b/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst new file mode 100644 index 000000000000..48c6d149a8ed --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst @@ -0,0 +1,2 @@ +In :mod:`mmap`, fix several bugs that could lead to access to memory-mapped files after +they have been invalidated. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index ec36465728c3..39e56f290383 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -292,7 +292,8 @@ mmap_read_method(mmap_object *self, CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) - return(NULL); + return NULL; + CHECK_VALID(NULL); /* silently 'adjust' out-of-range requests */ remaining = (self->pos < self->size) ? self->size - self->pos : 0; @@ -333,6 +334,7 @@ mmap_gfind(mmap_object *self, end = self->size; Py_ssize_t res; + CHECK_VALID(NULL); if (reverse) { res = _PyBytes_ReverseFind( self->data + start, end - start, @@ -396,7 +398,7 @@ mmap_write_method(mmap_object *self, CHECK_VALID(NULL); if (!PyArg_ParseTuple(args, "y*:write", &data)) - return(NULL); + return NULL; if (!is_writable(self)) { PyBuffer_Release(&data); @@ -409,6 +411,7 @@ mmap_write_method(mmap_object *self, return NULL; } + CHECK_VALID(NULL); memcpy(&self->data[self->pos], data.buf, data.len); self->pos += data.len; PyBuffer_Release(&data); @@ -428,6 +431,7 @@ mmap_write_byte_method(mmap_object *self, if (!is_writable(self)) return NULL; + CHECK_VALID(NULL); if (self->pos < self->size) { self->data[self->pos++] = value; Py_RETURN_NONE; @@ -732,6 +736,7 @@ mmap_move_method(mmap_object *self, PyObject *args) if (self->size - dest < cnt || self->size - src < cnt) goto bounds; + CHECK_VALID(NULL); memmove(&self->data[dest], &self->data[src], cnt); Py_RETURN_NONE; @@ -857,6 +862,7 @@ mmap_madvise_method(mmap_object *self, PyObject *args) length = self->size - start; } + CHECK_VALID(NULL); if (madvise(self->data + start, length, option) != 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; @@ -955,6 +961,7 @@ mmap_subscript(mmap_object *self, PyObject *item) "mmap index out of range"); return NULL; } + CHECK_VALID(NULL); return PyLong_FromLong(Py_CHARMASK(self->data[i])); } else if (PySlice_Check(item)) { @@ -965,6 +972,7 @@ mmap_subscript(mmap_object *self, PyObject *item) } slicelen = PySlice_AdjustIndices(self->size, &start, &stop, step); + CHECK_VALID(NULL); if (slicelen <= 0) return PyBytes_FromStringAndSize("", 0); else if (step == 1) @@ -978,6 +986,7 @@ mmap_subscript(mmap_object *self, PyObject *item) if (result_buf == NULL) return PyErr_NoMemory(); + for (cur = start, i = 0; i < slicelen; cur += step, i++) { result_buf[i] = self->data[cur]; @@ -1062,6 +1071,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) "in range(0, 256)"); return -1; } + CHECK_VALID(-1); self->data[i] = (char) v; return 0; } @@ -1087,6 +1097,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) return -1; } + CHECK_VALID(-1); if (slicelen == 0) { } else if (step == 1) { From webhook-mailer at python.org Sat May 20 04:25:59 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 20 May 2023 08:25:59 -0000 Subject: [Python-checkins] Replace "OS X" with "macOS" (#104653) Message-ID: <mailman.472.1684571160.13550.python-checkins@python.org> https://github.com/python/cpython/commit/06eeee97e36aa6bb3d21d7cbc288763ae3a7b21e commit: 06eeee97e36aa6bb3d21d7cbc288763ae3a7b21e branch: main author: partev <petrosyan at gmail.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-05-20T01:25:52-07:00 summary: Replace "OS X" with "macOS" (#104653) files: M Doc/using/mac.rst diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 69cd5c92d884..651782728621 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -144,8 +144,8 @@ the foundation of most modern Mac development. Information on PyObjC is available from https://pypi.org/project/pyobjc/. The standard Python GUI toolkit is :mod:`tkinter`, based on the cross-platform -Tk toolkit (https://www.tcl.tk). An Aqua-native version of Tk is bundled with OS -X by Apple, and the latest version can be downloaded and installed from +Tk toolkit (https://www.tcl.tk). An Aqua-native version of Tk is bundled with +macOS by Apple, and the latest version can be downloaded and installed from https://www.activestate.com; it can also be built from source. *wxPython* is another popular cross-platform GUI toolkit that runs natively on From webhook-mailer at python.org Sat May 20 06:24:17 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 20 May 2023 10:24:17 -0000 Subject: [Python-checkins] gh-104683: Argument clinic: use `dict` over `OrderedDict` (#104647) Message-ID: <mailman.473.1684578258.13550.python-checkins@python.org> https://github.com/python/cpython/commit/02b60035ceb735c3f7dd5bb7dc6a1508748a7a8d commit: 02b60035ceb735c3f7dd5bb7dc6a1508748a7a8d branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-20T11:24:00+01:00 summary: gh-104683: Argument clinic: use `dict` over `OrderedDict` (#104647) For code readability. Instances of `builtins.dict` have been ordered since 3.6, and have been guaranteed by the language to be ordered since Python 3.7. Argument Clinic now requires Python 3.10+. files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3d4961e6e7d7..521191ed0c70 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2060,8 +2060,8 @@ def __init__(self, language, printer=None, *, verify=True, filename=None): self.printer = printer or BlockPrinter(language) self.verify = verify self.filename = filename - self.modules = collections.OrderedDict() - self.classes = collections.OrderedDict() + self.modules = {} + self.classes = {} self.functions = [] self.line_prefix = self.line_suffix = '' @@ -2074,18 +2074,18 @@ def __init__(self, language, printer=None, *, verify=True, filename=None): self.add_destination("file", "file", "{dirname}/clinic/{basename}.h") d = self.get_destination_buffer - self.destination_buffers = collections.OrderedDict(( - ('cpp_if', d('file')), - ('docstring_prototype', d('suppress')), - ('docstring_definition', d('file')), - ('methoddef_define', d('file')), - ('impl_prototype', d('file')), - ('parser_prototype', d('suppress')), - ('parser_definition', d('file')), - ('cpp_endif', d('file')), - ('methoddef_ifndef', d('file', 1)), - ('impl_definition', d('block')), - )) + self.destination_buffers = { + 'cpp_if': d('file'), + 'docstring_prototype': d('suppress'), + 'docstring_definition': d('file'), + 'methoddef_define': d('file'), + 'impl_prototype': d('file'), + 'parser_prototype': d('suppress'), + 'parser_definition': d('file'), + 'cpp_endif': d('file'), + 'methoddef_ifndef': d('file', 1), + 'impl_definition': d('block'), + } self.destination_buffers_stack = [] self.ifndef_symbols = set() @@ -2098,7 +2098,7 @@ def __init__(self, language, printer=None, *, verify=True, filename=None): continue name, value, *options = line.split() if name == 'preset': - self.presets[value] = preset = collections.OrderedDict() + self.presets[value] = preset = {} continue if len(options): @@ -2301,8 +2301,8 @@ def __init__( self.name = name self.module = self.parent = module - self.modules: ModuleDict = collections.OrderedDict() - self.classes: ClassDict = collections.OrderedDict() + self.modules: ModuleDict = {} + self.classes: ClassDict = {} self.functions: list[Function] = [] def __repr__(self) -> str: @@ -2327,7 +2327,7 @@ def __init__( self.type_object = type_object self.parent = cls or module - self.classes: ClassDict = collections.OrderedDict() + self.classes: ClassDict = {} self.functions: list[Function] = [] def __repr__(self) -> str: @@ -2428,7 +2428,7 @@ def __init__(self, parameters=None, *, name, return_converter, return_annotation=inspect.Signature.empty, docstring=None, kind=CALLABLE, coexist=False, docstring_only=False): - self.parameters = parameters or collections.OrderedDict() + self.parameters = parameters or {} self.return_annotation = return_annotation self.name = name self.full_name = full_name @@ -2489,12 +2489,10 @@ def copy(self, **overrides): } kwargs.update(overrides) f = Function(**kwargs) - - parameters = collections.OrderedDict() - for name, value in f.parameters.items(): - value = value.copy(function=f) - parameters[name] = value - f.parameters = parameters + f.parameters = { + name: value.copy(function=f) + for name, value in f.parameters.items() + } return f From webhook-mailer at python.org Sat May 20 06:52:39 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 20 May 2023 10:52:39 -0000 Subject: [Python-checkins] gh-104146: Purge dead code from Argument Clinic (#104680) Message-ID: <mailman.474.1684579960.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ae147d01a005e0a65510a605762d1ff79f3affb9 commit: ae147d01a005e0a65510a605762d1ff79f3affb9 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-20T10:52:32Z summary: gh-104146: Purge dead code from Argument Clinic (#104680) The following local variables were assigned but never used: - line 551: result - line 1341: groups - line 1431: default_return_converter - line 1529: ignore_self - line 1809: input_checksum - line 4224: new' --- Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 521191ed0c70..792e8e4dc03a 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -548,8 +548,6 @@ def permute_optional_groups(left, required, right): If required is empty, left must also be empty. """ required = tuple(required) - result = [] - if not required: if left: raise ValueError("required is empty but left is not") @@ -1338,7 +1336,6 @@ def render_option_group_parsing(self, f, template_dict): if isinstance(parameters[0].converter, self_converter): del parameters[0] - groups = [] group = None left = [] right = [] @@ -1428,8 +1425,6 @@ def render_function(self, clinic, f): first_optional = len(selfless) positional = selfless and selfless[-1].is_positional_only() new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) - default_return_converter = (not f.return_converter or - f.return_converter.type == 'PyObject *') has_option_groups = False # offset i by -1 because first_optional needs to ignore self @@ -1526,7 +1521,6 @@ def render_function(self, clinic, f): template_dict['return_value'] = data.return_value # used by unpack tuple code generator - ignore_self = -1 if isinstance(converters[0], self_converter) else 0 unpack_min = first_optional unpack_max = len(selfless) template_dict['unpack_min'] = str(unpack_min) @@ -1803,10 +1797,8 @@ def is_stop_line(line): if self.verify: if 'input' in d: checksum = d['output'] - input_checksum = d['input'] else: checksum = d['checksum'] - input_checksum = None computed = compute_checksum(output, len(checksum)) if checksum != computed: @@ -4243,8 +4235,7 @@ def directive_version(self, required): fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required) def directive_module(self, name): - fields = name.split('.') - new = fields.pop() + fields = name.split('.')[:-1] module, cls = self.clinic._module_and_class(fields) if cls: fail("Can't nest a module inside a class!") From webhook-mailer at python.org Sat May 20 07:08:41 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 20 May 2023 11:08:41 -0000 Subject: [Python-checkins] gh-104683: Modernise `clinic.py` using `str.removeprefix` and `str.removesuffix` (#104685) Message-ID: <mailman.475.1684580922.13550.python-checkins@python.org> https://github.com/python/cpython/commit/663c049ff78a299bdf7c1a0444b9900e6d37372d commit: 663c049ff78a299bdf7c1a0444b9900e6d37372d branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-20T11:08:28Z summary: gh-104683: Modernise `clinic.py` using `str.removeprefix` and `str.removesuffix` (#104685) Both methods were new in Python 3.9. files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 792e8e4dc03a..b00b480a684d 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1741,7 +1741,7 @@ def is_stop_line(line): # make sure to recognize stop line even if it # doesn't end with EOL (it could be the very end of the file) if line.startswith(stop_line): - remainder = line[len(stop_line):] + remainder = line.removeprefix(stop_line) if remainder and not remainder.isspace(): fail(f"Garbage after stop line: {remainder!r}") return True @@ -1759,7 +1759,7 @@ def is_stop_line(line): if body_prefix: line = line.lstrip() assert line.startswith(body_prefix) - line = line[len(body_prefix):] + line = line.removeprefix(body_prefix) input_add(line) # consume output and checksum line, if present. @@ -2562,7 +2562,7 @@ def add_c_converter(f, name=None): name = f.__name__ if not name.endswith('_converter'): return f - name = name[:-len('_converter')] + name = name.removesuffix('_converter') converters[name] = f return f @@ -3969,7 +3969,7 @@ def add_c_return_converter(f, name=None): name = f.__name__ if not name.endswith('_return_converter'): return f - name = name[:-len('_return_converter')] + name = name.removesuffix('_return_converter') return_converters[name] = f return f @@ -5360,7 +5360,7 @@ def main(argv): if name in ignored: continue if name.endswith(suffix): - ids.append((name, name[:-len(suffix)])) + ids.append((name, name.removesuffix(suffix))) break print() From webhook-mailer at python.org Sat May 20 09:07:12 2023 From: webhook-mailer at python.org (pablogsal) Date: Sat, 20 May 2023 13:07:12 -0000 Subject: [Python-checkins] gh-104658: Fix location of unclosed quote error for multiline f-strings (#104660) Message-ID: <mailman.476.1684588033.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ff7f7316326a19749c5d79f9e44acdbe7d54ac4e commit: ff7f7316326a19749c5d79f9e44acdbe7d54ac4e branch: main author: Pablo Galindo Salgado <Pablogsal at gmail.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-20T14:07:05+01:00 summary: gh-104658: Fix location of unclosed quote error for multiline f-strings (#104660) 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 58e2550715ce..fcb12d25ff9d 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1558,7 +1558,21 @@ 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'''"]) - + # Ensure that the errors are reported at the correct line number. + data = '''\ +x = 1 + 1 +y = 2 + 2 +z = f""" +sdfjnsdfjsdf +sdfsdfs{1+ +2} dfigdf {3+ +4}sdufsd"" +''' + try: + compile(data, "?", "exec") + except SyntaxError as e: + self.assertEqual(e.text, 'z = f"""') + self.assertEqual(e.lineno, 3) def test_syntax_error_after_debug(self): self.assertAllRaise(SyntaxError, "f-string: expecting a valid expression after '{'", [ diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 91ffabac56c7..c5dc9e706fe4 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1124,7 +1124,7 @@ tok_underflow_interactive(struct tok_state *tok) { static int tok_underflow_file(struct tok_state *tok) { - if (tok->start == NULL) { + if (tok->start == NULL && !INSIDE_FSTRING(tok)) { tok->cur = tok->inp = tok->buf; } if (tok->decoding_state == STATE_INIT) { @@ -2250,6 +2250,7 @@ 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_line_start = tok->lineno; 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; @@ -2580,7 +2581,9 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct tok->cur++; tok->line_start = current_tok->f_string_multi_line_start; int start = tok->lineno; - tok->lineno = tok->first_lineno; + + tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); + tok->lineno = the_current_tok->f_string_line_start; if (current_tok->f_string_quote_size == 3) { return MAKE_TOKEN(syntaxerror(tok, diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 5e2171885ac7..fd169cf3d1ba 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -53,6 +53,7 @@ typedef struct _tokenizer_mode { int f_string_raw; const char* f_string_start; const char* f_string_multi_line_start; + int f_string_line_start; Py_ssize_t f_string_start_offset; Py_ssize_t f_string_multi_line_start_offset; From webhook-mailer at python.org Sat May 20 11:42:36 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 20 May 2023 15:42:36 -0000 Subject: [Python-checkins] gh-104679 Fixed syntax highlighting in turtle docs (#104682) Message-ID: <mailman.477.1684597357.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2c97878bb8a09f5aba8bf413bb794f6efd5065df commit: 2c97878bb8a09f5aba8bf413bb794f6efd5065df branch: main author: han-solo <hanish0019 at gmail.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-20T09:42:29-06:00 summary: gh-104679 Fixed syntax highlighting in turtle docs (#104682) files: M Doc/library/turtle.rst diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 10138f4f406f..c656f6d9cfda 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -359,18 +359,18 @@ Turtle motion .. doctest:: :skipif: _tkinter is None - >>> tp = turtle.pos() - >>> tp - (0.00,0.00) - >>> turtle.setpos(60,30) - >>> turtle.pos() - (60.00,30.00) - >>> turtle.setpos((20,80)) - >>> turtle.pos() - (20.00,80.00) - >>> turtle.setpos(tp) - >>> turtle.pos() - (0.00,0.00) + >>> tp = turtle.pos() + >>> tp + (0.00,0.00) + >>> turtle.setpos(60,30) + >>> turtle.pos() + (60.00,30.00) + >>> turtle.setpos((20,80)) + >>> turtle.pos() + (20.00,80.00) + >>> turtle.setpos(tp) + >>> turtle.pos() + (0.00,0.00) .. function:: teleport(x, y=None, *, fill_gap=False) @@ -395,18 +395,18 @@ Turtle motion .. doctest:: :skipif: _tkinter is None - >>> tp = turtle.pos() - >>> tp - (0.00,0.00) - >>> turtle.teleport(60) - >>> turtle.pos() - (60.00,0.00) - >>> turtle.teleport(y=10) - >>> turtle.pos() - (60.00,10.00) - >>> turtle.teleport(20, 30) - >>> turtle.pos() - (20.00,30.00) + >>> tp = turtle.pos() + >>> tp + (0.00,0.00) + >>> turtle.teleport(60) + >>> turtle.pos() + (60.00,0.00) + >>> turtle.teleport(y=10) + >>> turtle.pos() + (60.00,10.00) + >>> turtle.teleport(20, 30) + >>> turtle.pos() + (20.00,30.00) .. versionadded: 3.12 @@ -950,23 +950,23 @@ Color control .. doctest:: :skipif: _tkinter is None - >>> colormode() - 1.0 - >>> turtle.pencolor() - 'red' - >>> turtle.pencolor("brown") - >>> turtle.pencolor() - 'brown' - >>> tup = (0.2, 0.8, 0.55) - >>> turtle.pencolor(tup) - >>> turtle.pencolor() - (0.2, 0.8, 0.5490196078431373) - >>> colormode(255) - >>> turtle.pencolor() - (51.0, 204.0, 140.0) - >>> turtle.pencolor('#32c18f') - >>> turtle.pencolor() - (50.0, 193.0, 143.0) + >>> colormode() + 1.0 + >>> turtle.pencolor() + 'red' + >>> turtle.pencolor("brown") + >>> turtle.pencolor() + 'brown' + >>> tup = (0.2, 0.8, 0.55) + >>> turtle.pencolor(tup) + >>> turtle.pencolor() + (0.2, 0.8, 0.5490196078431373) + >>> colormode(255) + >>> turtle.pencolor() + (51.0, 204.0, 140.0) + >>> turtle.pencolor('#32c18f') + >>> turtle.pencolor() + (50.0, 193.0, 143.0) .. function:: fillcolor(*args) @@ -999,17 +999,17 @@ Color control .. doctest:: :skipif: _tkinter is None - >>> turtle.fillcolor("violet") - >>> turtle.fillcolor() - 'violet' - >>> turtle.pencolor() - (50.0, 193.0, 143.0) - >>> turtle.fillcolor((50, 193, 143)) # Integers, not floats - >>> turtle.fillcolor() - (50.0, 193.0, 143.0) - >>> turtle.fillcolor('#ffffff') - >>> turtle.fillcolor() - (255.0, 255.0, 255.0) + >>> turtle.fillcolor("violet") + >>> turtle.fillcolor() + 'violet' + >>> turtle.pencolor() + (50.0, 193.0, 143.0) + >>> turtle.fillcolor((50, 193, 143)) # Integers, not floats + >>> turtle.fillcolor() + (50.0, 193.0, 143.0) + >>> turtle.fillcolor('#ffffff') + >>> turtle.fillcolor() + (255.0, 255.0, 255.0) .. function:: color(*args) @@ -1038,12 +1038,12 @@ Color control .. doctest:: :skipif: _tkinter is None - >>> turtle.color("red", "green") - >>> turtle.color() - ('red', 'green') - >>> color("#285078", "#a0c8f0") - >>> color() - ((40.0, 80.0, 120.0), (160.0, 200.0, 240.0)) + >>> turtle.color("red", "green") + >>> turtle.color() + ('red', 'green') + >>> color("#285078", "#a0c8f0") + >>> color() + ((40.0, 80.0, 120.0), (160.0, 200.0, 240.0)) See also: Screen method :func:`colormode`. @@ -1065,11 +1065,11 @@ Filling .. doctest:: :skipif: _tkinter is None - >>> turtle.begin_fill() - >>> if turtle.filling(): - ... turtle.pensize(5) - ... else: - ... turtle.pensize(3) + >>> turtle.begin_fill() + >>> if turtle.filling(): + ... turtle.pensize(5) + ... else: + ... turtle.pensize(3) @@ -1275,11 +1275,11 @@ Appearance .. doctest:: :skipif: _tkinter is None - >>> turtle.shape("circle") - >>> turtle.shapesize(5,2) - >>> turtle.shearfactor(0.5) - >>> turtle.shearfactor() - 0.5 + >>> turtle.shape("circle") + >>> turtle.shapesize(5,2) + >>> turtle.shearfactor(0.5) + >>> turtle.shearfactor() + 0.5 .. function:: tilt(angle) @@ -1648,11 +1648,11 @@ Window control ``"nopic"``, delete background image, if present. If *picname* is ``None``, return the filename of the current backgroundimage. :: - >>> screen.bgpic() - 'nopic' - >>> screen.bgpic("landscape.gif") - >>> screen.bgpic() - "landscape.gif" + >>> screen.bgpic() + 'nopic' + >>> screen.bgpic("landscape.gif") + >>> screen.bgpic() + "landscape.gif" .. function:: clear() @@ -2059,16 +2059,16 @@ Settings and special methods Return the height of the turtle window. :: - >>> screen.window_height() - 480 + >>> screen.window_height() + 480 .. function:: window_width() Return the width of the turtle window. :: - >>> screen.window_width() - 640 + >>> screen.window_width() + 640 .. _screenspecific: @@ -2249,12 +2249,12 @@ facilities: in the range 0..colormode or a 3-tuple of such numbers. - >>> screen.bgcolor("orange") - >>> screen.bgcolor() - "orange" - >>> screen.bgcolor(0.5,0,0.5) - >>> screen.bgcolor() - "#800080" + >>> screen.bgcolor("orange") + >>> screen.bgcolor() + "orange" + >>> screen.bgcolor(0.5,0,0.5) + >>> screen.bgcolor() + "#800080" >>> help(Turtle.penup) Help on method penup in module turtle: From webhook-mailer at python.org Sat May 20 12:07:54 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 20 May 2023 16:07:54 -0000 Subject: [Python-checkins] gh-56276: Add tests to test_compare (#3199) Message-ID: <mailman.478.1684598875.13550.python-checkins@python.org> https://github.com/python/cpython/commit/68ee8b3f15b744339c156bfeb583a414061ab22d commit: 68ee8b3f15b744339c156bfeb583a414061ab22d branch: main author: Cheryl Sabella <cheryl.sabella at gmail.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-20T12:07:40-04:00 summary: gh-56276: Add tests to test_compare (#3199) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: M Lib/test/test_compare.py diff --git a/Lib/test/test_compare.py b/Lib/test/test_compare.py index 2b3faed7965b..8166b0eea306 100644 --- a/Lib/test/test_compare.py +++ b/Lib/test/test_compare.py @@ -1,21 +1,27 @@ +"""Test equality and order comparisons.""" import unittest from test.support import ALWAYS_EQ +from fractions import Fraction +from decimal import Decimal -class Empty: - def __repr__(self): - return '<Empty>' -class Cmp: - def __init__(self,arg): - self.arg = arg +class ComparisonSimpleTest(unittest.TestCase): + """Test equality and order comparisons for some simple cases.""" - def __repr__(self): - return '<Cmp %s>' % self.arg + class Empty: + def __repr__(self): + return '<Empty>' - def __eq__(self, other): - return self.arg == other + class Cmp: + def __init__(self, arg): + self.arg = arg + + def __repr__(self): + return '<Cmp %s>' % self.arg + + def __eq__(self, other): + return self.arg == other -class ComparisonTest(unittest.TestCase): set1 = [2, 2.0, 2, 2+0j, Cmp(2.0)] set2 = [[1], (3,), None, Empty()] candidates = set1 + set2 @@ -32,16 +38,15 @@ def test_id_comparisons(self): # Ensure default comparison compares id() of args L = [] for i in range(10): - L.insert(len(L)//2, Empty()) + L.insert(len(L)//2, self.Empty()) for a in L: for b in L: - self.assertEqual(a == b, id(a) == id(b), - 'a=%r, b=%r' % (a, b)) + self.assertEqual(a == b, a is b, 'a=%r, b=%r' % (a, b)) def test_ne_defaults_to_not_eq(self): - a = Cmp(1) - b = Cmp(1) - c = Cmp(2) + a = self.Cmp(1) + b = self.Cmp(1) + c = self.Cmp(2) self.assertIs(a == b, True) self.assertIs(a != b, False) self.assertIs(a != c, True) @@ -114,5 +119,392 @@ def test_issue_1393(self): self.assertEqual(ALWAYS_EQ, y) +class ComparisonFullTest(unittest.TestCase): + """Test equality and ordering comparisons for built-in types and + user-defined classes that implement relevant combinations of rich + comparison methods. + """ + + class CompBase: + """Base class for classes with rich comparison methods. + + The "x" attribute should be set to an underlying value to compare. + + Derived classes have a "meth" tuple attribute listing names of + comparison methods implemented. See assert_total_order(). + """ + + # Class without any rich comparison methods. + class CompNone(CompBase): + meth = () + + # Classes with all combinations of value-based equality comparison methods. + class CompEq(CompBase): + meth = ("eq",) + def __eq__(self, other): + return self.x == other.x + + class CompNe(CompBase): + meth = ("ne",) + def __ne__(self, other): + return self.x != other.x + + class CompEqNe(CompBase): + meth = ("eq", "ne") + def __eq__(self, other): + return self.x == other.x + def __ne__(self, other): + return self.x != other.x + + # Classes with all combinations of value-based less/greater-than order + # comparison methods. + class CompLt(CompBase): + meth = ("lt",) + def __lt__(self, other): + return self.x < other.x + + class CompGt(CompBase): + meth = ("gt",) + def __gt__(self, other): + return self.x > other.x + + class CompLtGt(CompBase): + meth = ("lt", "gt") + def __lt__(self, other): + return self.x < other.x + def __gt__(self, other): + return self.x > other.x + + # Classes with all combinations of value-based less/greater-or-equal-than + # order comparison methods + class CompLe(CompBase): + meth = ("le",) + def __le__(self, other): + return self.x <= other.x + + class CompGe(CompBase): + meth = ("ge",) + def __ge__(self, other): + return self.x >= other.x + + class CompLeGe(CompBase): + meth = ("le", "ge") + def __le__(self, other): + return self.x <= other.x + def __ge__(self, other): + return self.x >= other.x + + # It should be sufficient to combine the comparison methods only within + # each group. + all_comp_classes = ( + CompNone, + CompEq, CompNe, CompEqNe, # equal group + CompLt, CompGt, CompLtGt, # less/greater-than group + CompLe, CompGe, CompLeGe) # less/greater-or-equal group + + def create_sorted_instances(self, class_, values): + """Create objects of type `class_` and return them in a list. + + `values` is a list of values that determines the value of data + attribute `x` of each object. + + Objects in the returned list are sorted by their identity. They + assigned values in `values` list order. By assign decreasing + values to objects with increasing identities, testcases can assert + that order comparison is performed by value and not by identity. + """ + + instances = [class_() for __ in range(len(values))] + instances.sort(key=id) + # Assign the provided values to the instances. + for inst, value in zip(instances, values): + inst.x = value + return instances + + def assert_equality_only(self, a, b, equal): + """Assert equality result and that ordering is not implemented. + + a, b: Instances to be tested (of same or different type). + equal: Boolean indicating the expected equality comparison results. + """ + self.assertEqual(a == b, equal) + self.assertEqual(b == a, equal) + self.assertEqual(a != b, not equal) + self.assertEqual(b != a, not equal) + with self.assertRaisesRegex(TypeError, "not supported"): + a < b + with self.assertRaisesRegex(TypeError, "not supported"): + a <= b + with self.assertRaisesRegex(TypeError, "not supported"): + a > b + with self.assertRaisesRegex(TypeError, "not supported"): + a >= b + with self.assertRaisesRegex(TypeError, "not supported"): + b < a + with self.assertRaisesRegex(TypeError, "not supported"): + b <= a + with self.assertRaisesRegex(TypeError, "not supported"): + b > a + with self.assertRaisesRegex(TypeError, "not supported"): + b >= a + + def assert_total_order(self, a, b, comp, a_meth=None, b_meth=None): + """Test total ordering comparison of two instances. + + a, b: Instances to be tested (of same or different type). + + comp: -1, 0, or 1 indicates that the expected order comparison + result for operations that are supported by the classes is + a <, ==, or > b. + + a_meth, b_meth: Either None, indicating that all rich comparison + methods are available, aa for builtins, or the tuple (subset) + of "eq", "ne", "lt", "le", "gt", and "ge" that are available + for the corresponding instance (of a user-defined class). + """ + self.assert_eq_subtest(a, b, comp, a_meth, b_meth) + self.assert_ne_subtest(a, b, comp, a_meth, b_meth) + self.assert_lt_subtest(a, b, comp, a_meth, b_meth) + self.assert_le_subtest(a, b, comp, a_meth, b_meth) + self.assert_gt_subtest(a, b, comp, a_meth, b_meth) + self.assert_ge_subtest(a, b, comp, a_meth, b_meth) + + # The body of each subtest has form: + # + # if value-based comparison methods: + # expect what the testcase defined for a op b and b rop a; + # else: no value-based comparison + # expect default behavior of object for a op b and b rop a. + + def assert_eq_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "eq" in a_meth or "eq" in b_meth: + self.assertEqual(a == b, comp == 0) + self.assertEqual(b == a, comp == 0) + else: + self.assertEqual(a == b, a is b) + self.assertEqual(b == a, a is b) + + def assert_ne_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or not {"ne", "eq"}.isdisjoint(a_meth + b_meth): + self.assertEqual(a != b, comp != 0) + self.assertEqual(b != a, comp != 0) + else: + self.assertEqual(a != b, a is not b) + self.assertEqual(b != a, a is not b) + + def assert_lt_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "lt" in a_meth or "gt" in b_meth: + self.assertEqual(a < b, comp < 0) + self.assertEqual(b > a, comp < 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a < b + with self.assertRaisesRegex(TypeError, "not supported"): + b > a + + def assert_le_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "le" in a_meth or "ge" in b_meth: + self.assertEqual(a <= b, comp <= 0) + self.assertEqual(b >= a, comp <= 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a <= b + with self.assertRaisesRegex(TypeError, "not supported"): + b >= a + + def assert_gt_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "gt" in a_meth or "lt" in b_meth: + self.assertEqual(a > b, comp > 0) + self.assertEqual(b < a, comp > 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a > b + with self.assertRaisesRegex(TypeError, "not supported"): + b < a + + def assert_ge_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "ge" in a_meth or "le" in b_meth: + self.assertEqual(a >= b, comp >= 0) + self.assertEqual(b <= a, comp >= 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a >= b + with self.assertRaisesRegex(TypeError, "not supported"): + b <= a + + def test_objects(self): + """Compare instances of type 'object'.""" + a = object() + b = object() + self.assert_equality_only(a, a, True) + self.assert_equality_only(a, b, False) + + def test_comp_classes_same(self): + """Compare same-class instances with comparison methods.""" + + for cls in self.all_comp_classes: + with self.subTest(cls): + instances = self.create_sorted_instances(cls, (1, 2, 1)) + + # Same object. + self.assert_total_order(instances[0], instances[0], 0, + cls.meth, cls.meth) + + # Different objects, same value. + self.assert_total_order(instances[0], instances[2], 0, + cls.meth, cls.meth) + + # Different objects, value ascending for ascending identities. + self.assert_total_order(instances[0], instances[1], -1, + cls.meth, cls.meth) + + # different objects, value descending for ascending identities. + # This is the interesting case to assert that order comparison + # is performed based on the value and not based on the identity. + self.assert_total_order(instances[1], instances[2], +1, + cls.meth, cls.meth) + + def test_comp_classes_different(self): + """Compare different-class instances with comparison methods.""" + + for cls_a in self.all_comp_classes: + for cls_b in self.all_comp_classes: + with self.subTest(a=cls_a, b=cls_b): + a1 = cls_a() + a1.x = 1 + b1 = cls_b() + b1.x = 1 + b2 = cls_b() + b2.x = 2 + + self.assert_total_order( + a1, b1, 0, cls_a.meth, cls_b.meth) + self.assert_total_order( + a1, b2, -1, cls_a.meth, cls_b.meth) + + def test_str_subclass(self): + """Compare instances of str and a subclass.""" + class StrSubclass(str): + pass + + s1 = str("a") + s2 = str("b") + c1 = StrSubclass("a") + c2 = StrSubclass("b") + c3 = StrSubclass("b") + + self.assert_total_order(s1, s1, 0) + self.assert_total_order(s1, s2, -1) + self.assert_total_order(c1, c1, 0) + self.assert_total_order(c1, c2, -1) + self.assert_total_order(c2, c3, 0) + + self.assert_total_order(s1, c2, -1) + self.assert_total_order(s2, c3, 0) + self.assert_total_order(c1, s2, -1) + self.assert_total_order(c2, s2, 0) + + def test_numbers(self): + """Compare number types.""" + + # Same types. + i1 = 1001 + i2 = 1002 + self.assert_total_order(i1, i1, 0) + self.assert_total_order(i1, i2, -1) + + f1 = 1001.0 + f2 = 1001.1 + self.assert_total_order(f1, f1, 0) + self.assert_total_order(f1, f2, -1) + + q1 = Fraction(2002, 2) + q2 = Fraction(2003, 2) + self.assert_total_order(q1, q1, 0) + self.assert_total_order(q1, q2, -1) + + d1 = Decimal('1001.0') + d2 = Decimal('1001.1') + self.assert_total_order(d1, d1, 0) + self.assert_total_order(d1, d2, -1) + + c1 = 1001+0j + c2 = 1001+1j + self.assert_equality_only(c1, c1, True) + self.assert_equality_only(c1, c2, False) + + + # Mixing types. + for n1, n2 in ((i1,f1), (i1,q1), (i1,d1), (f1,q1), (f1,d1), (q1,d1)): + self.assert_total_order(n1, n2, 0) + for n1 in (i1, f1, q1, d1): + self.assert_equality_only(n1, c1, True) + + def test_sequences(self): + """Compare list, tuple, and range.""" + l1 = [1, 2] + l2 = [2, 3] + self.assert_total_order(l1, l1, 0) + self.assert_total_order(l1, l2, -1) + + t1 = (1, 2) + t2 = (2, 3) + self.assert_total_order(t1, t1, 0) + self.assert_total_order(t1, t2, -1) + + r1 = range(1, 2) + r2 = range(2, 2) + self.assert_equality_only(r1, r1, True) + self.assert_equality_only(r1, r2, False) + + self.assert_equality_only(t1, l1, False) + self.assert_equality_only(l1, r1, False) + self.assert_equality_only(r1, t1, False) + + def test_bytes(self): + """Compare bytes and bytearray.""" + bs1 = b'a1' + bs2 = b'b2' + self.assert_total_order(bs1, bs1, 0) + self.assert_total_order(bs1, bs2, -1) + + ba1 = bytearray(b'a1') + ba2 = bytearray(b'b2') + self.assert_total_order(ba1, ba1, 0) + self.assert_total_order(ba1, ba2, -1) + + self.assert_total_order(bs1, ba1, 0) + self.assert_total_order(bs1, ba2, -1) + self.assert_total_order(ba1, bs1, 0) + self.assert_total_order(ba1, bs2, -1) + + def test_sets(self): + """Compare set and frozenset.""" + s1 = {1, 2} + s2 = {1, 2, 3} + self.assert_total_order(s1, s1, 0) + self.assert_total_order(s1, s2, -1) + + f1 = frozenset(s1) + f2 = frozenset(s2) + self.assert_total_order(f1, f1, 0) + self.assert_total_order(f1, f2, -1) + + self.assert_total_order(s1, f1, 0) + self.assert_total_order(s1, f2, -1) + self.assert_total_order(f1, s1, 0) + self.assert_total_order(f1, s2, -1) + + def test_mappings(self): + """ Compare dict. + """ + d1 = {1: "a", 2: "b"} + d2 = {2: "b", 3: "c"} + d3 = {3: "c", 2: "b"} + self.assert_equality_only(d1, d1, True) + self.assert_equality_only(d1, d2, False) + self.assert_equality_only(d2, d3, True) + + if __name__ == '__main__': unittest.main() From webhook-mailer at python.org Sat May 20 12:31:49 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 20 May 2023 16:31:49 -0000 Subject: [Python-checkins] [3.11] gh-56276: Add tests to test_compare (GH-3199) (#104694) Message-ID: <mailman.479.1684600309.13550.python-checkins@python.org> https://github.com/python/cpython/commit/795b20e2f1099cc720491517ac41d4d6ed9e11e1 commit: 795b20e2f1099cc720491517ac41d4d6ed9e11e1 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-20T16:31:42Z summary: [3.11] gh-56276: Add tests to test_compare (GH-3199) (#104694) gh-56276: Add tests to test_compare (GH-3199) (cherry picked from commit 68ee8b3f15b744339c156bfeb583a414061ab22d) Co-authored-by: Cheryl Sabella <cheryl.sabella at gmail.com> Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: M Lib/test/test_compare.py diff --git a/Lib/test/test_compare.py b/Lib/test/test_compare.py index 2b3faed7965b..8166b0eea306 100644 --- a/Lib/test/test_compare.py +++ b/Lib/test/test_compare.py @@ -1,21 +1,27 @@ +"""Test equality and order comparisons.""" import unittest from test.support import ALWAYS_EQ +from fractions import Fraction +from decimal import Decimal -class Empty: - def __repr__(self): - return '<Empty>' -class Cmp: - def __init__(self,arg): - self.arg = arg +class ComparisonSimpleTest(unittest.TestCase): + """Test equality and order comparisons for some simple cases.""" - def __repr__(self): - return '<Cmp %s>' % self.arg + class Empty: + def __repr__(self): + return '<Empty>' - def __eq__(self, other): - return self.arg == other + class Cmp: + def __init__(self, arg): + self.arg = arg + + def __repr__(self): + return '<Cmp %s>' % self.arg + + def __eq__(self, other): + return self.arg == other -class ComparisonTest(unittest.TestCase): set1 = [2, 2.0, 2, 2+0j, Cmp(2.0)] set2 = [[1], (3,), None, Empty()] candidates = set1 + set2 @@ -32,16 +38,15 @@ def test_id_comparisons(self): # Ensure default comparison compares id() of args L = [] for i in range(10): - L.insert(len(L)//2, Empty()) + L.insert(len(L)//2, self.Empty()) for a in L: for b in L: - self.assertEqual(a == b, id(a) == id(b), - 'a=%r, b=%r' % (a, b)) + self.assertEqual(a == b, a is b, 'a=%r, b=%r' % (a, b)) def test_ne_defaults_to_not_eq(self): - a = Cmp(1) - b = Cmp(1) - c = Cmp(2) + a = self.Cmp(1) + b = self.Cmp(1) + c = self.Cmp(2) self.assertIs(a == b, True) self.assertIs(a != b, False) self.assertIs(a != c, True) @@ -114,5 +119,392 @@ def test_issue_1393(self): self.assertEqual(ALWAYS_EQ, y) +class ComparisonFullTest(unittest.TestCase): + """Test equality and ordering comparisons for built-in types and + user-defined classes that implement relevant combinations of rich + comparison methods. + """ + + class CompBase: + """Base class for classes with rich comparison methods. + + The "x" attribute should be set to an underlying value to compare. + + Derived classes have a "meth" tuple attribute listing names of + comparison methods implemented. See assert_total_order(). + """ + + # Class without any rich comparison methods. + class CompNone(CompBase): + meth = () + + # Classes with all combinations of value-based equality comparison methods. + class CompEq(CompBase): + meth = ("eq",) + def __eq__(self, other): + return self.x == other.x + + class CompNe(CompBase): + meth = ("ne",) + def __ne__(self, other): + return self.x != other.x + + class CompEqNe(CompBase): + meth = ("eq", "ne") + def __eq__(self, other): + return self.x == other.x + def __ne__(self, other): + return self.x != other.x + + # Classes with all combinations of value-based less/greater-than order + # comparison methods. + class CompLt(CompBase): + meth = ("lt",) + def __lt__(self, other): + return self.x < other.x + + class CompGt(CompBase): + meth = ("gt",) + def __gt__(self, other): + return self.x > other.x + + class CompLtGt(CompBase): + meth = ("lt", "gt") + def __lt__(self, other): + return self.x < other.x + def __gt__(self, other): + return self.x > other.x + + # Classes with all combinations of value-based less/greater-or-equal-than + # order comparison methods + class CompLe(CompBase): + meth = ("le",) + def __le__(self, other): + return self.x <= other.x + + class CompGe(CompBase): + meth = ("ge",) + def __ge__(self, other): + return self.x >= other.x + + class CompLeGe(CompBase): + meth = ("le", "ge") + def __le__(self, other): + return self.x <= other.x + def __ge__(self, other): + return self.x >= other.x + + # It should be sufficient to combine the comparison methods only within + # each group. + all_comp_classes = ( + CompNone, + CompEq, CompNe, CompEqNe, # equal group + CompLt, CompGt, CompLtGt, # less/greater-than group + CompLe, CompGe, CompLeGe) # less/greater-or-equal group + + def create_sorted_instances(self, class_, values): + """Create objects of type `class_` and return them in a list. + + `values` is a list of values that determines the value of data + attribute `x` of each object. + + Objects in the returned list are sorted by their identity. They + assigned values in `values` list order. By assign decreasing + values to objects with increasing identities, testcases can assert + that order comparison is performed by value and not by identity. + """ + + instances = [class_() for __ in range(len(values))] + instances.sort(key=id) + # Assign the provided values to the instances. + for inst, value in zip(instances, values): + inst.x = value + return instances + + def assert_equality_only(self, a, b, equal): + """Assert equality result and that ordering is not implemented. + + a, b: Instances to be tested (of same or different type). + equal: Boolean indicating the expected equality comparison results. + """ + self.assertEqual(a == b, equal) + self.assertEqual(b == a, equal) + self.assertEqual(a != b, not equal) + self.assertEqual(b != a, not equal) + with self.assertRaisesRegex(TypeError, "not supported"): + a < b + with self.assertRaisesRegex(TypeError, "not supported"): + a <= b + with self.assertRaisesRegex(TypeError, "not supported"): + a > b + with self.assertRaisesRegex(TypeError, "not supported"): + a >= b + with self.assertRaisesRegex(TypeError, "not supported"): + b < a + with self.assertRaisesRegex(TypeError, "not supported"): + b <= a + with self.assertRaisesRegex(TypeError, "not supported"): + b > a + with self.assertRaisesRegex(TypeError, "not supported"): + b >= a + + def assert_total_order(self, a, b, comp, a_meth=None, b_meth=None): + """Test total ordering comparison of two instances. + + a, b: Instances to be tested (of same or different type). + + comp: -1, 0, or 1 indicates that the expected order comparison + result for operations that are supported by the classes is + a <, ==, or > b. + + a_meth, b_meth: Either None, indicating that all rich comparison + methods are available, aa for builtins, or the tuple (subset) + of "eq", "ne", "lt", "le", "gt", and "ge" that are available + for the corresponding instance (of a user-defined class). + """ + self.assert_eq_subtest(a, b, comp, a_meth, b_meth) + self.assert_ne_subtest(a, b, comp, a_meth, b_meth) + self.assert_lt_subtest(a, b, comp, a_meth, b_meth) + self.assert_le_subtest(a, b, comp, a_meth, b_meth) + self.assert_gt_subtest(a, b, comp, a_meth, b_meth) + self.assert_ge_subtest(a, b, comp, a_meth, b_meth) + + # The body of each subtest has form: + # + # if value-based comparison methods: + # expect what the testcase defined for a op b and b rop a; + # else: no value-based comparison + # expect default behavior of object for a op b and b rop a. + + def assert_eq_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "eq" in a_meth or "eq" in b_meth: + self.assertEqual(a == b, comp == 0) + self.assertEqual(b == a, comp == 0) + else: + self.assertEqual(a == b, a is b) + self.assertEqual(b == a, a is b) + + def assert_ne_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or not {"ne", "eq"}.isdisjoint(a_meth + b_meth): + self.assertEqual(a != b, comp != 0) + self.assertEqual(b != a, comp != 0) + else: + self.assertEqual(a != b, a is not b) + self.assertEqual(b != a, a is not b) + + def assert_lt_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "lt" in a_meth or "gt" in b_meth: + self.assertEqual(a < b, comp < 0) + self.assertEqual(b > a, comp < 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a < b + with self.assertRaisesRegex(TypeError, "not supported"): + b > a + + def assert_le_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "le" in a_meth or "ge" in b_meth: + self.assertEqual(a <= b, comp <= 0) + self.assertEqual(b >= a, comp <= 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a <= b + with self.assertRaisesRegex(TypeError, "not supported"): + b >= a + + def assert_gt_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "gt" in a_meth or "lt" in b_meth: + self.assertEqual(a > b, comp > 0) + self.assertEqual(b < a, comp > 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a > b + with self.assertRaisesRegex(TypeError, "not supported"): + b < a + + def assert_ge_subtest(self, a, b, comp, a_meth, b_meth): + if a_meth is None or "ge" in a_meth or "le" in b_meth: + self.assertEqual(a >= b, comp >= 0) + self.assertEqual(b <= a, comp >= 0) + else: + with self.assertRaisesRegex(TypeError, "not supported"): + a >= b + with self.assertRaisesRegex(TypeError, "not supported"): + b <= a + + def test_objects(self): + """Compare instances of type 'object'.""" + a = object() + b = object() + self.assert_equality_only(a, a, True) + self.assert_equality_only(a, b, False) + + def test_comp_classes_same(self): + """Compare same-class instances with comparison methods.""" + + for cls in self.all_comp_classes: + with self.subTest(cls): + instances = self.create_sorted_instances(cls, (1, 2, 1)) + + # Same object. + self.assert_total_order(instances[0], instances[0], 0, + cls.meth, cls.meth) + + # Different objects, same value. + self.assert_total_order(instances[0], instances[2], 0, + cls.meth, cls.meth) + + # Different objects, value ascending for ascending identities. + self.assert_total_order(instances[0], instances[1], -1, + cls.meth, cls.meth) + + # different objects, value descending for ascending identities. + # This is the interesting case to assert that order comparison + # is performed based on the value and not based on the identity. + self.assert_total_order(instances[1], instances[2], +1, + cls.meth, cls.meth) + + def test_comp_classes_different(self): + """Compare different-class instances with comparison methods.""" + + for cls_a in self.all_comp_classes: + for cls_b in self.all_comp_classes: + with self.subTest(a=cls_a, b=cls_b): + a1 = cls_a() + a1.x = 1 + b1 = cls_b() + b1.x = 1 + b2 = cls_b() + b2.x = 2 + + self.assert_total_order( + a1, b1, 0, cls_a.meth, cls_b.meth) + self.assert_total_order( + a1, b2, -1, cls_a.meth, cls_b.meth) + + def test_str_subclass(self): + """Compare instances of str and a subclass.""" + class StrSubclass(str): + pass + + s1 = str("a") + s2 = str("b") + c1 = StrSubclass("a") + c2 = StrSubclass("b") + c3 = StrSubclass("b") + + self.assert_total_order(s1, s1, 0) + self.assert_total_order(s1, s2, -1) + self.assert_total_order(c1, c1, 0) + self.assert_total_order(c1, c2, -1) + self.assert_total_order(c2, c3, 0) + + self.assert_total_order(s1, c2, -1) + self.assert_total_order(s2, c3, 0) + self.assert_total_order(c1, s2, -1) + self.assert_total_order(c2, s2, 0) + + def test_numbers(self): + """Compare number types.""" + + # Same types. + i1 = 1001 + i2 = 1002 + self.assert_total_order(i1, i1, 0) + self.assert_total_order(i1, i2, -1) + + f1 = 1001.0 + f2 = 1001.1 + self.assert_total_order(f1, f1, 0) + self.assert_total_order(f1, f2, -1) + + q1 = Fraction(2002, 2) + q2 = Fraction(2003, 2) + self.assert_total_order(q1, q1, 0) + self.assert_total_order(q1, q2, -1) + + d1 = Decimal('1001.0') + d2 = Decimal('1001.1') + self.assert_total_order(d1, d1, 0) + self.assert_total_order(d1, d2, -1) + + c1 = 1001+0j + c2 = 1001+1j + self.assert_equality_only(c1, c1, True) + self.assert_equality_only(c1, c2, False) + + + # Mixing types. + for n1, n2 in ((i1,f1), (i1,q1), (i1,d1), (f1,q1), (f1,d1), (q1,d1)): + self.assert_total_order(n1, n2, 0) + for n1 in (i1, f1, q1, d1): + self.assert_equality_only(n1, c1, True) + + def test_sequences(self): + """Compare list, tuple, and range.""" + l1 = [1, 2] + l2 = [2, 3] + self.assert_total_order(l1, l1, 0) + self.assert_total_order(l1, l2, -1) + + t1 = (1, 2) + t2 = (2, 3) + self.assert_total_order(t1, t1, 0) + self.assert_total_order(t1, t2, -1) + + r1 = range(1, 2) + r2 = range(2, 2) + self.assert_equality_only(r1, r1, True) + self.assert_equality_only(r1, r2, False) + + self.assert_equality_only(t1, l1, False) + self.assert_equality_only(l1, r1, False) + self.assert_equality_only(r1, t1, False) + + def test_bytes(self): + """Compare bytes and bytearray.""" + bs1 = b'a1' + bs2 = b'b2' + self.assert_total_order(bs1, bs1, 0) + self.assert_total_order(bs1, bs2, -1) + + ba1 = bytearray(b'a1') + ba2 = bytearray(b'b2') + self.assert_total_order(ba1, ba1, 0) + self.assert_total_order(ba1, ba2, -1) + + self.assert_total_order(bs1, ba1, 0) + self.assert_total_order(bs1, ba2, -1) + self.assert_total_order(ba1, bs1, 0) + self.assert_total_order(ba1, bs2, -1) + + def test_sets(self): + """Compare set and frozenset.""" + s1 = {1, 2} + s2 = {1, 2, 3} + self.assert_total_order(s1, s1, 0) + self.assert_total_order(s1, s2, -1) + + f1 = frozenset(s1) + f2 = frozenset(s2) + self.assert_total_order(f1, f1, 0) + self.assert_total_order(f1, f2, -1) + + self.assert_total_order(s1, f1, 0) + self.assert_total_order(s1, f2, -1) + self.assert_total_order(f1, s1, 0) + self.assert_total_order(f1, s2, -1) + + def test_mappings(self): + """ Compare dict. + """ + d1 = {1: "a", 2: "b"} + d2 = {2: "b", 3: "c"} + d3 = {3: "c", 2: "b"} + self.assert_equality_only(d1, d1, True) + self.assert_equality_only(d1, d2, False) + self.assert_equality_only(d2, d3, True) + + if __name__ == '__main__': unittest.main() From webhook-mailer at python.org Sat May 20 12:36:50 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sat, 20 May 2023 16:36:50 -0000 Subject: [Python-checkins] [3.11] gh-104679 Fixed syntax highlighting in turtle docs (GH-104682). (#104695) Message-ID: <mailman.480.1684600611.13550.python-checkins@python.org> https://github.com/python/cpython/commit/89bd454cd9dfa33f3d7e40810e2c506f66869eef commit: 89bd454cd9dfa33f3d7e40810e2c506f66869eef branch: 3.11 author: han-solo <hanish0019 at gmail.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-20T12:36:43-04:00 summary: [3.11] gh-104679 Fixed syntax highlighting in turtle docs (GH-104682). (#104695) (cherry picked from commit 2c97878bb8a09f5aba8bf413bb794f6efd5065df) files: M Doc/library/turtle.rst diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 55d9130de8e2..2298c6c54545 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -358,18 +358,18 @@ Turtle motion .. doctest:: :skipif: _tkinter is None - >>> tp = turtle.pos() - >>> tp - (0.00,0.00) - >>> turtle.setpos(60,30) - >>> turtle.pos() - (60.00,30.00) - >>> turtle.setpos((20,80)) - >>> turtle.pos() - (20.00,80.00) - >>> turtle.setpos(tp) - >>> turtle.pos() - (0.00,0.00) + >>> tp = turtle.pos() + >>> tp + (0.00,0.00) + >>> turtle.setpos(60,30) + >>> turtle.pos() + (60.00,30.00) + >>> turtle.setpos((20,80)) + >>> turtle.pos() + (20.00,80.00) + >>> turtle.setpos(tp) + >>> turtle.pos() + (0.00,0.00) .. function:: setx(x) @@ -919,23 +919,23 @@ Color control .. doctest:: :skipif: _tkinter is None - >>> colormode() - 1.0 - >>> turtle.pencolor() - 'red' - >>> turtle.pencolor("brown") - >>> turtle.pencolor() - 'brown' - >>> tup = (0.2, 0.8, 0.55) - >>> turtle.pencolor(tup) - >>> turtle.pencolor() - (0.2, 0.8, 0.5490196078431373) - >>> colormode(255) - >>> turtle.pencolor() - (51.0, 204.0, 140.0) - >>> turtle.pencolor('#32c18f') - >>> turtle.pencolor() - (50.0, 193.0, 143.0) + >>> colormode() + 1.0 + >>> turtle.pencolor() + 'red' + >>> turtle.pencolor("brown") + >>> turtle.pencolor() + 'brown' + >>> tup = (0.2, 0.8, 0.55) + >>> turtle.pencolor(tup) + >>> turtle.pencolor() + (0.2, 0.8, 0.5490196078431373) + >>> colormode(255) + >>> turtle.pencolor() + (51.0, 204.0, 140.0) + >>> turtle.pencolor('#32c18f') + >>> turtle.pencolor() + (50.0, 193.0, 143.0) .. function:: fillcolor(*args) @@ -968,17 +968,17 @@ Color control .. doctest:: :skipif: _tkinter is None - >>> turtle.fillcolor("violet") - >>> turtle.fillcolor() - 'violet' - >>> turtle.pencolor() - (50.0, 193.0, 143.0) - >>> turtle.fillcolor((50, 193, 143)) # Integers, not floats - >>> turtle.fillcolor() - (50.0, 193.0, 143.0) - >>> turtle.fillcolor('#ffffff') - >>> turtle.fillcolor() - (255.0, 255.0, 255.0) + >>> turtle.fillcolor("violet") + >>> turtle.fillcolor() + 'violet' + >>> turtle.pencolor() + (50.0, 193.0, 143.0) + >>> turtle.fillcolor((50, 193, 143)) # Integers, not floats + >>> turtle.fillcolor() + (50.0, 193.0, 143.0) + >>> turtle.fillcolor('#ffffff') + >>> turtle.fillcolor() + (255.0, 255.0, 255.0) .. function:: color(*args) @@ -1007,12 +1007,12 @@ Color control .. doctest:: :skipif: _tkinter is None - >>> turtle.color("red", "green") - >>> turtle.color() - ('red', 'green') - >>> color("#285078", "#a0c8f0") - >>> color() - ((40.0, 80.0, 120.0), (160.0, 200.0, 240.0)) + >>> turtle.color("red", "green") + >>> turtle.color() + ('red', 'green') + >>> color("#285078", "#a0c8f0") + >>> color() + ((40.0, 80.0, 120.0), (160.0, 200.0, 240.0)) See also: Screen method :func:`colormode`. @@ -1034,11 +1034,11 @@ Filling .. doctest:: :skipif: _tkinter is None - >>> turtle.begin_fill() - >>> if turtle.filling(): - ... turtle.pensize(5) - ... else: - ... turtle.pensize(3) + >>> turtle.begin_fill() + >>> if turtle.filling(): + ... turtle.pensize(5) + ... else: + ... turtle.pensize(3) @@ -1244,11 +1244,11 @@ Appearance .. doctest:: :skipif: _tkinter is None - >>> turtle.shape("circle") - >>> turtle.shapesize(5,2) - >>> turtle.shearfactor(0.5) - >>> turtle.shearfactor() - 0.5 + >>> turtle.shape("circle") + >>> turtle.shapesize(5,2) + >>> turtle.shearfactor(0.5) + >>> turtle.shearfactor() + 0.5 .. function:: tilt(angle) @@ -1617,11 +1617,11 @@ Window control ``"nopic"``, delete background image, if present. If *picname* is ``None``, return the filename of the current backgroundimage. :: - >>> screen.bgpic() - 'nopic' - >>> screen.bgpic("landscape.gif") - >>> screen.bgpic() - "landscape.gif" + >>> screen.bgpic() + 'nopic' + >>> screen.bgpic("landscape.gif") + >>> screen.bgpic() + "landscape.gif" .. function:: clear() @@ -2028,16 +2028,16 @@ Settings and special methods Return the height of the turtle window. :: - >>> screen.window_height() - 480 + >>> screen.window_height() + 480 .. function:: window_width() Return the width of the turtle window. :: - >>> screen.window_width() - 640 + >>> screen.window_width() + 640 .. _screenspecific: @@ -2218,12 +2218,12 @@ facilities: in the range 0..colormode or a 3-tuple of such numbers. - >>> screen.bgcolor("orange") - >>> screen.bgcolor() - "orange" - >>> screen.bgcolor(0.5,0,0.5) - >>> screen.bgcolor() - "#800080" + >>> screen.bgcolor("orange") + >>> screen.bgcolor() + "orange" + >>> screen.bgcolor(0.5,0,0.5) + >>> screen.bgcolor() + "#800080" >>> help(Turtle.penup) Help on method penup in module turtle: From webhook-mailer at python.org Sat May 20 13:09:30 2023 From: webhook-mailer at python.org (gpshead) Date: Sat, 20 May 2023 17:09:30 -0000 Subject: [Python-checkins] gh-104372: Use non-Raw malloc for c_fds_to_keep in _posixsubprocess (#104697) Message-ID: <mailman.481.1684602571.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d1732feea0eadd4ccc3516440d0c071be0093dec commit: d1732feea0eadd4ccc3516440d0c071be0093dec branch: main author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-20T17:09:23Z summary: gh-104372: Use non-Raw malloc for c_fds_to_keep in _posixsubprocess (#104697) Use non-Raw malloc for c_fds_to_keep as the code could ask for 0 length. files: M Modules/_posixsubprocess.c diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 75965d338d59..1b7fe71186a1 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -1074,7 +1074,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, #endif /* HAVE_SETREUID */ } - c_fds_to_keep = PyMem_RawMalloc(fds_to_keep_len * sizeof(int)); + c_fds_to_keep = PyMem_Malloc(fds_to_keep_len * sizeof(int)); if (c_fds_to_keep == NULL) { PyErr_SetString(PyExc_MemoryError, "failed to malloc c_fds_to_keep"); goto cleanup; @@ -1157,7 +1157,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, cleanup: if (c_fds_to_keep != NULL) { - PyMem_RawFree(c_fds_to_keep); + PyMem_Free(c_fds_to_keep); } if (saved_errno != 0) { From webhook-mailer at python.org Sat May 20 16:12:17 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 20 May 2023 20:12:17 -0000 Subject: [Python-checkins] gh-49174: document that the effect of calling gc.collect() during a collection is undefined (#104699) Message-ID: <mailman.482.1684613538.13550.python-checkins@python.org> https://github.com/python/cpython/commit/30488fa22a8f63753192ae7f1d01665857764e45 commit: 30488fa22a8f63753192ae7f1d01665857764e45 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-20T21:12:10+01:00 summary: gh-49174: document that the effect of calling gc.collect() during a collection is undefined (#104699) files: M Doc/library/gc.rst diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 6d5c64df1a1f..0961ca4aaa94 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -50,6 +50,9 @@ The :mod:`gc` module provides the following functions: is run. Not all items in some free lists may be freed due to the particular implementation, in particular :class:`float`. + The effect of calling ``gc.collect()`` while the interpreter is already + performing a collection is undefined. + .. function:: set_debug(flags) From webhook-mailer at python.org Sat May 20 16:12:59 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 20 May 2023 20:12:59 -0000 Subject: [Python-checkins] [3.11] gh-49174: document that the effect of calling gc.collect() during a collection is undefined (GH-104699) (#104703) Message-ID: <mailman.483.1684613580.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d45c1df83ee89882b50d0a48b190d87767038848 commit: d45c1df83ee89882b50d0a48b190d87767038848 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-20T20:12:52Z summary: [3.11] gh-49174: document that the effect of calling gc.collect() during a collection is undefined (GH-104699) (#104703) gh-49174: document that the effect of calling gc.collect() during a collection is undefined (GH-104699) (cherry picked from commit 30488fa22a8f63753192ae7f1d01665857764e45) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: M Doc/library/gc.rst diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 42bb6dc3503f..5c2d0bbe0035 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -50,6 +50,9 @@ The :mod:`gc` module provides the following functions: is run. Not all items in some free lists may be freed due to the particular implementation, in particular :class:`float`. + The effect of calling ``gc.collect()`` while the interpreter is already + performing a collection is undefined. + .. function:: set_debug(flags) From webhook-mailer at python.org Sat May 20 16:16:56 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sat, 20 May 2023 20:16:56 -0000 Subject: [Python-checkins] gh-104683: Modernise Tools/clinic/ (#104684) Message-ID: <mailman.484.1684613816.13550.python-checkins@python.org> https://github.com/python/cpython/commit/19dd5aa89af4cc3150ed87f039601f87bc419be7 commit: 19dd5aa89af4cc3150ed87f039601f87bc419be7 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-20T20:16:49Z summary: gh-104683: Modernise Tools/clinic/ (#104684) - Make some string interpolations more readable using f-strings or explicit parametrisation - Remove unneeded open() mode specifiers Co-authored-by: Erlend E. Aasland <erlend.aasland at protonmail.com> files: M Tools/clinic/clinic.py M Tools/clinic/cpp.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index b00b480a684d..41e08d15436b 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -208,7 +208,7 @@ def is_legal_py_identifier(s: str) -> bool: def ensure_legal_c_identifier(s: str) -> str: # for now, just complain if what we're given isn't legal if not is_legal_c_identifier(s): - fail("Illegal C identifier: {}".format(s)) + fail("Illegal C identifier:", s) # but if we picked a C keyword, pick something else if s in c_keywords: return s + "_value" @@ -991,7 +991,7 @@ def parser_body(prototype, *fields, declarations=''): argname_fmt = 'PyTuple_GET_ITEM(args, %d)' - left_args = "{} - {}".format(nargs, max_pos) + left_args = f"{nargs} - {max_pos}" max_args = NO_VARARG if (vararg != NO_VARARG) else max_pos parser_code = [normalize_snippet(""" if (!_PyArg_CheckPositional("{name}", %s, %d, %s)) {{ @@ -1435,7 +1435,7 @@ def render_function(self, clinic, f): first_optional = min(first_optional, i) if p.is_vararg(): - data.cleanup.append("Py_XDECREF({});".format(c.parser_name)) + data.cleanup.append(f"Py_XDECREF({c.parser_name});") # insert group variable group = p.group @@ -1487,8 +1487,7 @@ def render_function(self, clinic, f): template_dict['c_basename'] = c_basename - methoddef_name = "{}_METHODDEF".format(c_basename.upper()) - template_dict['methoddef_name'] = methoddef_name + template_dict['methoddef_name'] = c_basename.upper() + "_METHODDEF" template_dict['docstring'] = self.docstring_for_c_string(f) @@ -1791,7 +1790,7 @@ def is_stop_line(line): for field in shlex.split(arguments): name, equals, value = field.partition('=') if not equals: - fail("Mangled Argument Clinic marker line: {!r}".format(line)) + fail("Mangled Argument Clinic marker line:", repr(line)) d[name.strip()] = value.strip() if self.verify: @@ -1867,7 +1866,10 @@ def print_block(self, block, *, core_includes=False): output += '\n' write(output) - arguments="output={} input={}".format(compute_checksum(output, 16), compute_checksum(input, 16)) + arguments = "output={output} input={input}".format( + output=compute_checksum(output, 16), + input=compute_checksum(input, 16) + ) write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments)) write("\n") @@ -1976,7 +1978,7 @@ def dump(self): def file_changed(filename: str, new_contents: str) -> bool: """Return true if file contents changed (meaning we must update it)""" try: - with open(filename, 'r', encoding="utf-8") as fp: + with open(filename, encoding="utf-8") as fp: old_contents = fp.read() return old_contents != new_contents except FileNotFoundError: @@ -2132,7 +2134,7 @@ def parse(self, input): dsl_name = block.dsl_name if dsl_name: if dsl_name not in self.parsers: - assert dsl_name in parsers, "No parser to handle {!r} block.".format(dsl_name) + assert dsl_name in parsers, f"No parser to handle {dsl_name!r} block." self.parsers[dsl_name] = parsers[dsl_name](self) parser = self.parsers[dsl_name] try: @@ -2172,7 +2174,7 @@ def parse(self, input): "can't make directory {}!".format( destination.filename, dirname)) if self.verify: - with open(destination.filename, "rt") as f: + with open(destination.filename) as f: parser_2 = BlockParser(f.read(), language=self.language) blocks = list(parser_2) if (len(blocks) != 1) or (blocks[0].input != 'preserve\n'): @@ -2239,7 +2241,7 @@ def parse_file( except KeyError: fail("Can't identify file type for file " + repr(filename)) - with open(filename, 'r', encoding="utf-8") as f: + with open(filename, encoding="utf-8") as f: raw = f.read() # exit quickly if there are no clinic markers in the file @@ -2537,9 +2539,9 @@ def get_displayname(self, i): if i == 0: return '"argument"' if not self.is_positional_only(): - return '''"argument '{}'"'''.format(self.name) + return f'"argument {self.name!r}"' else: - return '"argument {}"'.format(i) + return f'"argument {i}"' class LandMine: @@ -2723,7 +2725,8 @@ def __init__(self, if isinstance(self.default_type, type): types_str = self.default_type.__name__ else: - types_str = ', '.join((cls.__name__ for cls in self.default_type)) + names = [cls.__name__ for cls in self.default_type] + types_str = ', '.join(names) fail("{}: default value {!r} for field {} is not of type {}".format( self.__class__.__name__, default, name, types_str)) self.default = default @@ -3955,7 +3958,7 @@ def set_template_dict(self, template_dict): ' Py_TYPE({0})->tp_new == base_tp->tp_new)' ).format(self.name) - line = '{} &&\n '.format(type_check) + line = f'{type_check} &&\n ' template_dict['self_type_check'] = line type_object = self.function.cls.type_object @@ -4011,10 +4014,12 @@ def declare(self, data): data.return_value = data.converter_retval def err_occurred_if(self, expr, data): - data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n goto exit;\n}}\n'.format(expr)) + line = f'if (({expr}) && PyErr_Occurred()) {{\n goto exit;\n}}\n' + data.return_conversion.append(line) def err_occurred_if_null_pointer(self, variable, data): - data.return_conversion.append('if ({} == NULL) {{\n goto exit;\n}}\n'.format(variable)) + line = f'if ({variable} == NULL) {{\n goto exit;\n}}\n' + data.return_conversion.append(line) def render(self, function, data): """ @@ -4477,13 +4482,13 @@ def state_modulename_name(self, line): c_basename = c_basename.strip() or None if not is_legal_py_identifier(full_name): - fail("Illegal function name: {}".format(full_name)) + fail("Illegal function name:", full_name) if c_basename and not is_legal_c_identifier(c_basename): - fail("Illegal C basename: {}".format(c_basename)) + fail("Illegal C basename:", c_basename) return_converter = None if returns: - ast_input = "def x() -> {}: pass".format(returns) + ast_input = f"def x() -> {returns}: pass" module = None try: module = ast.parse(ast_input) @@ -4696,7 +4701,7 @@ def state_parameter(self, line): module = None try: - ast_input = "def x({}): pass".format(base) + ast_input = f"def x({base}): pass" module = ast.parse(ast_input) except SyntaxError: try: @@ -4704,7 +4709,7 @@ def state_parameter(self, line): # c: int(accept={str}) # so assume there was no actual default value. default = None - ast_input = "def x({}): pass".format(line) + ast_input = f"def x({line}): pass" module = ast.parse(ast_input) except SyntaxError: pass @@ -4748,8 +4753,7 @@ def state_parameter(self, line): self.parameter_state = self.ps_optional default = default.strip() bad = False - ast_input = "x = {}".format(default) - bad = False + ast_input = f"x = {default}" try: module = ast.parse(ast_input) @@ -4856,7 +4860,7 @@ def bad_node(self, node): dict = legacy_converters if legacy else converters legacy_str = "legacy " if legacy else "" if name not in dict: - fail('{} is not a valid {}converter'.format(name, legacy_str)) + fail(f'{name} is not a valid {legacy_str}converter') # if you use a c_name for the parameter, we just give that name to the converter # but the parameter object gets the python name converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs) @@ -5388,7 +5392,7 @@ def main(argv): for parameter_name, parameter in signature.parameters.items(): if parameter.kind == inspect.Parameter.KEYWORD_ONLY: if parameter.default != inspect.Parameter.empty: - s = '{}={!r}'.format(parameter_name, parameter.default) + s = f'{parameter_name}={parameter.default!r}' else: s = parameter_name parameters.append(s) diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index a3546f570c5a..c1a2eeef22de 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -185,7 +185,7 @@ def pop_stack() -> TokenAndCondition: if __name__ == '__main__': for filename in sys.argv[1:]: - with open(filename, "rt") as f: + with open(filename) as f: cpp = Monitor(filename, verbose=True) print() print(filename) From webhook-mailer at python.org Sat May 20 17:55:11 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sat, 20 May 2023 21:55:11 -0000 Subject: [Python-checkins] gh-104050: Add basic type hints to Argument Clinic DSL parser (#104704) Message-ID: <mailman.485.1684619712.13550.python-checkins@python.org> https://github.com/python/cpython/commit/27a68be77f7a5bfb7c4b97438571b4fcf5aae8b4 commit: 27a68be77f7a5bfb7c4b97438571b4fcf5aae8b4 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-20T21:55:02Z summary: gh-104050: Add basic type hints to Argument Clinic DSL parser (#104704) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 41e08d15436b..863bd66bef75 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -324,9 +324,9 @@ def version_splitter(s: str) -> tuple[int, ...]: c -> -1 (This permits Python-style version strings such as "1.4b3".) """ - version = [] + version: list[int] = [] accumulator: list[str] = [] - def flush(): + def flush() -> None: if not accumulator: raise ValueError('Unsupported version string: ' + repr(s)) version.append(int(''.join(accumulator))) @@ -4201,8 +4201,10 @@ def dedent(self, line): return line[indent:] +StateKeeper = Callable[[str | None], None] + class DSLParser: - def __init__(self, clinic): + def __init__(self, clinic: Clinic) -> None: self.clinic = clinic self.directives = {} @@ -4219,9 +4221,9 @@ def __init__(self, clinic): self.reset() - def reset(self): + def reset(self) -> None: self.function = None - self.state = self.state_dsl_start + self.state: StateKeeper = self.state_dsl_start self.parameter_indent = None self.keyword_only = False self.positional_only = False @@ -4234,12 +4236,12 @@ def reset(self): self.parameter_continuation = '' self.preserve_output = False - def directive_version(self, required): + def directive_version(self, required: str) -> None: global version if version_comparitor(version, required) < 0: fail("Insufficient Clinic version!\n Version: " + version + "\n Required: " + required) - def directive_module(self, name): + def directive_module(self, name: str) -> None: fields = name.split('.')[:-1] module, cls = self.clinic._module_and_class(fields) if cls: @@ -4252,9 +4254,13 @@ def directive_module(self, name): module.modules[name] = m self.block.signatures.append(m) - def directive_class(self, name, typedef, type_object): + def directive_class( + self, + name: str, + typedef: str, + type_object: str + ) -> None: fields = name.split('.') - parent = self name = fields.pop() module, cls = self.clinic._module_and_class(fields) @@ -4266,7 +4272,7 @@ def directive_class(self, name, typedef, type_object): parent.classes[name] = c self.block.signatures.append(c) - def directive_set(self, name, value): + def directive_set(self, name: str, value: str) -> None: if name not in ("line_prefix", "line_suffix"): fail("unknown variable", repr(name)) @@ -4277,7 +4283,12 @@ def directive_set(self, name, value): self.clinic.__dict__[name] = value - def directive_destination(self, name, command, *args): + def directive_destination( + self, + name: str, + command: str, + *args + ) -> None: if command == 'new': self.clinic.add_destination(name, *args) return @@ -4287,7 +4298,11 @@ def directive_destination(self, name, command, *args): fail("unknown destination command", repr(command)) - def directive_output(self, command_or_name, destination=''): + def directive_output( + self, + command_or_name: str, + destination: str = '' + ) -> None: fd = self.clinic.destination_buffers if command_or_name == "preset": @@ -4325,34 +4340,34 @@ def directive_output(self, command_or_name, destination=''): fail("Invalid command / destination name " + repr(command_or_name) + ", must be one of:\n preset push pop print everything " + " ".join(fd)) fd[command_or_name] = d - def directive_dump(self, name): + def directive_dump(self, name: str) -> None: self.block.output.append(self.clinic.get_destination(name).dump()) - def directive_printout(self, *args): + def directive_printout(self, *args: str) -> None: self.block.output.append(' '.join(args)) self.block.output.append('\n') - def directive_preserve(self): + def directive_preserve(self) -> None: if self.preserve_output: fail("Can't have preserve twice in one block!") self.preserve_output = True - def at_classmethod(self): + def at_classmethod(self) -> None: if self.kind is not CALLABLE: fail("Can't set @classmethod, function is not a normal callable") self.kind = CLASS_METHOD - def at_staticmethod(self): + def at_staticmethod(self) -> None: if self.kind is not CALLABLE: fail("Can't set @staticmethod, function is not a normal callable") self.kind = STATIC_METHOD - def at_coexist(self): + def at_coexist(self) -> None: if self.coexist: fail("Called @coexist twice!") self.coexist = True - def parse(self, block): + def parse(self, block: Block) -> None: self.reset() self.block = block self.saved_output = self.block.output @@ -4388,10 +4403,14 @@ def ignore_line(line): return False @staticmethod - def calculate_indent(line): + def calculate_indent(line: str) -> int: return len(line) - len(line.strip()) - def next(self, state, line=None): + def next( + self, + state: StateKeeper, + line: str | None = None + ) -> None: # real_print(self.state.__name__, "->", state.__name__, ", line=", line) self.state = state if line is not None: From webhook-mailer at python.org Sat May 20 18:26:56 2023 From: webhook-mailer at python.org (gpshead) Date: Sat, 20 May 2023 22:26:56 -0000 Subject: [Python-checkins] gh-103606: raise RuntimeError if config file is invalid or empty (#104701) Message-ID: <mailman.486.1684621617.13550.python-checkins@python.org> https://github.com/python/cpython/commit/12f1581b0c43f40a792c188e17d2dea2357debb3 commit: 12f1581b0c43f40a792c188e17d2dea2357debb3 branch: main author: Prince Roshan <princekrroshan01 at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-20T22:26:49Z summary: gh-103606: raise RuntimeError if config file is invalid or empty (#104701) (this adjusts new code) raise RuntimeError if provided config file is invalid or empty, not ValueError. files: 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 452832f26aa7..448978f43b6d 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -88,7 +88,7 @@ in :mod:`logging` itself) and defining handlers which are declared either in configuration). It will raise :exc:`FileNotFoundError` if the file - doesn't exist and :exc:`ValueError` if the file is invalid or + doesn't exist and :exc:`RuntimeError` if the file is invalid or empty. :param fname: A filename, or a file-like object, or an instance derived @@ -130,7 +130,7 @@ in :mod:`logging` itself) and defining handlers which are declared either in .. versionadded:: 3.10 The *encoding* parameter is added. - .. versionadded:: 3.12 + .. versionchanged:: 3.12 An exception will be thrown if the provided file doesn't exist or is invalid or empty. diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 652f21ecb459..a68281d3e359 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -65,7 +65,7 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non if not os.path.exists(fname): raise FileNotFoundError(f"{fname} doesn't exist") elif not os.path.getsize(fname): - raise ValueError(f'{fname} is an empty file') + raise RuntimeError(f'{fname} is an empty file') if isinstance(fname, configparser.RawConfigParser): cp = fname @@ -78,7 +78,7 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non encoding = io.text_encoding(encoding) cp.read(fname, encoding=encoding) except configparser.ParsingError as e: - raise ValueError(f'{fname} is invalid: {e}') + raise RuntimeError(f'{fname} is invalid: {e}') formatters = _create_formatters(cp) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index ba836a7d9ea3..18258c22874a 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1781,12 +1781,12 @@ def test_exception_if_confg_file_is_invalid(self): """ file = io.StringIO(textwrap.dedent(test_config)) - self.assertRaises(ValueError, logging.config.fileConfig, file) + self.assertRaises(RuntimeError, logging.config.fileConfig, file) def test_exception_if_confg_file_is_empty(self): fd, fn = tempfile.mkstemp(prefix='test_empty_', suffix='.ini') os.close(fd) - self.assertRaises(ValueError, logging.config.fileConfig, fn) + self.assertRaises(RuntimeError, logging.config.fileConfig, fn) os.remove(fn) def test_exception_if_config_file_does_not_exist(self): From webhook-mailer at python.org Sat May 20 19:33:16 2023 From: webhook-mailer at python.org (gpshead) Date: Sat, 20 May 2023 23:33:16 -0000 Subject: [Python-checkins] gh-61460: Stronger HMAC in multiprocessing (#20380) Message-ID: <mailman.487.1684625597.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3ed57e4995d9f8583083483f397ddc3131720953 commit: 3ed57e4995d9f8583083483f397ddc3131720953 branch: main author: Christian Heimes <christian at python.org> committer: gpshead <greg at krypto.org> date: 2023-05-20T23:33:09Z summary: gh-61460: Stronger HMAC in multiprocessing (#20380) bpo-17258: `multiprocessing` now supports stronger HMAC algorithms for inter-process connection authentication rather than only HMAC-MD5. Signed-off-by: Christian Heimes <christian at python.org> gpshead: I Reworked to be more robust while keeping the idea. The protocol modification idea remains, but we now take advantage of the message length as an indicator of legacy vs modern protocol version. No more regular expression usage. We now default to HMAC-SHA256, but do so in a way that will be compatible when communicating with older clients or older servers. No protocol transition period is needed. More integration tests to verify these claims remain true are required. I'm unaware of anyone depending on multiprocessing connections between different Python versions. --------- Signed-off-by: Christian Heimes <christian at python.org> Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst M Lib/multiprocessing/connection.py M Lib/test/_test_multiprocessing.py diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 1a8822b9db01..04eaea811cfb 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -722,11 +722,11 @@ def PipeClient(address): # Authentication stuff # -MESSAGE_LENGTH = 20 +MESSAGE_LENGTH = 40 # MUST be > 20 -CHALLENGE = b'#CHALLENGE#' -WELCOME = b'#WELCOME#' -FAILURE = b'#FAILURE#' +_CHALLENGE = b'#CHALLENGE#' +_WELCOME = b'#WELCOME#' +_FAILURE = b'#FAILURE#' # multiprocessing.connection Authentication Handshake Protocol Description # (as documented for reference after reading the existing code) @@ -750,7 +750,12 @@ def PipeClient(address): # ------------------------------ --------------------------------------- # 0. Open a connection on the pipe. # 1. Accept connection. -# 2. New random 20 bytes -> MESSAGE +# 2. Random 20+ bytes -> MESSAGE +# Modern servers always send +# more than 20 bytes and include +# a {digest} prefix on it with +# their preferred HMAC digest. +# Legacy ones send ==20 bytes. # 3. send 4 byte length (net order) # prefix followed by: # b'#CHALLENGE#' + MESSAGE @@ -763,14 +768,32 @@ def PipeClient(address): # 6. Assert that M1 starts with: # b'#CHALLENGE#' # 7. Strip that prefix from M1 into -> M2 -# 8. Compute HMAC-MD5 of AUTHKEY, M2 -> C_DIGEST +# 7.1. Parse M2: if it is exactly 20 bytes in +# length this indicates a legacy server +# supporting only HMAC-MD5. Otherwise the +# 7.2. preferred digest is looked up from an +# expected "{digest}" prefix on M2. No prefix +# or unsupported digest? <- AuthenticationError +# 7.3. Put divined algorithm name in -> D_NAME +# 8. Compute HMAC-D_NAME of AUTHKEY, M2 -> C_DIGEST # 9. Send 4 byte length prefix (net order) # followed by C_DIGEST bytes. -# 10. Compute HMAC-MD5 of AUTHKEY, -# MESSAGE into -> M_DIGEST. -# 11. Receive 4 or 4+8 byte length +# 10. Receive 4 or 4+8 byte length # prefix (#4 dance) -> SIZE. -# 12. Receive min(SIZE, 256) -> C_D. +# 11. Receive min(SIZE, 256) -> C_D. +# 11.1. Parse C_D: legacy servers +# accept it as is, "md5" -> D_NAME +# 11.2. modern servers check the length +# of C_D, IF it is 16 bytes? +# 11.2.1. "md5" -> D_NAME +# and skip to step 12. +# 11.3. longer? expect and parse a "{digest}" +# prefix into -> D_NAME. +# Strip the prefix and store remaining +# bytes in -> C_D. +# 11.4. Don't like D_NAME? <- AuthenticationError +# 12. Compute HMAC-D_NAME of AUTHKEY, +# MESSAGE into -> M_DIGEST. # 13. Compare M_DIGEST == C_D: # 14a: Match? Send length prefix & # b'#WELCOME#' @@ -787,42 +810,139 @@ def PipeClient(address): # # If this RETURNed, the connection remains open: it has been authenticated. # -# Length prefixes are used consistently even though every step so far has -# always been a singular specific fixed length. This may help us evolve -# the protocol in the future without breaking backwards compatibility. -# -# Similarly the initial challenge message from the serving side has always -# been 20 bytes, but clients can accept a 100+ so using the length of the -# opening challenge message as an indicator of protocol version may work. +# Length prefixes are used consistently. Even on the legacy protocol, this +# was good fortune and allowed us to evolve the protocol by using the length +# of the opening challenge or length of the returned digest as a signal as +# to which protocol the other end supports. + +_ALLOWED_DIGESTS = frozenset( + {b'md5', b'sha256', b'sha384', b'sha3_256', b'sha3_384'}) +_MAX_DIGEST_LEN = max(len(_) for _ in _ALLOWED_DIGESTS) + +# Old hmac-md5 only server versions from Python <=3.11 sent a message of this +# length. It happens to not match the length of any supported digest so we can +# use a message of this length to indicate that we should work in backwards +# compatible md5-only mode without a {digest_name} prefix on our response. +_MD5ONLY_MESSAGE_LENGTH = 20 +_MD5_DIGEST_LEN = 16 +_LEGACY_LENGTHS = (_MD5ONLY_MESSAGE_LENGTH, _MD5_DIGEST_LEN) + + +def _get_digest_name_and_payload(message: bytes) -> (str, bytes): + """Returns a digest name and the payload for a response hash. + + If a legacy protocol is detected based on the message length + or contents the digest name returned will be empty to indicate + legacy mode where MD5 and no digest prefix should be sent. + """ + # modern message format: b"{digest}payload" longer than 20 bytes + # legacy message format: 16 or 20 byte b"payload" + if len(message) in _LEGACY_LENGTHS: + # Either this was a legacy server challenge, or we're processing + # a reply from a legacy client that sent an unprefixed 16-byte + # HMAC-MD5 response. All messages using the modern protocol will + # be longer than either of these lengths. + return '', message + if (message.startswith(b'{') and + (curly := message.find(b'}', 1, _MAX_DIGEST_LEN+2)) > 0): + digest = message[1:curly] + if digest in _ALLOWED_DIGESTS: + payload = message[curly+1:] + return digest.decode('ascii'), payload + raise AuthenticationError( + 'unsupported message length, missing digest prefix, ' + f'or unsupported digest: {message=}') + + +def _create_response(authkey, message): + """Create a MAC based on authkey and message + + The MAC algorithm defaults to HMAC-MD5, unless MD5 is not available or + the message has a '{digest_name}' prefix. For legacy HMAC-MD5, the response + is the raw MAC, otherwise the response is prefixed with '{digest_name}', + e.g. b'{sha256}abcdefg...' + + Note: The MAC protects the entire message including the digest_name prefix. + """ + import hmac + digest_name = _get_digest_name_and_payload(message)[0] + # The MAC protects the entire message: digest header and payload. + if not digest_name: + # Legacy server without a {digest} prefix on message. + # Generate a legacy non-prefixed HMAC-MD5 reply. + try: + return hmac.new(authkey, message, 'md5').digest() + except ValueError: + # HMAC-MD5 is not available (FIPS mode?), fall back to + # HMAC-SHA2-256 modern protocol. The legacy server probably + # doesn't support it and will reject us anyways. :shrug: + digest_name = 'sha256' + # Modern protocol, indicate the digest used in the reply. + response = hmac.new(authkey, message, digest_name).digest() + return b'{%s}%s' % (digest_name.encode('ascii'), response) + + +def _verify_challenge(authkey, message, response): + """Verify MAC challenge + + If our message did not include a digest_name prefix, the client is allowed + to select a stronger digest_name from _ALLOWED_DIGESTS. + + In case our message is prefixed, a client cannot downgrade to a weaker + algorithm, because the MAC is calculated over the entire message + including the '{digest_name}' prefix. + """ + import hmac + response_digest, response_mac = _get_digest_name_and_payload(response) + response_digest = response_digest or 'md5' + try: + expected = hmac.new(authkey, message, response_digest).digest() + except ValueError: + raise AuthenticationError(f'{response_digest=} unsupported') + if len(expected) != len(response_mac): + raise AuthenticationError( + f'expected {response_digest!r} of length {len(expected)} ' + f'got {len(response_mac)}') + if not hmac.compare_digest(expected, response_mac): + raise AuthenticationError('digest received was wrong') -def deliver_challenge(connection, authkey): - import hmac +def deliver_challenge(connection, authkey: bytes, digest_name='sha256'): if not isinstance(authkey, bytes): raise ValueError( "Authkey must be bytes, not {0!s}".format(type(authkey))) + assert MESSAGE_LENGTH > _MD5ONLY_MESSAGE_LENGTH, "protocol constraint" message = os.urandom(MESSAGE_LENGTH) - connection.send_bytes(CHALLENGE + message) - digest = hmac.new(authkey, message, 'md5').digest() + message = b'{%s}%s' % (digest_name.encode('ascii'), message) + # Even when sending a challenge to a legacy client that does not support + # digest prefixes, they'll take the entire thing as a challenge and + # respond to it with a raw HMAC-MD5. + connection.send_bytes(_CHALLENGE + message) response = connection.recv_bytes(256) # reject large message - if response == digest: - connection.send_bytes(WELCOME) + try: + _verify_challenge(authkey, message, response) + except AuthenticationError: + connection.send_bytes(_FAILURE) + raise else: - connection.send_bytes(FAILURE) - raise AuthenticationError('digest received was wrong') + connection.send_bytes(_WELCOME) -def answer_challenge(connection, authkey): - import hmac + +def answer_challenge(connection, authkey: bytes): if not isinstance(authkey, bytes): raise ValueError( "Authkey must be bytes, not {0!s}".format(type(authkey))) message = connection.recv_bytes(256) # reject large message - assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message - message = message[len(CHALLENGE):] - digest = hmac.new(authkey, message, 'md5').digest() + if not message.startswith(_CHALLENGE): + raise AuthenticationError( + f'Protocol error, expected challenge: {message=}') + message = message[len(_CHALLENGE):] + if len(message) < _MD5ONLY_MESSAGE_LENGTH: + raise AuthenticationError('challenge too short: {len(message)} bytes') + digest = _create_response(authkey, message) connection.send_bytes(digest) response = connection.recv_bytes(256) # reject large message - if response != WELCOME: + if response != _WELCOME: raise AuthenticationError('digest sent was rejected') # diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 9a2db24b4bd5..767f049b0d71 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -48,6 +48,7 @@ import multiprocessing.managers import multiprocessing.pool import multiprocessing.queues +from multiprocessing.connection import wait, AuthenticationError from multiprocessing import util @@ -131,8 +132,6 @@ def _resource_unlink(name, rtype): WIN32 = (sys.platform == "win32") -from multiprocessing.connection import wait - def wait_for_handle(handle, timeout): if timeout is not None and timeout < 0.0: timeout = None @@ -3042,7 +3041,7 @@ def test_remote(self): del queue - at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') class _TestManagerRestart(BaseTestCase): @classmethod @@ -3531,7 +3530,7 @@ def test_dont_merge(self): # @unittest.skipUnless(HAS_REDUCTION, "test needs multiprocessing.reduction") - at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') class _TestPicklingConnections(BaseTestCase): ALLOWED_TYPES = ('processes',) @@ -3834,7 +3833,7 @@ def test_copy(self): @unittest.skipUnless(HAS_SHMEM, "requires multiprocessing.shared_memory") - at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') class _TestSharedMemory(BaseTestCase): ALLOWED_TYPES = ('processes',) @@ -4636,7 +4635,7 @@ def test_invalid_handles(self): - at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') class OtherTest(unittest.TestCase): # TODO: add more tests for deliver/answer challenge. def test_deliver_challenge_auth_failure(self): @@ -4656,7 +4655,7 @@ def __init__(self): def recv_bytes(self, size): self.count += 1 if self.count == 1: - return multiprocessing.connection.CHALLENGE + return multiprocessing.connection._CHALLENGE elif self.count == 2: return b'something bogus' return b'' @@ -4666,6 +4665,44 @@ def send_bytes(self, data): multiprocessing.connection.answer_challenge, _FakeConnection(), b'abc') + + at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') +class ChallengeResponseTest(unittest.TestCase): + authkey = b'supadupasecretkey' + + def create_response(self, message): + return multiprocessing.connection._create_response( + self.authkey, message + ) + + def verify_challenge(self, message, response): + return multiprocessing.connection._verify_challenge( + self.authkey, message, response + ) + + def test_challengeresponse(self): + for algo in [None, "md5", "sha256"]: + with self.subTest(f"{algo=}"): + msg = b'is-twenty-bytes-long' # The length of a legacy message. + if algo: + prefix = b'{%s}' % algo.encode("ascii") + else: + prefix = b'' + msg = prefix + msg + response = self.create_response(msg) + if not response.startswith(prefix): + self.fail(response) + self.verify_challenge(msg, response) + + # TODO(gpshead): We need integration tests for handshakes between modern + # deliver_challenge() and verify_response() code and connections running a + # test-local copy of the legacy Python <=3.11 implementations. + + # TODO(gpshead): properly annotate tests for requires_hashdigest rather than + # only running these on a platform supporting everything. otherwise logic + # issues preventing it from working on FIPS mode setups will be hidden. + # # Test Manager.start()/Pool.__init__() initializer feature - see issue 5585 # @@ -4673,7 +4710,7 @@ def send_bytes(self, data): def initializer(ns): ns.test += 1 - at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') class TestInitializers(unittest.TestCase): def setUp(self): self.mgr = multiprocessing.Manager() @@ -5537,7 +5574,7 @@ def is_alive(self): any(process.is_alive() for process in forked_processes)) - at hashlib_helper.requires_hashdigest('md5') + at hashlib_helper.requires_hashdigest('sha256') class TestSyncManagerTypes(unittest.TestCase): """Test all the types which can be shared between a parent and a child process by using a manager which acts as an intermediary @@ -5969,7 +6006,7 @@ def install_tests_in_module_dict(remote_globs, start_method): class Temp(base, Mixin, unittest.TestCase): pass if type_ == 'manager': - Temp = hashlib_helper.requires_hashdigest('md5')(Temp) + Temp = hashlib_helper.requires_hashdigest('sha256')(Temp) Temp.__name__ = Temp.__qualname__ = newname Temp.__module__ = __module__ remote_globs[newname] = Temp diff --git a/Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst b/Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst new file mode 100644 index 000000000000..18ebd6e140cf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst @@ -0,0 +1,2 @@ +:mod:`multiprocessing` now supports stronger HMAC algorithms for inter-process +connection authentication rather than only HMAC-MD5. From webhook-mailer at python.org Sat May 20 20:03:09 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 21 May 2023 00:03:09 -0000 Subject: [Python-checkins] gh-102856: Python tokenizer implementation for PEP 701 (#104323) Message-ID: <mailman.488.1684627390.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6715f91edcf6f379f666e18f57b8a0dcb724bf79 commit: 6715f91edcf6f379f666e18f57b8a0dcb724bf79 branch: main author: Marta G?mez Mac?as <mgmacias at google.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-21T01:03:02+01:00 summary: gh-102856: Python tokenizer implementation for PEP 701 (#104323) This commit replaces the Python implementation of the tokenize module with an implementation that reuses the real C tokenizer via a private extension module. The tokenize module now implements a compatibility layer that transforms tokens from the C tokenizer into Python tokenize tokens for backward compatibility. As the C tokenizer does not emit some tokens that the Python tokenizer provides (such as comments and non-semantic newlines), a new special mode has been added to the C tokenizer mode that currently is only used via the extension module that exposes it to the Python layer. This new mode forces the C tokenizer to emit these new extra tokens and add the appropriate metadata that is needed to match the old Python implementation. Co-authored-by: Pablo Galindo <pablogsal at gmail.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst M Doc/library/token-list.inc M Doc/library/token.rst M Grammar/Tokens M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_token.h M Include/internal/pycore_unicodeobject_generated.h M Lib/inspect.py M Lib/tabnanny.py M Lib/test/test_tabnanny.py M Lib/test/test_tokenize.py M Lib/token.py M Lib/tokenize.py M Parser/pegen.c M Parser/pegen_errors.c M Parser/token.c M Parser/tokenizer.c M Parser/tokenizer.h M Python/Python-tokenize.c M Python/clinic/Python-tokenize.c.h diff --git a/Doc/library/token-list.inc b/Doc/library/token-list.inc index 3b345099bf54..e885de88cad9 100644 --- a/Doc/library/token-list.inc +++ b/Doc/library/token-list.inc @@ -223,6 +223,10 @@ .. data:: FSTRING_END +.. data:: COMMENT + +.. data:: NL + .. data:: ERRORTOKEN .. data:: N_TOKENS diff --git a/Doc/library/token.rst b/Doc/library/token.rst index a1aceba96ce0..903847bb206d 100644 --- a/Doc/library/token.rst +++ b/Doc/library/token.rst @@ -50,11 +50,13 @@ The following token type values aren't used by the C tokenizer but are needed fo the :mod:`tokenize` module. .. data:: COMMENT + :noindex: Token value used to indicate a comment. .. data:: NL + :noindex: Token value used to indicate a non-terminating newline. The :data:`NEWLINE` token indicates the end of a logical line of Python code; diff --git a/Grammar/Tokens b/Grammar/Tokens index 096876fdd130..618ae811d824 100644 --- a/Grammar/Tokens +++ b/Grammar/Tokens @@ -64,9 +64,9 @@ SOFT_KEYWORD FSTRING_START FSTRING_MIDDLE FSTRING_END +COMMENT +NL ERRORTOKEN # These aren't used by the C tokenizer but are needed for tokenize.py -COMMENT -NL ENCODING diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 8ca3545d8b3f..5a1993eac23a 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -918,6 +918,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exception)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exp)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extend)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(extra_tokens)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(facility)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(factory)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(false)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 8e429bbfa26f..61967877ab4a 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -406,6 +406,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(exception) STRUCT_FOR_ID(exp) STRUCT_FOR_ID(extend) + STRUCT_FOR_ID(extra_tokens) STRUCT_FOR_ID(facility) STRUCT_FOR_ID(factory) STRUCT_FOR_ID(false) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 3edf076696d9..59ec49af358f 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -912,6 +912,7 @@ extern "C" { INIT_ID(exception), \ INIT_ID(exp), \ INIT_ID(extend), \ + INIT_ID(extra_tokens), \ INIT_ID(facility), \ INIT_ID(factory), \ INIT_ID(false), \ diff --git a/Include/internal/pycore_token.h b/Include/internal/pycore_token.h index b9df8766736a..c02e637fee1e 100644 --- a/Include/internal/pycore_token.h +++ b/Include/internal/pycore_token.h @@ -77,7 +77,9 @@ extern "C" { #define FSTRING_START 61 #define FSTRING_MIDDLE 62 #define FSTRING_END 63 -#define ERRORTOKEN 64 +#define COMMENT 64 +#define NL 65 +#define ERRORTOKEN 66 #define N_TOKENS 68 #define NT_OFFSET 256 diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 0e1f71798a6e..8f8a067e4c18 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1059,6 +1059,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(extend); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(extra_tokens); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(facility); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Lib/inspect.py b/Lib/inspect.py index 63f5aa91d270..7709a95003ef 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2187,7 +2187,7 @@ def _signature_strip_non_python_syntax(signature): if string == ',': current_parameter += 1 - if (type == ERRORTOKEN) and (string == '$'): + if (type == OP) and (string == '$'): assert self_parameter is None self_parameter = current_parameter continue @@ -2195,7 +2195,7 @@ def _signature_strip_non_python_syntax(signature): add(string) if (string == ','): add(' ') - clean_signature = ''.join(text) + clean_signature = ''.join(text).strip() return clean_signature, self_parameter diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index 9d2df59d36ff..e2ac6837f157 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -107,6 +107,10 @@ def check(file): errprint("%r: Token Error: %s" % (file, msg)) return + except SyntaxError as msg: + errprint("%r: Token Error: %s" % (file, msg)) + return + except IndentationError as msg: errprint("%r: Indentation Error: %s" % (file, msg)) return @@ -272,6 +276,12 @@ def format_witnesses(w): return prefix + " " + ', '.join(firsts) def process_tokens(tokens): + try: + _process_tokens(tokens) + except TabError as e: + raise NannyNag(e.lineno, e.msg, e.text) + +def _process_tokens(tokens): INDENT = tokenize.INDENT DEDENT = tokenize.DEDENT NEWLINE = tokenize.NEWLINE diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index afb8da719b0e..dac47318011d 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -223,7 +223,7 @@ def test_when_nannynag_error_verbose(self): with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: out = f"{file_path!r}: *** Line 3: trouble in tab city! ***\n" out += "offending line: '\\tprint(\"world\")\\n'\n" - out += "indent not equal e.g. at tab size 1\n" + out += "inconsistent use of tabs and spaces in indentation\n" tabnanny.verbose = 1 self.verify_tabnanny_check(file_path, out=out) @@ -315,7 +315,7 @@ def validate_cmd(self, *args, stdout="", stderr="", partial=False, expect_failur def test_with_errored_file(self): """Should displays error when errored python file is given.""" with TemporaryPyFile(SOURCE_CODES["wrong_indented"]) as file_path: - stderr = f"{file_path!r}: Indentation Error: " + stderr = f"{file_path!r}: Token Error: " stderr += ('unindent does not match any outer indentation level' ' (<tokenize>, line 3)') self.validate_cmd(file_path, stderr=stderr, expect_failure=True) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 911b53e58165..dda7243bfa19 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -3,7 +3,7 @@ from tokenize import (tokenize, _tokenize, untokenize, NUMBER, NAME, OP, STRING, ENDMARKER, ENCODING, tok_name, detect_encoding, open as tokenize_open, Untokenizer, generate_tokens, - NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT) + NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT, TokenInfo) from io import BytesIO, StringIO import unittest from textwrap import dedent @@ -82,7 +82,7 @@ def test_basic(self): NAME 'False' (4, 11) (4, 16) COMMENT '# NEWLINE' (4, 17) (4, 26) NEWLINE '\\n' (4, 26) (4, 27) - DEDENT '' (5, 0) (5, 0) + DEDENT '' (4, 27) (4, 27) """) indent_error_file = b"""\ def k(x): @@ -230,6 +230,10 @@ def number_token(s): continue self.assertEqual(number_token(lit), lit) for lit in INVALID_UNDERSCORE_LITERALS: + try: + number_token(lit) + except SyntaxError: + continue self.assertNotEqual(number_token(lit), lit) def test_string(self): @@ -381,21 +385,119 @@ def test_string(self): STRING 'rb"\""a\\\\\\nb\\\\\\nc"\""' (1, 0) (3, 4) """) 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) + OP '{' (1, 4) (1, 5) + NAME 'b' (1, 5) (1, 6) + OP '}' (1, 6) (1, 7) + FSTRING_MIDDLE 'c' (1, 7) (1, 8) + FSTRING_END '"' (1, 8) (1, 9) + """) + self.check_tokenize('fR"a{{{b!r}}}c"', """\ + FSTRING_START 'fR"' (1, 0) (1, 3) + FSTRING_MIDDLE 'a{' (1, 3) (1, 5) + OP '{' (1, 6) (1, 7) + NAME 'b' (1, 7) (1, 8) + OP '!' (1, 8) (1, 9) + NAME 'r' (1, 9) (1, 10) + OP '}' (1, 10) (1, 11) + FSTRING_MIDDLE '}' (1, 11) (1, 12) + FSTRING_MIDDLE 'c' (1, 13) (1, 14) + FSTRING_END '"' (1, 14) (1, 15) + """) + self.check_tokenize('f"{{{1+1}}}"', """\ + FSTRING_START 'f"' (1, 0) (1, 2) + FSTRING_MIDDLE '{' (1, 2) (1, 3) + OP '{' (1, 4) (1, 5) + NUMBER '1' (1, 5) (1, 6) + OP '+' (1, 6) (1, 7) + NUMBER '1' (1, 7) (1, 8) + OP '}' (1, 8) (1, 9) + FSTRING_MIDDLE '}' (1, 9) (1, 10) + FSTRING_END '"' (1, 11) (1, 12) + """) + self.check_tokenize('f"""{f\'\'\'{f\'{f"{1+1}"}\'}\'\'\'}"""', """\ + FSTRING_START 'f\"""' (1, 0) (1, 4) + OP '{' (1, 4) (1, 5) + FSTRING_START "f'''" (1, 5) (1, 9) + OP '{' (1, 9) (1, 10) + FSTRING_START "f'" (1, 10) (1, 12) + OP '{' (1, 12) (1, 13) + FSTRING_START 'f"' (1, 13) (1, 15) + OP '{' (1, 15) (1, 16) + NUMBER '1' (1, 16) (1, 17) + OP '+' (1, 17) (1, 18) + NUMBER '1' (1, 18) (1, 19) + OP '}' (1, 19) (1, 20) + FSTRING_END '"' (1, 20) (1, 21) + OP '}' (1, 21) (1, 22) + FSTRING_END "'" (1, 22) (1, 23) + OP '}' (1, 23) (1, 24) + FSTRING_END "'''" (1, 24) (1, 27) + OP '}' (1, 27) (1, 28) + FSTRING_END '\"""' (1, 28) (1, 31) + """) + self.check_tokenize('f""" x\nstr(data, encoding={invalid!r})\n"""', """\ + FSTRING_START 'f\"""' (1, 0) (1, 4) + FSTRING_MIDDLE ' x\\nstr(data, encoding=' (1, 4) (2, 19) + OP '{' (2, 19) (2, 20) + NAME 'invalid' (2, 20) (2, 27) + OP '!' (2, 27) (2, 28) + NAME 'r' (2, 28) (2, 29) + OP '}' (2, 29) (2, 30) + FSTRING_MIDDLE ')\\n' (2, 30) (3, 0) + FSTRING_END '\"""' (3, 0) (3, 3) + """) + self.check_tokenize('f"""123456789\nsomething{None}bad"""', """\ + FSTRING_START 'f\"""' (1, 0) (1, 4) + FSTRING_MIDDLE '123456789\\nsomething' (1, 4) (2, 9) + OP '{' (2, 9) (2, 10) + NAME 'None' (2, 10) (2, 14) + OP '}' (2, 14) (2, 15) + FSTRING_MIDDLE 'bad' (2, 15) (2, 18) + FSTRING_END '\"""' (2, 18) (2, 21) """) 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) + """) + self.check_tokenize("f'some words {a+b:.3f} more words {c+d=} final words'", """\ + FSTRING_START "f'" (1, 0) (1, 2) + FSTRING_MIDDLE 'some words ' (1, 2) (1, 13) + OP '{' (1, 13) (1, 14) + NAME 'a' (1, 14) (1, 15) + OP '+' (1, 15) (1, 16) + NAME 'b' (1, 16) (1, 17) + OP ':' (1, 17) (1, 18) + FSTRING_MIDDLE '.3f' (1, 18) (1, 21) + OP '}' (1, 21) (1, 22) + FSTRING_MIDDLE ' more words ' (1, 22) (1, 34) + OP '{' (1, 34) (1, 35) + NAME 'c' (1, 35) (1, 36) + OP '+' (1, 36) (1, 37) + NAME 'd' (1, 37) (1, 38) + OP '=' (1, 38) (1, 39) + OP '}' (1, 39) (1, 40) + FSTRING_MIDDLE ' final words' (1, 40) (1, 52) + FSTRING_END "'" (1, 52) (1, 53) """) def test_function(self): @@ -644,8 +746,8 @@ def test_tabs(self): NEWLINE '\\n' (2, 5) (2, 6) INDENT ' \\t' (3, 0) (3, 9) NAME 'pass' (3, 9) (3, 13) - DEDENT '' (4, 0) (4, 0) - DEDENT '' (4, 0) (4, 0) + DEDENT '' (3, 14) (3, 14) + DEDENT '' (3, 14) (3, 14) """) def test_non_ascii_identifiers(self): @@ -857,7 +959,7 @@ async def foo(): NUMBER '1' (2, 17) (2, 18) OP ':' (2, 18) (2, 19) NAME 'pass' (2, 20) (2, 24) - DEDENT '' (3, 0) (3, 0) + DEDENT '' (2, 25) (2, 25) """) self.check_tokenize('''async def foo(async): await''', """\ @@ -905,7 +1007,7 @@ async def bar(): pass NAME 'await' (6, 2) (6, 7) OP '=' (6, 8) (6, 9) NUMBER '2' (6, 10) (6, 11) - DEDENT '' (7, 0) (7, 0) + DEDENT '' (6, 12) (6, 12) """) self.check_tokenize('''\ @@ -943,7 +1045,7 @@ async def bar(): pass NAME 'await' (6, 2) (6, 7) OP '=' (6, 8) (6, 9) NUMBER '2' (6, 10) (6, 11) - DEDENT '' (7, 0) (7, 0) + DEDENT '' (6, 12) (6, 12) """) class GenerateTokensTest(TokenizeTest): @@ -968,7 +1070,7 @@ def decistmt(s): ]) else: result.append((toknum, tokval)) - return untokenize(result).decode('utf-8') + return untokenize(result).decode('utf-8').strip() class TestMisc(TestCase): @@ -1040,33 +1142,16 @@ def readline(): nonlocal first if not first: first = True - return line + yield line else: - return b'' + yield b'' # skip the initial encoding token and the end tokens - tokens = list(_tokenize(readline, encoding='utf-8'))[1:-2] - expected_tokens = [(3, '"?????"', (1, 0), (1, 7), '"?????"')] + tokens = list(_tokenize(readline(), encoding='utf-8'))[:-2] + expected_tokens = [TokenInfo(3, '"?????"', (1, 0), (1, 7), '"?????"\n')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") - def test__tokenize_does_not_decode_with_encoding_none(self): - literal = '"?????"' - first = False - def readline(): - nonlocal first - if not first: - first = True - return literal - else: - return b'' - - # skip the end tokens - tokens = list(_tokenize(readline, encoding=None))[:-2] - expected_tokens = [(3, '"?????"', (1, 0), (1, 7), '"?????"')] - self.assertEqual(tokens, expected_tokens, - "string not tokenized when encoding is None") - class TestDetectEncoding(TestCase): @@ -1326,7 +1411,7 @@ class TestTokenize(TestCase): def test_tokenize(self): import tokenize as tokenize_module - encoding = object() + encoding = "utf-8" encoding_used = None def mock_detect_encoding(readline): return encoding, [b'first', b'second'] @@ -1336,7 +1421,10 @@ def mock__tokenize(readline, encoding): encoding_used = encoding out = [] while True: - next_line = readline() + try: + next_line = next(readline) + except StopIteration: + return out if next_line: out.append(next_line) continue @@ -1356,7 +1444,7 @@ def mock_readline(): tokenize_module._tokenize = mock__tokenize try: results = tokenize(mock_readline) - self.assertEqual(list(results), + self.assertEqual(list(results)[1:], [b'first', b'second', b'1', b'2', b'3', b'4']) finally: tokenize_module.detect_encoding = orig_detect_encoding @@ -1652,8 +1740,8 @@ def test_random_files(self): if support.verbose >= 2: print('tokenize', testfile) with open(testfile, 'rb') as f: - with self.subTest(file=testfile): - self.check_roundtrip(f) + # with self.subTest(file=testfile): + self.check_roundtrip(f) def roundtrip(self, code): @@ -2496,13 +2584,13 @@ async def bar(): pass def test_unicode(self): self.check_tokenize("?rter = u'places'\ngr?n = U'green'", """\ - NAME '?rter' (1, 0) (1, 6) - EQUAL '=' (1, 7) (1, 8) - STRING "u'places'" (1, 9) (1, 18) - NEWLINE '' (1, 18) (1, 18) - NAME 'gr?n' (2, 0) (2, 5) - EQUAL '=' (2, 6) (2, 7) - STRING "U'green'" (2, 8) (2, 16) + NAME '?rter' (1, 0) (1, 5) + EQUAL '=' (1, 6) (1, 7) + STRING "u'places'" (1, 8) (1, 17) + NEWLINE '' (1, 17) (1, 17) + NAME 'gr?n' (2, 0) (2, 4) + EQUAL '=' (2, 5) (2, 6) + STRING "U'green'" (2, 7) (2, 15) """) def test_invalid_syntax(self): @@ -2559,8 +2647,7 @@ def generate_source(indents): compile(valid, "<string>", "exec") invalid = generate_source(MAXINDENT) - tokens = list(_generate_tokens_from_c_tokenizer(invalid)) - self.assertEqual(tokens[-1].type, NEWLINE) + self.assertRaises(SyntaxError, lambda: list(_generate_tokens_from_c_tokenizer(invalid))) self.assertRaises( IndentationError, compile, invalid, "<string>", "exec" ) diff --git a/Lib/token.py b/Lib/token.py index 1459d12b376f..487f6edd3c95 100644 --- a/Lib/token.py +++ b/Lib/token.py @@ -67,10 +67,10 @@ FSTRING_START = 61 FSTRING_MIDDLE = 62 FSTRING_END = 63 +COMMENT = 64 +NL = 65 # These aren't used by the C tokenizer but are needed for tokenize.py -ERRORTOKEN = 64 -COMMENT = 65 -NL = 66 +ERRORTOKEN = 66 ENCODING = 67 N_TOKENS = 68 # Special definitions for cooperation with parser diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 46d2224f5cc0..bfe40c627fde 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -56,112 +56,11 @@ def exact_type(self): else: return self.type -def group(*choices): return '(' + '|'.join(choices) + ')' -def any(*choices): return group(*choices) + '*' -def maybe(*choices): return group(*choices) + '?' - -# Note: we use unicode matching for names ("\w") but ascii matching for -# number literals. -Whitespace = r'[ \f\t]*' -Comment = r'#[^\r\n]*' -Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) -Name = r'\w+' - -Hexnumber = r'0[xX](?:_?[0-9a-fA-F])+' -Binnumber = r'0[bB](?:_?[01])+' -Octnumber = r'0[oO](?:_?[0-7])+' -Decnumber = r'(?:0(?:_?0)*|[1-9](?:_?[0-9])*)' -Intnumber = group(Hexnumber, Binnumber, Octnumber, Decnumber) -Exponent = r'[eE][-+]?[0-9](?:_?[0-9])*' -Pointfloat = group(r'[0-9](?:_?[0-9])*\.(?:[0-9](?:_?[0-9])*)?', - r'\.[0-9](?:_?[0-9])*') + maybe(Exponent) -Expfloat = r'[0-9](?:_?[0-9])*' + Exponent -Floatnumber = group(Pointfloat, Expfloat) -Imagnumber = group(r'[0-9](?:_?[0-9])*[jJ]', Floatnumber + r'[jJ]') -Number = group(Imagnumber, Floatnumber, Intnumber) - -# Return the empty string, plus all of the valid string prefixes. -def _all_string_prefixes(): - # The valid string prefixes. Only contain the lower case versions, - # and don't contain any permutations (include 'fr', but not - # 'rf'). The various permutations will be generated. - _valid_string_prefixes = ['b', 'r', 'u', 'f', 'br', 'fr'] - # if we add binary f-strings, add: ['fb', 'fbr'] - result = {''} - for prefix in _valid_string_prefixes: - for t in _itertools.permutations(prefix): - # create a list with upper and lower versions of each - # character - for u in _itertools.product(*[(c, c.upper()) for c in t]): - result.add(''.join(u)) - return result - - at functools.lru_cache -def _compile(expr): - return re.compile(expr, re.UNICODE) - -# Note that since _all_string_prefixes includes the empty string, -# StringPrefix can be the empty string (making it optional). -StringPrefix = group(*_all_string_prefixes()) - -# Tail end of ' string. -Single = r"[^'\\]*(?:\\.[^'\\]*)*'" -# Tail end of " string. -Double = r'[^"\\]*(?:\\.[^"\\]*)*"' -# Tail end of ''' string. -Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" -# Tail end of """ string. -Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' -Triple = group(StringPrefix + "'''", StringPrefix + '"""') -# Single-line ' or " string. -String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", - StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') - -# Sorting in reverse order puts the long operators before their prefixes. -# Otherwise if = came before ==, == would get recognized as two instances -# of =. -Special = group(*map(re.escape, sorted(EXACT_TOKEN_TYPES, reverse=True))) -Funny = group(r'\r?\n', Special) - -PlainToken = group(Number, Funny, String, Name) -Token = Ignore + PlainToken - -# First (or only) line of ' or " string. -ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + - group("'", r'\\\r?\n'), - StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + - group('"', r'\\\r?\n')) -PseudoExtras = group(r'\\\r?\n|\Z', Comment, Triple) -PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) - -# For a given string prefix plus quotes, endpats maps it to a regex -# to match the remainder of that string. _prefix can be empty, for -# a normal single or triple quoted string (with no prefix). -endpats = {} -for _prefix in _all_string_prefixes(): - endpats[_prefix + "'"] = Single - endpats[_prefix + '"'] = Double - endpats[_prefix + "'''"] = Single3 - endpats[_prefix + '"""'] = Double3 -del _prefix - -# A set of all of the single and triple quoted string prefixes, -# including the opening quotes. -single_quoted = set() -triple_quoted = set() -for t in _all_string_prefixes(): - for u in (t + '"', t + "'"): - single_quoted.add(u) - for u in (t + '"""', t + "'''"): - triple_quoted.add(u) -del t, u - -tabsize = 8 class TokenError(Exception): pass -class StopTokenizing(Exception): pass +class StopTokenizing(Exception): pass class Untokenizer: @@ -213,6 +112,14 @@ def untokenize(self, iterable): self.tokens.append(indent) self.prev_col = len(indent) startline = False + elif tok_type == FSTRING_MIDDLE: + if '{' in token or '}' in token: + end_line, end_col = end + end = (end_line, end_col + token.count('{') + token.count('}')) + token = re.sub('{', '{{', token) + token = re.sub('}', '}}', token) + + self.add_whitespace(start) self.tokens.append(token) self.prev_row, self.prev_col = end @@ -255,6 +162,11 @@ def compat(self, token, iterable): elif startline and indents: toks_append(indents[-1]) startline = False + elif toknum == FSTRING_MIDDLE: + if '{' in tokval or '}' in tokval: + tokval = re.sub('{', '{{', tokval) + tokval = re.sub('}', '}}', tokval) + toks_append(tokval) @@ -404,7 +316,6 @@ def open(filename): buffer.close() raise - def tokenize(readline): """ The tokenize() generator requires one argument, readline, which @@ -425,192 +336,32 @@ def tokenize(readline): which tells you which encoding was used to decode the bytes stream. """ encoding, consumed = detect_encoding(readline) - empty = _itertools.repeat(b"") - rl_gen = _itertools.chain(consumed, iter(readline, b""), empty) - return _tokenize(rl_gen.__next__, encoding) - - -def _tokenize(readline, encoding): - lnum = parenlev = continued = 0 - numchars = '0123456789' - contstr, needcont = '', 0 - contline = None - indents = [0] - + rl_gen = _itertools.chain(consumed, iter(readline, b"")) if encoding is not None: if encoding == "utf-8-sig": # BOM will already have been stripped. encoding = "utf-8" yield TokenInfo(ENCODING, encoding, (0, 0), (0, 0), '') - last_line = b'' - line = b'' - while True: # loop over lines in stream - try: - # We capture the value of the line variable here because - # readline uses the empty string '' to signal end of input, - # hence `line` itself will always be overwritten at the end - # of this loop. - last_line = line - line = readline() - except StopIteration: - line = b'' - - if encoding is not None: - line = line.decode(encoding) - lnum += 1 - pos, max = 0, len(line) - - if contstr: # continued string - if not line: - raise TokenError("EOF in multi-line string", strstart) - endmatch = endprog.match(line) - if endmatch: - pos = end = endmatch.end(0) - yield TokenInfo(STRING, contstr + line[:end], - strstart, (lnum, end), contline + line) - contstr, needcont = '', 0 - contline = None - elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': - yield TokenInfo(ERRORTOKEN, contstr + line, - strstart, (lnum, len(line)), contline) - contstr = '' - contline = None - continue - else: - contstr = contstr + line - contline = contline + line - continue - - elif parenlev == 0 and not continued: # new statement - if not line: break - column = 0 - while pos < max: # measure leading whitespace - if line[pos] == ' ': - column += 1 - elif line[pos] == '\t': - column = (column//tabsize + 1)*tabsize - elif line[pos] == '\f': - column = 0 - else: - break - pos += 1 - if pos == max: - break - - if line[pos] in '#\r\n': # skip comments or blank lines - if line[pos] == '#': - comment_token = line[pos:].rstrip('\r\n') - yield TokenInfo(COMMENT, comment_token, - (lnum, pos), (lnum, pos + len(comment_token)), line) - pos += len(comment_token) - - yield TokenInfo(NL, line[pos:], - (lnum, pos), (lnum, len(line)), line) - continue - - if column > indents[-1]: # count indents or dedents - indents.append(column) - yield TokenInfo(INDENT, line[:pos], (lnum, 0), (lnum, pos), line) - while column < indents[-1]: - if column not in indents: - raise IndentationError( - "unindent does not match any outer indentation level", - ("<tokenize>", lnum, pos, line)) - indents = indents[:-1] - - yield TokenInfo(DEDENT, '', (lnum, pos), (lnum, pos), line) - - else: # continued statement - if not line: - raise TokenError("EOF in multi-line statement", (lnum, 0)) - continued = 0 - - while pos < max: - pseudomatch = _compile(PseudoToken).match(line, pos) - if pseudomatch: # scan for tokens - start, end = pseudomatch.span(1) - spos, epos, pos = (lnum, start), (lnum, end), end - if start == end: - continue - token, initial = line[start:end], line[start] - - if (initial in numchars or # ordinary number - (initial == '.' and token != '.' and token != '...')): - yield TokenInfo(NUMBER, token, spos, epos, line) - elif initial in '\r\n': - if parenlev > 0: - yield TokenInfo(NL, token, spos, epos, line) - else: - yield TokenInfo(NEWLINE, token, spos, epos, line) - - elif initial == '#': - assert not token.endswith("\n") - yield TokenInfo(COMMENT, token, spos, epos, line) - - elif token in triple_quoted: - endprog = _compile(endpats[token]) - endmatch = endprog.match(line, pos) - if endmatch: # all on one line - pos = endmatch.end(0) - token = line[start:pos] - yield TokenInfo(STRING, token, spos, (lnum, pos), line) - else: - strstart = (lnum, start) # multiple lines - contstr = line[start:] - contline = line - break - - # Check up to the first 3 chars of the token to see if - # they're in the single_quoted set. If so, they start - # a string. - # We're using the first 3, because we're looking for - # "rb'" (for example) at the start of the token. If - # we switch to longer prefixes, this needs to be - # adjusted. - # Note that initial == token[:1]. - # Also note that single quote checking must come after - # triple quote checking (above). - elif (initial in single_quoted or - token[:2] in single_quoted or - token[:3] in single_quoted): - if token[-1] == '\n': # continued string - strstart = (lnum, start) - # Again, using the first 3 chars of the - # token. This is looking for the matching end - # regex for the correct type of quote - # character. So it's really looking for - # endpats["'"] or endpats['"'], by trying to - # skip string prefix characters, if any. - endprog = _compile(endpats.get(initial) or - endpats.get(token[1]) or - endpats.get(token[2])) - contstr, needcont = line[start:], 1 - contline = line - break - else: # ordinary string - yield TokenInfo(STRING, token, spos, epos, line) - - elif initial.isidentifier(): # ordinary name - yield TokenInfo(NAME, token, spos, epos, line) - elif initial == '\\': # continued stmt - continued = 1 - else: - if initial in '([{': - parenlev += 1 - elif initial in ')]}': - parenlev -= 1 - yield TokenInfo(OP, token, spos, epos, line) - else: - yield TokenInfo(ERRORTOKEN, line[pos], - (lnum, pos), (lnum, pos+1), line) - pos += 1 - - # Add an implicit NEWLINE if the input doesn't end in one - if last_line and last_line[-1] not in '\r\n' and not last_line.strip().startswith("#"): - yield TokenInfo(NEWLINE, '', (lnum - 1, len(last_line)), (lnum - 1, len(last_line) + 1), '') - for indent in indents[1:]: # pop remaining indent levels - yield TokenInfo(DEDENT, '', (lnum, 0), (lnum, 0), '') - yield TokenInfo(ENDMARKER, '', (lnum, 0), (lnum, 0), '') + yield from _tokenize(rl_gen, encoding) + +def _tokenize(rl_gen, encoding): + source = b"".join(rl_gen).decode(encoding) + token = None + for token in _generate_tokens_from_c_tokenizer(source, extra_tokens=True): + # TODO: Marta -> limpiar esto + if 6 < token.type <= 54: + token = token._replace(type=OP) + if token.type in {ASYNC, AWAIT}: + token = token._replace(type=NAME) + if token.type == NEWLINE: + l_start, c_start = token.start + l_end, c_end = token.end + token = token._replace(string='\n', start=(l_start, c_start), end=(l_end, c_end+1)) + + yield token + if token is not None: + last_line, _ = token.start + yield TokenInfo(ENDMARKER, '', (last_line + 1, 0), (last_line + 1, 0), '') def generate_tokens(readline): @@ -619,7 +370,16 @@ def generate_tokens(readline): This has the same API as tokenize(), except that it expects the *readline* callable to return str objects instead of bytes. """ - return _tokenize(readline, None) + def _gen(): + while True: + try: + line = readline() + except StopIteration: + return + if not line: + return + yield line.encode() + return _tokenize(_gen(), 'utf-8') def main(): import argparse @@ -656,7 +416,10 @@ def error(message, filename=None, location=None): tokens = list(tokenize(f.readline)) else: filename = "<stdin>" - tokens = _tokenize(sys.stdin.readline, None) + tokens = _tokenize( + (x.encode('utf-8') for x in iter(sys.stdin.readline, "") + ), "utf-8") + # Output the tokenization for token in tokens: @@ -682,10 +445,10 @@ def error(message, filename=None, location=None): perror("unexpected error: %s" % err) raise -def _generate_tokens_from_c_tokenizer(source): +def _generate_tokens_from_c_tokenizer(source, extra_tokens=False): """Tokenize a source reading Python code as unicode strings using the internal C tokenizer""" import _tokenize as c_tokenizer - for info in c_tokenizer.TokenizerIter(source): + for info in c_tokenizer.TokenizerIter(source, extra_tokens=extra_tokens): tok, type, lineno, end_lineno, col_off, end_col_off, line = info yield TokenInfo(type, tok, (lineno, col_off), (end_lineno, end_col_off), line) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst new file mode 100644 index 000000000000..ff831c9f935d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst @@ -0,0 +1 @@ +Implement PEP 701 changes in the :mod:`tokenize` module. Patch by Marta G?mez Mac?as and Pablo Galindo Salgado diff --git a/Parser/pegen.c b/Parser/pegen.c index da410ea84ecb..b031a6f5d440 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -208,7 +208,7 @@ int _PyPegen_fill_token(Parser *p) { struct token new_token; - new_token.metadata = NULL; + _PyToken_Init(&new_token); int type = _PyTokenizer_Get(p->tok, &new_token); // Record and skip '# type: ignore' comments @@ -251,7 +251,7 @@ _PyPegen_fill_token(Parser *p) Token *t = p->tokens[p->fill]; return initialize_token(p, t, &new_token, type); error: - Py_XDECREF(new_token.metadata); + _PyToken_Free(&new_token); return -1; } diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index 1f227da0194e..af529057f50e 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -165,7 +165,7 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) { int ret = 0; struct token new_token; - new_token.metadata = NULL; + _PyToken_Init(&new_token); for (;;) { switch (_PyTokenizer_Get(p->tok, &new_token)) { @@ -193,7 +193,7 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) { exit: - Py_XDECREF(new_token.metadata); + _PyToken_Free(&new_token); // 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. diff --git a/Parser/token.c b/Parser/token.c index 82267fbfcd0c..2bc963a91c77 100644 --- a/Parser/token.c +++ b/Parser/token.c @@ -70,9 +70,9 @@ const char * const _PyParser_TokenNames[] = { "FSTRING_START", "FSTRING_MIDDLE", "FSTRING_END", + "COMMENT", + "NL", "<ERRORTOKEN>", - "<COMMENT>", - "<NL>", "<ENCODING>", "<N_TOKENS>", }; diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index c5dc9e706fe4..fb94fbeac42b 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -111,6 +111,8 @@ tok_new(void) tok->interactive_underflow = IUNDERFLOW_NORMAL; tok->str = NULL; tok->report_warnings = 1; + tok->tok_extra_tokens = 0; + tok->comment_newline = 0; tok->tok_mode_stack[0] = (tokenizer_mode){.kind =TOK_REGULAR_MODE, .f_string_quote='\0', .f_string_quote_size = 0, .f_string_debug=0}; tok->tok_mode_stack_index = 0; tok->tok_report_warnings = 1; @@ -980,6 +982,16 @@ _PyTokenizer_Free(struct tok_state *tok) PyMem_Free(tok); } +void +_PyToken_Free(struct token *token) { + Py_XDECREF(token->metadata); +} + +void +_PyToken_Init(struct token *token) { + token->metadata = NULL; +} + static int tok_readline_raw(struct tok_state *tok) { @@ -1636,6 +1648,7 @@ token_setup(struct tok_state *tok, struct token *token, int type, const char *st return type; } + static int tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token) { @@ -1649,6 +1662,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t tok->starting_col_offset = -1; blankline = 0; + /* Get indentation level */ if (tok->atbol) { int col = 0; @@ -1749,12 +1763,20 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t tok->starting_col_offset = tok->col_offset; /* Return pending indents/dedents */ - if (tok->pendin != 0) { + if (tok->pendin != 0) { if (tok->pendin < 0) { + if (tok->tok_extra_tokens) { + p_start = tok->cur; + p_end = tok->cur; + } tok->pendin++; return MAKE_TOKEN(DEDENT); } else { + if (tok->tok_extra_tokens) { + p_start = tok->buf; + p_end = tok->cur; + } tok->pendin--; return MAKE_TOKEN(INDENT); } @@ -1803,13 +1825,18 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t return MAKE_TOKEN(syntaxerror(tok, "f-string expression part cannot include '#'")); } - const char *prefix, *p, *type_start; + const char* p = NULL; + const char *prefix, *type_start; int current_starting_col_offset; while (c != EOF && c != '\n') { c = tok_nextc(tok); } + if (tok->tok_extra_tokens) { + p = tok->start; + } + if (tok->type_comments) { p = tok->start; current_starting_col_offset = tok->starting_col_offset; @@ -1864,6 +1891,13 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t } } } + if (tok->tok_extra_tokens) { + tok_backup(tok, c); /* don't eat the newline or EOF */ + p_start = p; + p_end = tok->cur; + tok->comment_newline = blankline; + return MAKE_TOKEN(COMMENT); + } } if (tok->done == E_INTERACT_STOP) { @@ -1949,6 +1983,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t struct tok_state ahead_tok; struct token ahead_token; + _PyToken_Init(&ahead_token); int ahead_tok_kind; memcpy(&ahead_tok, tok, sizeof(ahead_tok)); @@ -1964,8 +1999,10 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t returning a plain NAME token, return ASYNC. */ tok->async_def_indent = tok->indent; tok->async_def = 1; + _PyToken_Free(&ahead_token); return MAKE_TOKEN(ASYNC); } + _PyToken_Free(&ahead_token); } } @@ -1976,8 +2013,19 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t if (c == '\n') { tok->atbol = 1; if (blankline || tok->level > 0) { + if (tok->tok_extra_tokens) { + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NL); + } goto nextline; } + if (tok->comment_newline && tok->tok_extra_tokens) { + tok->comment_newline = 0; + p_start = tok->start; + p_end = tok->cur; + return MAKE_TOKEN(NL); + } p_start = tok->start; p_end = tok->cur - 1; /* Leave '\n' out of the string */ tok->cont_line = 0; @@ -2563,6 +2611,9 @@ tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct f_string_middle: + // TODO: This is a bit of a hack, but it works for now. We need to find a better way to handle + // this. + tok->multi_line_start = tok->line_start; while (end_quote_size != current_tok->f_string_quote_size) { int c = tok_nextc(tok); if (tok->done == E_ERROR) { @@ -2788,7 +2839,9 @@ _PyTokenizer_FindEncodingFilename(int fd, PyObject *filename) // if fetching the encoding shows a warning. tok->report_warnings = 0; while (tok->lineno < 2 && tok->done == E_OK) { + _PyToken_Init(&token); _PyTokenizer_Get(tok, &token); + _PyToken_Free(&token); } fclose(fp); if (tok->encoding) { diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index fd169cf3d1ba..3f34763239ac 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -128,6 +128,8 @@ struct tok_state { tokenizer_mode tok_mode_stack[MAXFSTRINGLEVEL]; int tok_mode_stack_index; int tok_report_warnings; + int tok_extra_tokens; + int comment_newline; #ifdef Py_DEBUG int debug; #endif @@ -138,6 +140,8 @@ extern struct tok_state *_PyTokenizer_FromUTF8(const char *, int); extern struct tok_state *_PyTokenizer_FromFile(FILE *, const char*, const char *, const char *); extern void _PyTokenizer_Free(struct tok_state *); +extern void _PyToken_Free(struct token *); +extern void _PyToken_Init(struct token *); extern int _PyTokenizer_Get(struct tok_state *, struct token *); #define tok_dump _Py_tok_dump diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 3394a5108cb5..ece238672e34 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -1,5 +1,8 @@ #include "Python.h" +#include "errcode.h" #include "../Parser/tokenizer.h" +#include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset() +#include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset() static struct PyModuleDef _tokenizemodule; @@ -34,11 +37,14 @@ typedef struct _tokenizer.tokenizeriter.__new__ as tokenizeriter_new source: str + * + extra_tokens: bool [clinic start generated code]*/ static PyObject * -tokenizeriter_new_impl(PyTypeObject *type, const char *source) -/*[clinic end generated code: output=7fd9f46cf9263cbb input=4384b368407375c6]*/ +tokenizeriter_new_impl(PyTypeObject *type, const char *source, + int extra_tokens) +/*[clinic end generated code: output=f6f9d8b4beec8106 input=90dc5b6a5df180c2]*/ { tokenizeriterobject *self = (tokenizeriterobject *)type->tp_alloc(type, 0); if (self == NULL) { @@ -54,20 +60,123 @@ tokenizeriter_new_impl(PyTypeObject *type, const char *source) return NULL; } self->tok->filename = filename; + if (extra_tokens) { + self->tok->tok_extra_tokens = 1; + } return (PyObject *)self; } +static int +_tokenizer_error(struct tok_state *tok) +{ + if (PyErr_Occurred()) { + return -1; + } + + const char *msg = NULL; + PyObject* errtype = PyExc_SyntaxError; + switch (tok->done) { + case E_TOKEN: + msg = "invalid token"; + break; + case E_EOF: + if (tok->level) { + PyErr_Format(PyExc_SyntaxError, + "parenthesis '%c' was never closed", + tok->parenstack[tok->level-1]); + } else { + PyErr_SetString(PyExc_SyntaxError, "unexpected EOF while parsing"); + } + return -1; + case E_DEDENT: + PyErr_Format(PyExc_IndentationError, + "unindent does not match any outer indentation level " + "(<tokenize>, line %d)", + tok->lineno); + return -1; + case E_INTR: + if (!PyErr_Occurred()) { + PyErr_SetNone(PyExc_KeyboardInterrupt); + } + return -1; + case E_NOMEM: + PyErr_NoMemory(); + return -1; + case E_TABSPACE: + errtype = PyExc_TabError; + msg = "inconsistent use of tabs and spaces in indentation"; + break; + case E_TOODEEP: + errtype = PyExc_IndentationError; + msg = "too many levels of indentation"; + break; + case E_LINECONT: { + msg = "unexpected character after line continuation character"; + break; + } + default: + msg = "unknown tokenization error"; + } + + PyObject* errstr = NULL; + PyObject* error_line = NULL; + PyObject* tmp = NULL; + PyObject* value = NULL; + int result = 0; + + Py_ssize_t size = tok->inp - tok->buf; + error_line = PyUnicode_DecodeUTF8(tok->buf, size, "replace"); + if (!error_line) { + result = -1; + goto exit; + } + + tmp = Py_BuildValue("(OnnOii)", tok->filename, tok->lineno, 0, error_line, 0, 0); + if (!tmp) { + result = -1; + goto exit; + } + + errstr = PyUnicode_FromString(msg); + if (!errstr) { + result = -1; + goto exit; + } + + value = PyTuple_Pack(2, errstr, tmp); + if (!value) { + result = -1; + goto exit; + } + + PyErr_SetObject(errtype, value); + +exit: + Py_XDECREF(errstr); + Py_XDECREF(error_line); + Py_XDECREF(tmp); + Py_XDECREF(value); + return result; +} + static PyObject * tokenizeriter_next(tokenizeriterobject *it) { + PyObject* result = NULL; struct token token; + _PyToken_Init(&token); + int type = _PyTokenizer_Get(it->tok, &token); - if (type == ERRORTOKEN && PyErr_Occurred()) { - return NULL; + if (type == ERRORTOKEN) { + if(!PyErr_Occurred()) { + _tokenizer_error(it->tok); + assert(PyErr_Occurred()); + } + goto exit; } if (type == ERRORTOKEN || type == ENDMARKER) { PyErr_SetString(PyExc_StopIteration, "EOF"); - return NULL; + goto exit; } PyObject *str = NULL; if (token.start == NULL || token.end == NULL) { @@ -77,28 +186,31 @@ tokenizeriter_next(tokenizeriterobject *it) str = PyUnicode_FromStringAndSize(token.start, token.end - token.start); } if (str == NULL) { - return NULL; + goto exit; } Py_ssize_t size = it->tok->inp - it->tok->buf; PyObject *line = PyUnicode_DecodeUTF8(it->tok->buf, size, "replace"); if (line == NULL) { Py_DECREF(str); - return NULL; + goto exit; } 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; + Py_ssize_t lineno = ISSTRINGLIT(type) ? it->tok->first_lineno : it->tok->lineno; + Py_ssize_t end_lineno = it->tok->lineno; + Py_ssize_t col_offset = -1; + Py_ssize_t end_col_offset = -1; if (token.start != NULL && token.start >= line_start) { - col_offset = (int)(token.start - line_start); + col_offset = _PyPegen_byte_offset_to_character_offset(line, token.start - line_start); } if (token.end != NULL && token.end >= it->tok->line_start) { - end_col_offset = (int)(token.end - it->tok->line_start); + end_col_offset = _PyPegen_byte_offset_to_character_offset(line, token.end - it->tok->line_start); } - return Py_BuildValue("(NiiiiiN)", str, type, lineno, end_lineno, col_offset, end_col_offset, line); + result = Py_BuildValue("(NinnnnN)", str, type, lineno, end_lineno, col_offset, end_col_offset, line); +exit: + _PyToken_Free(&token); + return result; } static void diff --git a/Python/clinic/Python-tokenize.c.h b/Python/clinic/Python-tokenize.c.h index 6af93743f40d..7e779388a92d 100644 --- a/Python/clinic/Python-tokenize.c.h +++ b/Python/clinic/Python-tokenize.c.h @@ -9,7 +9,8 @@ preserve static PyObject * -tokenizeriter_new_impl(PyTypeObject *type, const char *source); +tokenizeriter_new_impl(PyTypeObject *type, const char *source, + int extra_tokens); static PyObject * tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) @@ -17,14 +18,14 @@ tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 1 + #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(source), }, + .ob_item = { &_Py_ID(source), &_Py_ID(extra_tokens), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -33,19 +34,20 @@ tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"source", NULL}; + static const char * const _keywords[] = {"source", "extra_tokens", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "tokenizeriter", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[1]; + PyObject *argsbuf[2]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); const char *source; + int extra_tokens; - fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 1, argsbuf); if (!fastargs) { goto exit; } @@ -62,9 +64,13 @@ tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - return_value = tokenizeriter_new_impl(type, source); + extra_tokens = PyObject_IsTrue(fastargs[1]); + if (extra_tokens < 0) { + goto exit; + } + return_value = tokenizeriter_new_impl(type, source, extra_tokens); exit: return return_value; } -/*[clinic end generated code: output=8c2c09f651961986 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=940b564c67f6e0e2 input=a9049054013a1b77]*/ From webhook-mailer at python.org Sat May 20 20:13:44 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 21 May 2023 00:13:44 -0000 Subject: [Python-checkins] gh-74690: Make a typing test more resilient (#104691) Message-ID: <mailman.489.1684628025.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b870b1fa755808977578e99bd42859c519e00bb7 commit: b870b1fa755808977578e99bd42859c519e00bb7 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-20T17:13:37-07:00 summary: gh-74690: Make a typing test more resilient (#104691) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 6459fa3eb96a..9a3e64289ee8 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3154,10 +3154,10 @@ class NonP(P): class NonPR(PR): pass - class C: + class C(metaclass=abc.ABCMeta): x = 1 - class D: + class D(metaclass=abc.ABCMeta): def meth(self): pass self.assertNotIsInstance(C(), NonP) @@ -3174,8 +3174,7 @@ def meth(self): pass acceptable_extra_attrs = { '_is_protocol', '_is_runtime_protocol', '__parameters__', - '__subclasshook__', '__abstractmethods__', '_abc_impl', - '__init__', '__annotations__', + '__init__', '__annotations__', '__subclasshook__', } self.assertLessEqual(vars(NonP).keys(), vars(C).keys() | acceptable_extra_attrs) self.assertLessEqual( From webhook-mailer at python.org Sat May 20 20:17:34 2023 From: webhook-mailer at python.org (gpshead) Date: Sun, 21 May 2023 00:17:34 -0000 Subject: [Python-checkins] [3.11] gh-101857: Allow xattr detection on musl libc (GH-101858) (#101894) Message-ID: <mailman.490.1684628255.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2e457bc202179445cbf7b3a2a96c8450f1cda72f commit: 2e457bc202179445cbf7b3a2a96c8450f1cda72f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-21T00:17:27Z summary: [3.11] gh-101857: Allow xattr detection on musl libc (GH-101858) (#101894) gh-101857: Allow xattr detection on musl libc (GH-101858) Previously, we checked exclusively for `__GLIBC__` (AND'd with some other conditions). Checking for `__linux__` instead should be fine. This fixes using e.g. `os.listxattr()` on systems using musl libc. Bug: https://bugs.gentoo.org/894130 (cherry picked from commit 8be8101bca34b60481ec3d7ecaea4a3379fb7dbb) Co-authored-by: Sam James <sam at gentoo.org> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst M Modules/posixmodule.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst new file mode 100644 index 000000000000..832cc300fa94 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst @@ -0,0 +1 @@ +Fix xattr support detection on Linux systems by widening the check to linux, not just glibc. This fixes support for musl. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index c825aeedcf08..a01662d868e5 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -280,8 +280,9 @@ corresponding Unix manual entries for more information on calls."); # undef HAVE_SCHED_SETAFFINITY #endif -#if defined(HAVE_SYS_XATTR_H) && defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) +#if defined(HAVE_SYS_XATTR_H) && defined(__linux__) && !defined(__FreeBSD_kernel__) && !defined(__GNU__) # define USE_XATTRS +# include <linux/limits.h> // Needed for XATTR_SIZE_MAX on musl libc. #endif #ifdef USE_XATTRS From webhook-mailer at python.org Sat May 20 20:20:03 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 21 May 2023 00:20:03 -0000 Subject: [Python-checkins] gh-104698: Fix reference leak in mmapmodule.c (#104700) Message-ID: <mailman.491.1684628404.13550.python-checkins@python.org> https://github.com/python/cpython/commit/99b641886a09252bbcf99a1d322fa8734f1ca30d commit: 99b641886a09252bbcf99a1d322fa8734f1ca30d branch: main author: Kirill Podoprigora <kirill.bast9 at mail.ru> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-21T01:19:56+01:00 summary: gh-104698: Fix reference leak in mmapmodule.c (#104700) Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Modules/mmapmodule.c diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 8e5a0bde8899..6bde9939eaa2 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -227,6 +227,14 @@ do { \ return err; \ } \ } while (0) +#define CHECK_VALID_OR_RELEASE(err, buffer) \ +do { \ + if (self->map_handle == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + PyBuffer_Release(&(buffer)); \ + return (err); \ + } \ +} while (0) #endif /* MS_WINDOWS */ #ifdef UNIX @@ -237,6 +245,14 @@ do { \ return err; \ } \ } while (0) +#define CHECK_VALID_OR_RELEASE(err, buffer) \ +do { \ + if (self->data == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + PyBuffer_Release(&(buffer)); \ + return (err); \ + } \ +} while (0) #endif /* UNIX */ static PyObject * @@ -326,7 +342,7 @@ mmap_gfind(mmap_object *self, end = self->size; Py_ssize_t res; - CHECK_VALID(NULL); + CHECK_VALID_OR_RELEASE(NULL, view); if (reverse) { res = _PyBytes_ReverseFind( self->data + start, end - start, @@ -403,7 +419,7 @@ mmap_write_method(mmap_object *self, return NULL; } - CHECK_VALID(NULL); + CHECK_VALID_OR_RELEASE(NULL, data); memcpy(&self->data[self->pos], data.buf, data.len); self->pos += data.len; PyBuffer_Release(&data); @@ -1087,7 +1103,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) return -1; } - CHECK_VALID(-1); + CHECK_VALID_OR_RELEASE(-1, vbuf); if (slicelen == 0) { } else if (step == 1) { From webhook-mailer at python.org Sat May 20 21:44:00 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 21 May 2023 01:44:00 -0000 Subject: [Python-checkins] [3.11] gh-104698: Fix reference leak in mmapmodule.c (GH-104700) (#104710) Message-ID: <mailman.492.1684633441.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b2e0201222dc993ce1813b2a92bda43b74f4262f commit: b2e0201222dc993ce1813b2a92bda43b74f4262f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-20T18:43:18-07:00 summary: [3.11] gh-104698: Fix reference leak in mmapmodule.c (GH-104700) (#104710) (cherry picked from commit 99b641886a09252bbcf99a1d322fa8734f1ca30d) Co-authored-by: Kirill Podoprigora <kirill.bast9 at mail.ru> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: M Modules/mmapmodule.c diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 39e56f290383..4b0c1e27e0c5 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -235,6 +235,14 @@ do { \ return err; \ } \ } while (0) +#define CHECK_VALID_OR_RELEASE(err, buffer) \ +do { \ + if (self->map_handle == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + PyBuffer_Release(&(buffer)); \ + return (err); \ + } \ +} while (0) #endif /* MS_WINDOWS */ #ifdef UNIX @@ -245,6 +253,14 @@ do { \ return err; \ } \ } while (0) +#define CHECK_VALID_OR_RELEASE(err, buffer) \ +do { \ + if (self->data == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + PyBuffer_Release(&(buffer)); \ + return (err); \ + } \ +} while (0) #endif /* UNIX */ static PyObject * @@ -334,7 +350,7 @@ mmap_gfind(mmap_object *self, end = self->size; Py_ssize_t res; - CHECK_VALID(NULL); + CHECK_VALID_OR_RELEASE(NULL, view); if (reverse) { res = _PyBytes_ReverseFind( self->data + start, end - start, @@ -411,7 +427,7 @@ mmap_write_method(mmap_object *self, return NULL; } - CHECK_VALID(NULL); + CHECK_VALID_OR_RELEASE(NULL, data); memcpy(&self->data[self->pos], data.buf, data.len); self->pos += data.len; PyBuffer_Release(&data); @@ -1097,7 +1113,7 @@ mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value) return -1; } - CHECK_VALID(-1); + CHECK_VALID_OR_RELEASE(-1, vbuf); if (slicelen == 0) { } else if (step == 1) { From webhook-mailer at python.org Sun May 21 01:57:57 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 21 May 2023 05:57:57 -0000 Subject: [Python-checkins] Corrected identifier (#104713) Message-ID: <mailman.493.1684648678.13550.python-checkins@python.org> https://github.com/python/cpython/commit/60993ba8b4a04dfcf2d3067d919bcce160f01bd5 commit: 60993ba8b4a04dfcf2d3067d919bcce160f01bd5 branch: main author: William Sawyer <wmsawyer2609 at gmail.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-21T01:57:50-04:00 summary: Corrected identifier (#104713) files: M Doc/library/operator.rst diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index 6d90473f2367..dab4de9eb6ab 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -244,7 +244,7 @@ Operations which work with sequences (some of them with mappings too) include: .. function:: length_hint(obj, default=0) - Return an estimated length for the object *o*. First try to return its + Return an estimated length for the object *obj*. First try to return its actual length, then an estimate using :meth:`object.__length_hint__`, and finally return the default value. From webhook-mailer at python.org Sun May 21 02:06:24 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 21 May 2023 06:06:24 -0000 Subject: [Python-checkins] [3.11] Corrected identifier (GH-104713) (#104714) Message-ID: <mailman.494.1684649185.13550.python-checkins@python.org> https://github.com/python/cpython/commit/dc0c41b2e5ec64854caa9055f2c7388e22fa4bf8 commit: dc0c41b2e5ec64854caa9055f2c7388e22fa4bf8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-21T02:06:17-04:00 summary: [3.11] Corrected identifier (GH-104713) (#104714) Corrected identifier (GH-104713) (cherry picked from commit 60993ba8b4a04dfcf2d3067d919bcce160f01bd5) Co-authored-by: William Sawyer <wmsawyer2609 at gmail.com> files: M Doc/library/operator.rst diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst index 6d90473f2367..dab4de9eb6ab 100644 --- a/Doc/library/operator.rst +++ b/Doc/library/operator.rst @@ -244,7 +244,7 @@ Operations which work with sequences (some of them with mappings too) include: .. function:: length_hint(obj, default=0) - Return an estimated length for the object *o*. First try to return its + Return an estimated length for the object *obj*. First try to return its actual length, then an estimate using :meth:`object.__length_hint__`, and finally return the default value. From webhook-mailer at python.org Sun May 21 05:40:02 2023 From: webhook-mailer at python.org (corona10) Date: Sun, 21 May 2023 09:40:02 -0000 Subject: [Python-checkins] gh-104469: Convert _testcapi/exceptions to use AC (gh-104502) Message-ID: <mailman.495.1684662003.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2e91c7e62609ef405901dd5c4cb9d5aa794591ab commit: 2e91c7e62609ef405901dd5c4cb9d5aa794591ab branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-21T18:39:45+09:00 summary: gh-104469: Convert _testcapi/exceptions to use AC (gh-104502) files: A Modules/_testcapi/clinic/exceptions.c.h M Lib/test/test_capi/test_exceptions.py M Lib/test/test_faulthandler.py M Modules/_testcapi/exceptions.c diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index b1c1a61e2068..1081f40b6981 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -66,7 +66,7 @@ def check_fatal_error(self, code, expected, not_expected=()): rc, out, err = assert_python_failure('-sSI', '-c', code) err = decode_stderr(err) - self.assertIn('Fatal Python error: test_fatal_error: MESSAGE\n', + self.assertIn('Fatal Python error: _testcapi_fatal_error_impl: MESSAGE\n', err) match = re.search(r'^Extension modules:(.*) \(total: ([0-9]+)\)$', diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 8d106daaf652..2e97de592712 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -270,7 +270,7 @@ def check_fatal_error_func(self, release_gil): """, 2, 'xyz', - func='test_fatal_error', + func='_testcapi_fatal_error_impl', py_fatal_error=True) def test_fatal_error(self): diff --git a/Modules/_testcapi/clinic/exceptions.c.h b/Modules/_testcapi/clinic/exceptions.c.h new file mode 100644 index 000000000000..2cc4ef3dc0d4 --- /dev/null +++ b/Modules/_testcapi/clinic/exceptions.c.h @@ -0,0 +1,398 @@ +/*[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(_testcapi_err_set_raised__doc__, +"err_set_raised($module, exception, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_ERR_SET_RAISED_METHODDEF \ + {"err_set_raised", (PyCFunction)_testcapi_err_set_raised, METH_O, _testcapi_err_set_raised__doc__}, + +PyDoc_STRVAR(_testcapi_exception_print__doc__, +"exception_print($module, exception, legacy=False, /)\n" +"--\n" +"\n" +"To test the format of exceptions as printed out."); + +#define _TESTCAPI_EXCEPTION_PRINT_METHODDEF \ + {"exception_print", _PyCFunction_CAST(_testcapi_exception_print), METH_FASTCALL, _testcapi_exception_print__doc__}, + +static PyObject * +_testcapi_exception_print_impl(PyObject *module, PyObject *exc, int legacy); + +static PyObject * +_testcapi_exception_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc; + int legacy = 0; + + if (!_PyArg_CheckPositional("exception_print", nargs, 1, 2)) { + goto exit; + } + exc = args[0]; + if (nargs < 2) { + goto skip_optional; + } + legacy = PyObject_IsTrue(args[1]); + if (legacy < 0) { + goto exit; + } +skip_optional: + return_value = _testcapi_exception_print_impl(module, exc, legacy); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_make_exception_with_doc__doc__, +"make_exception_with_doc($module, /, name, doc=<unrepresentable>,\n" +" base=<unrepresentable>, dict=<unrepresentable>)\n" +"--\n" +"\n" +"Test PyErr_NewExceptionWithDoc (also exercise PyErr_NewException). Run via Lib/test/test_exceptions.py"); + +#define _TESTCAPI_MAKE_EXCEPTION_WITH_DOC_METHODDEF \ + {"make_exception_with_doc", _PyCFunction_CAST(_testcapi_make_exception_with_doc), METH_FASTCALL|METH_KEYWORDS, _testcapi_make_exception_with_doc__doc__}, + +static PyObject * +_testcapi_make_exception_with_doc_impl(PyObject *module, const char *name, + const char *doc, PyObject *base, + PyObject *dict); + +static PyObject * +_testcapi_make_exception_with_doc(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 4 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(name), &_Py_ID(doc), &_Py_ID(base), &_Py_ID(dict), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"name", "doc", "base", "dict", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "make_exception_with_doc", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + const char *name; + const char *doc = NULL; + PyObject *base = NULL; + PyObject *dict = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 4, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("make_exception_with_doc", "argument 'name'", "str", args[0]); + goto exit; + } + Py_ssize_t name_length; + name = PyUnicode_AsUTF8AndSize(args[0], &name_length); + if (name == NULL) { + goto exit; + } + if (strlen(name) != (size_t)name_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[1]) { + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("make_exception_with_doc", "argument 'doc'", "str", args[1]); + goto exit; + } + Py_ssize_t doc_length; + doc = PyUnicode_AsUTF8AndSize(args[1], &doc_length); + if (doc == NULL) { + goto exit; + } + if (strlen(doc) != (size_t)doc_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (args[2]) { + base = args[2]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + dict = args[3]; +skip_optional_pos: + return_value = _testcapi_make_exception_with_doc_impl(module, name, doc, base, dict); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_exc_set_object__doc__, +"exc_set_object($module, exception, obj, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_EXC_SET_OBJECT_METHODDEF \ + {"exc_set_object", _PyCFunction_CAST(_testcapi_exc_set_object), METH_FASTCALL, _testcapi_exc_set_object__doc__}, + +static PyObject * +_testcapi_exc_set_object_impl(PyObject *module, PyObject *exc, PyObject *obj); + +static PyObject * +_testcapi_exc_set_object(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc; + PyObject *obj; + + if (!_PyArg_CheckPositional("exc_set_object", nargs, 2, 2)) { + goto exit; + } + exc = args[0]; + obj = args[1]; + return_value = _testcapi_exc_set_object_impl(module, exc, obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_exc_set_object_fetch__doc__, +"exc_set_object_fetch($module, exception, obj, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_EXC_SET_OBJECT_FETCH_METHODDEF \ + {"exc_set_object_fetch", _PyCFunction_CAST(_testcapi_exc_set_object_fetch), METH_FASTCALL, _testcapi_exc_set_object_fetch__doc__}, + +static PyObject * +_testcapi_exc_set_object_fetch_impl(PyObject *module, PyObject *exc, + PyObject *obj); + +static PyObject * +_testcapi_exc_set_object_fetch(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc; + PyObject *obj; + + if (!_PyArg_CheckPositional("exc_set_object_fetch", nargs, 2, 2)) { + goto exit; + } + exc = args[0]; + obj = args[1]; + return_value = _testcapi_exc_set_object_fetch_impl(module, exc, obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_raise_exception__doc__, +"raise_exception($module, exception, num_args, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_RAISE_EXCEPTION_METHODDEF \ + {"raise_exception", _PyCFunction_CAST(_testcapi_raise_exception), METH_FASTCALL, _testcapi_raise_exception__doc__}, + +static PyObject * +_testcapi_raise_exception_impl(PyObject *module, PyObject *exc, int num_args); + +static PyObject * +_testcapi_raise_exception(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc; + int num_args; + + if (!_PyArg_CheckPositional("raise_exception", nargs, 2, 2)) { + goto exit; + } + exc = args[0]; + num_args = _PyLong_AsInt(args[1]); + if (num_args == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _testcapi_raise_exception_impl(module, exc, num_args); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_raise_memoryerror__doc__, +"raise_memoryerror($module, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_RAISE_MEMORYERROR_METHODDEF \ + {"raise_memoryerror", (PyCFunction)_testcapi_raise_memoryerror, METH_NOARGS, _testcapi_raise_memoryerror__doc__}, + +static PyObject * +_testcapi_raise_memoryerror_impl(PyObject *module); + +static PyObject * +_testcapi_raise_memoryerror(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_raise_memoryerror_impl(module); +} + +PyDoc_STRVAR(_testcapi_fatal_error__doc__, +"fatal_error($module, message, release_gil=False, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_FATAL_ERROR_METHODDEF \ + {"fatal_error", _PyCFunction_CAST(_testcapi_fatal_error), METH_FASTCALL, _testcapi_fatal_error__doc__}, + +static PyObject * +_testcapi_fatal_error_impl(PyObject *module, const char *message, + int release_gil); + +static PyObject * +_testcapi_fatal_error(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + const char *message; + int release_gil = 0; + + if (!_PyArg_ParseStack(args, nargs, "y|p:fatal_error", + &message, &release_gil)) { + goto exit; + } + return_value = _testcapi_fatal_error_impl(module, message, release_gil); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_set_exc_info__doc__, +"set_exc_info($module, new_type, new_value, new_tb, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_SET_EXC_INFO_METHODDEF \ + {"set_exc_info", _PyCFunction_CAST(_testcapi_set_exc_info), METH_FASTCALL, _testcapi_set_exc_info__doc__}, + +static PyObject * +_testcapi_set_exc_info_impl(PyObject *module, PyObject *new_type, + PyObject *new_value, PyObject *new_tb); + +static PyObject * +_testcapi_set_exc_info(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *new_type; + PyObject *new_value; + PyObject *new_tb; + + if (!_PyArg_CheckPositional("set_exc_info", nargs, 3, 3)) { + goto exit; + } + new_type = args[0]; + new_value = args[1]; + new_tb = args[2]; + return_value = _testcapi_set_exc_info_impl(module, new_type, new_value, new_tb); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_set_exception__doc__, +"set_exception($module, new_exc, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_SET_EXCEPTION_METHODDEF \ + {"set_exception", (PyCFunction)_testcapi_set_exception, METH_O, _testcapi_set_exception__doc__}, + +PyDoc_STRVAR(_testcapi_write_unraisable_exc__doc__, +"write_unraisable_exc($module, exception, err_msg, obj, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_WRITE_UNRAISABLE_EXC_METHODDEF \ + {"write_unraisable_exc", _PyCFunction_CAST(_testcapi_write_unraisable_exc), METH_FASTCALL, _testcapi_write_unraisable_exc__doc__}, + +static PyObject * +_testcapi_write_unraisable_exc_impl(PyObject *module, PyObject *exc, + PyObject *err_msg, PyObject *obj); + +static PyObject * +_testcapi_write_unraisable_exc(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc; + PyObject *err_msg; + PyObject *obj; + + if (!_PyArg_CheckPositional("write_unraisable_exc", nargs, 3, 3)) { + goto exit; + } + exc = args[0]; + err_msg = args[1]; + obj = args[2]; + return_value = _testcapi_write_unraisable_exc_impl(module, exc, err_msg, obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_traceback_print__doc__, +"traceback_print($module, traceback, file, /)\n" +"--\n" +"\n" +"To test the format of tracebacks as printed out."); + +#define _TESTCAPI_TRACEBACK_PRINT_METHODDEF \ + {"traceback_print", _PyCFunction_CAST(_testcapi_traceback_print), METH_FASTCALL, _testcapi_traceback_print__doc__}, + +static PyObject * +_testcapi_traceback_print_impl(PyObject *module, PyObject *traceback, + PyObject *file); + +static PyObject * +_testcapi_traceback_print(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *traceback; + PyObject *file; + + if (!_PyArg_CheckPositional("traceback_print", nargs, 2, 2)) { + goto exit; + } + traceback = args[0]; + file = args[1]; + return_value = _testcapi_traceback_print_impl(module, traceback, file); + +exit: + return return_value; +} +/*[clinic end generated code: output=ec1b2e62adea9846 input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 6099f7d20eb5..0a9902c135a7 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -1,7 +1,20 @@ #include "parts.h" +#include "clinic/exceptions.c.h" + +/*[clinic input] +module _testcapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ + +/*[clinic input] +_testcapi.err_set_raised + exception as exc: object + / +[clinic start generated code]*/ static PyObject * -err_set_raised(PyObject *self, PyObject *exc) +_testcapi_err_set_raised(PyObject *module, PyObject *exc) +/*[clinic end generated code: output=0a0c7743961fcae5 input=c5f7331864a94df9]*/ { Py_INCREF(exc); PyErr_SetRaisedException(exc); @@ -35,16 +48,19 @@ err_restore(PyObject *self, PyObject *args) { return NULL; } -/* To test the format of exceptions as printed out. */ +/*[clinic input] +_testcapi.exception_print + exception as exc: object + legacy: bool = False + / + +To test the format of exceptions as printed out. +[clinic start generated code]*/ + static PyObject * -exception_print(PyObject *self, PyObject *args) +_testcapi_exception_print_impl(PyObject *module, PyObject *exc, int legacy) +/*[clinic end generated code: output=3f04fe0c18412ae0 input=c76f42cb94136dbf]*/ { - PyObject *exc; - int legacy = 0; - - if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) { - return NULL; - } if (legacy) { PyObject *tb = NULL; if (PyExceptionInstance_Check(exc)) { @@ -59,55 +75,53 @@ exception_print(PyObject *self, PyObject *args) Py_RETURN_NONE; } -/* Test PyErr_NewExceptionWithDoc (also exercise PyErr_NewException). - Run via Lib/test/test_exceptions.py */ -static PyObject * -make_exception_with_doc(PyObject *self, PyObject *args, PyObject *kwargs) -{ - const char *name; - const char *doc = NULL; - PyObject *base = NULL; - PyObject *dict = NULL; - - static char *kwlist[] = {"name", "doc", "base", "dict", NULL}; +/*[clinic input] +_testcapi.make_exception_with_doc + name: str + doc: str = NULL + base: object = NULL + dict: object = NULL - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "s|sOO:make_exception_with_doc", kwlist, - &name, &doc, &base, &dict)) - { - return NULL; - } +Test PyErr_NewExceptionWithDoc (also exercise PyErr_NewException). Run via Lib/test/test_exceptions.py +[clinic start generated code]*/ +static PyObject * +_testcapi_make_exception_with_doc_impl(PyObject *module, const char *name, + const char *doc, PyObject *base, + PyObject *dict) +/*[clinic end generated code: output=439f0d963c1ce2c4 input=23a73013f8a8795a]*/ +{ return PyErr_NewExceptionWithDoc(name, doc, base, dict); } +/*[clinic input] +_testcapi.exc_set_object + exception as exc: object + obj: object + / +[clinic start generated code]*/ + static PyObject * -exc_set_object(PyObject *self, PyObject *args) +_testcapi_exc_set_object_impl(PyObject *module, PyObject *exc, PyObject *obj) +/*[clinic end generated code: output=34c8c7c83e5c8463 input=fc530aafb1b0a360]*/ { - PyObject *exc; - PyObject *obj; - - if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { - return NULL; - } - PyErr_SetObject(exc, obj); return NULL; } +/*[clinic input] +_testcapi.exc_set_object_fetch = _testcapi.exc_set_object +[clinic start generated code]*/ + static PyObject * -exc_set_object_fetch(PyObject *self, PyObject *args) +_testcapi_exc_set_object_fetch_impl(PyObject *module, PyObject *exc, + PyObject *obj) +/*[clinic end generated code: output=7a5ff5f6d3cf687f input=77ec686f1f95fa38]*/ { - PyObject *exc; - PyObject *obj; PyObject *type; PyObject *value; PyObject *tb; - if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { - return NULL; - } - PyErr_SetObject(exc, obj); PyErr_Fetch(&type, &value, &tb); Py_XDECREF(type); @@ -115,16 +129,17 @@ exc_set_object_fetch(PyObject *self, PyObject *args) return value; } +/*[clinic input] +_testcapi.raise_exception + exception as exc: object + num_args: int + / +[clinic start generated code]*/ + static PyObject * -raise_exception(PyObject *self, PyObject *args) +_testcapi_raise_exception_impl(PyObject *module, PyObject *exc, int num_args) +/*[clinic end generated code: output=eb0a9c5d69e0542d input=83d6262c3829d088]*/ { - PyObject *exc; - int num_args; - - if (!PyArg_ParseTuple(args, "Oi:raise_exception", &exc, &num_args)) { - return NULL; - } - PyObject *exc_args = PyTuple_New(num_args); if (exc_args == NULL) { return NULL; @@ -142,21 +157,29 @@ raise_exception(PyObject *self, PyObject *args) return NULL; } -/* reliably raise a MemoryError */ +/*[clinic input] +_testcapi.raise_memoryerror +[clinic start generated code]*/ + static PyObject * -raise_memoryerror(PyObject *self, PyObject *Py_UNUSED(ignored)) +_testcapi_raise_memoryerror_impl(PyObject *module) +/*[clinic end generated code: output=dd057803fb0131e6 input=6ca521bd07fb73cb]*/ { return PyErr_NoMemory(); } +/*[clinic input] +_testcapi.fatal_error + message: str(accept={robuffer}) + release_gil: bool = False + / +[clinic start generated code]*/ + static PyObject * -test_fatal_error(PyObject *self, PyObject *args) +_testcapi_fatal_error_impl(PyObject *module, const char *message, + int release_gil) +/*[clinic end generated code: output=9c3237116e6a03e8 input=1be357a2ccb04c8c]*/ { - char *message; - int release_gil = 0; - if (!PyArg_ParseTuple(args, "y|i:fatal_error", &message, &release_gil)) { - return NULL; - } if (release_gil) { Py_BEGIN_ALLOW_THREADS Py_FatalError(message); @@ -169,17 +192,20 @@ test_fatal_error(PyObject *self, PyObject *args) Py_RETURN_NONE; } +/*[clinic input] +_testcapi.set_exc_info + new_type: object + new_value: object + new_tb: object + / +[clinic start generated code]*/ + static PyObject * -test_set_exc_info(PyObject *self, PyObject *args) +_testcapi_set_exc_info_impl(PyObject *module, PyObject *new_type, + PyObject *new_value, PyObject *new_tb) +/*[clinic end generated code: output=b55fa35dec31300e input=ea9f19e0f55fe5b3]*/ { - PyObject *new_type, *new_value, *new_tb; PyObject *type, *value, *tb; - if (!PyArg_ParseTuple(args, "OOO:test_set_exc_info", - &new_type, &new_value, &new_tb)) - { - return NULL; - } - PyErr_GetExcInfo(&type, &value, &tb); Py_INCREF(new_type); @@ -197,23 +223,35 @@ test_set_exc_info(PyObject *self, PyObject *args) return orig_exc; } +/*[clinic input] +_testcapi.set_exception + new_exc: object + / +[clinic start generated code]*/ + static PyObject * -test_set_exception(PyObject *self, PyObject *new_exc) +_testcapi_set_exception(PyObject *module, PyObject *new_exc) +/*[clinic end generated code: output=8b969b35d029e96d input=c89d4ca966c69738]*/ { PyObject *exc = PyErr_GetHandledException(); assert(PyExceptionInstance_Check(exc) || exc == NULL); - PyErr_SetHandledException(new_exc); return exc; } +/*[clinic input] +_testcapi.write_unraisable_exc + exception as exc: object + err_msg: object + obj: object + / +[clinic start generated code]*/ + static PyObject * -test_write_unraisable_exc(PyObject *self, PyObject *args) +_testcapi_write_unraisable_exc_impl(PyObject *module, PyObject *exc, + PyObject *err_msg, PyObject *obj) +/*[clinic end generated code: output=39827c5e0a8c2092 input=582498da5b2ee6cf]*/ { - PyObject *exc, *err_msg, *obj; - if (!PyArg_ParseTuple(args, "OOO", &exc, &err_msg, &obj)) { - return NULL; - } const char *err_msg_utf8; if (err_msg != Py_None) { @@ -231,19 +269,19 @@ test_write_unraisable_exc(PyObject *self, PyObject *args) Py_RETURN_NONE; } -/* To test the format of tracebacks as printed out. */ +/*[clinic input] +_testcapi.traceback_print + traceback: object + file: object + / +To test the format of tracebacks as printed out. +[clinic start generated code]*/ + static PyObject * -traceback_print(PyObject *self, PyObject *args) +_testcapi_traceback_print_impl(PyObject *module, PyObject *traceback, + PyObject *file) +/*[clinic end generated code: output=17074ecf9d95cf30 input=9423f2857b008ca8]*/ { - PyObject *file; - PyObject *traceback; - - if (!PyArg_ParseTuple(args, "OO:traceback_print", - &traceback, &file)) - { - return NULL; - } - if (PyTraceBack_Print(traceback, file) < 0) { return NULL; } @@ -278,20 +316,18 @@ static PyTypeObject PyRecursingInfinitelyError_Type = { static PyMethodDef test_methods[] = { {"err_restore", err_restore, METH_VARARGS}, - {"err_set_raised", err_set_raised, METH_O}, - {"exception_print", exception_print, METH_VARARGS}, - {"fatal_error", test_fatal_error, METH_VARARGS, - PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")}, - {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), - METH_VARARGS | METH_KEYWORDS}, - {"exc_set_object", exc_set_object, METH_VARARGS}, - {"exc_set_object_fetch", exc_set_object_fetch, METH_VARARGS}, - {"raise_exception", raise_exception, METH_VARARGS}, - {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, - {"set_exc_info", test_set_exc_info, METH_VARARGS}, - {"set_exception", test_set_exception, METH_O}, - {"traceback_print", traceback_print, METH_VARARGS}, - {"write_unraisable_exc", test_write_unraisable_exc, METH_VARARGS}, + _TESTCAPI_ERR_SET_RAISED_METHODDEF + _TESTCAPI_EXCEPTION_PRINT_METHODDEF + _TESTCAPI_FATAL_ERROR_METHODDEF + _TESTCAPI_MAKE_EXCEPTION_WITH_DOC_METHODDEF + _TESTCAPI_EXC_SET_OBJECT_METHODDEF + _TESTCAPI_EXC_SET_OBJECT_FETCH_METHODDEF + _TESTCAPI_RAISE_EXCEPTION_METHODDEF + _TESTCAPI_RAISE_MEMORYERROR_METHODDEF + _TESTCAPI_SET_EXC_INFO_METHODDEF + _TESTCAPI_SET_EXCEPTION_METHODDEF + _TESTCAPI_TRACEBACK_PRINT_METHODDEF + _TESTCAPI_WRITE_UNRAISABLE_EXC_METHODDEF {NULL}, }; From webhook-mailer at python.org Sun May 21 06:12:32 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 21 May 2023 10:12:32 -0000 Subject: [Python-checkins] gh-103295: expose API for writing perf map files (#103546) Message-ID: <mailman.496.1684663953.13550.python-checkins@python.org> https://github.com/python/cpython/commit/be0c106789322273f1f76d232c768c09880a14bd commit: be0c106789322273f1f76d232c768c09880a14bd branch: main author: gsallam <123525874+gsallam at users.noreply.github.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-21T11:12:24+01:00 summary: gh-103295: expose API for writing perf map files (#103546) Co-authored-by: Aniket Panse <aniketpanse at fb.com> Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Carl Meyer <carl at oddbird.net> files: A Doc/c-api/perfmaps.rst A Lib/test/test_perfmaps.py A Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst M Doc/c-api/utilities.rst M Doc/howto/perf_profiling.rst M Include/sysmodule.h M Modules/_testinternalcapi.c M Python/perf_trampoline.c M Python/pylifecycle.c M Python/sysmodule.c M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Doc/c-api/perfmaps.rst b/Doc/c-api/perfmaps.rst new file mode 100644 index 000000000000..3d44d2eb6bf4 --- /dev/null +++ b/Doc/c-api/perfmaps.rst @@ -0,0 +1,50 @@ +.. highlight:: c + +.. _perfmaps: + +Support for Perf Maps +---------------------- + +On supported platforms (as of this writing, only Linux), the runtime can take +advantage of *perf map files* to make Python functions visible to an external +profiling tool (such as `perf <https://perf.wiki.kernel.org/index.php/Main_Page>`_). +A running process may create a file in the ``/tmp`` directory, which contains entries +that can map a section of executable code to a name. This interface is described in the +`documentation of the Linux Perf tool <https://git.kernel.org/pub/scm/linux/ +kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt>`_. + +In Python, these helper APIs can be used by libraries and features that rely +on generating machine code on the fly. + +Note that holding the Global Interpreter Lock (GIL) is not required for these APIs. + +.. c:function:: int PyUnstable_PerfMapState_Init(void) + + Open the ``/tmp/perf-$pid.map`` file, unless it's already opened, and create + a lock to ensure thread-safe writes to the file (provided the writes are + done through :c:func:`PyUnstable_WritePerfMapEntry`). Normally, there's no need + to call this explicitly; just use :c:func:`PyUnstable_WritePerfMapEntry` + and it will initialize the state on first call. + + Returns ``0`` on success, ``-1`` on failure to create/open the perf map file, + or ``-2`` on failure to create a lock. Check ``errno`` for more information + about the cause of a failure. + +.. c:function:: int PyUnstable_WritePerfMapEntry(const void *code_addr, unsigned int code_size, const char *entry_name) + + Write one single entry to the ``/tmp/perf-$pid.map`` file. This function is + thread safe. Here is what an example entry looks like:: + + # address size name + 7f3529fcf759 b py::bar:/run/t.py + + Will call :c:func:`PyUnstable_PerfMapState_Init` before writing the entry, if + the perf map file is not already opened. Returns ``0`` on success, or the + same error codes as :c:func:`PyUnstable_PerfMapState_Init` on failure. + +.. c:function:: void PyUnstable_PerfMapState_Fini(void) + + Close the perf map file opened by :c:func:`PyUnstable_PerfMapState_Init`. + This is called by the runtime itself during interpreter shut-down. In + general, there shouldn't be a reason to explicitly call this, except to + handle specific scenarios such as forking. diff --git a/Doc/c-api/utilities.rst b/Doc/c-api/utilities.rst index a805b564763c..ccbf14e1850f 100644 --- a/Doc/c-api/utilities.rst +++ b/Doc/c-api/utilities.rst @@ -19,3 +19,4 @@ and parsing function arguments and constructing Python values from C values. conversion.rst reflection.rst codec.rst + perfmaps.rst diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst index 6af5536166f5..61812c19ae6c 100644 --- a/Doc/howto/perf_profiling.rst +++ b/Doc/howto/perf_profiling.rst @@ -24,7 +24,7 @@ functions to appear in the output of the ``perf`` profiler. When this mode is enabled, the interpreter will interpose a small piece of code compiled on the fly before the execution of every Python function and it will teach ``perf`` the relationship between this piece of code and the associated Python function using -`perf map files`_. +:doc:`perf map files <../c-api/perfmaps>`. .. note:: @@ -206,5 +206,3 @@ You can check if your system has been compiled with this flag by running:: If you don't see any output it means that your interpreter has not been compiled with frame pointers and therefore it may not be able to show Python functions in the output of ``perf``. - -.. _perf map files: https://github.com/torvalds/linux/blob/0513e464f9007b70b96740271a948ca5ab6e7dd7/tools/perf/Documentation/jit-interface.txt diff --git a/Include/sysmodule.h b/Include/sysmodule.h index b5087119b1ca..96f883870b34 100644 --- a/Include/sysmodule.h +++ b/Include/sysmodule.h @@ -29,6 +29,19 @@ Py_DEPRECATED(3.11) PyAPI_FUNC(int) PySys_HasWarnOptions(void); Py_DEPRECATED(3.11) PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *); PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); +#if !defined(Py_LIMITED_API) +typedef struct { + FILE* perf_map; + PyThread_type_lock map_lock; +} PerfMapState; + +PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void); + +PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry(const void *code_addr, unsigned int code_size, const char *entry_name); + +PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void); +#endif + #ifndef Py_LIMITED_API # define Py_CPYTHON_SYSMODULE_H # include "cpython/sysmodule.h" diff --git a/Lib/test/test_perfmaps.py b/Lib/test/test_perfmaps.py new file mode 100644 index 000000000000..a17adb89f553 --- /dev/null +++ b/Lib/test/test_perfmaps.py @@ -0,0 +1,19 @@ +import os +import sys +import unittest + +from _testinternalcapi import perf_map_state_teardown, write_perf_map_entry + +if sys.platform != 'linux': + raise unittest.SkipTest('Linux only') + + +class TestPerfMapWriting(unittest.TestCase): + def test_write_perf_map_entry(self): + self.assertEqual(write_perf_map_entry(0x1234, 5678, "entry1"), 0) + self.assertEqual(write_perf_map_entry(0x2345, 6789, "entry2"), 0) + with open(f"/tmp/perf-{os.getpid()}.map") as f: + perf_file_contents = f.read() + self.assertIn("1234 162e entry1", perf_file_contents) + self.assertIn("2345 1a85 entry2", perf_file_contents) + perf_map_state_teardown() diff --git a/Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst b/Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst new file mode 100644 index 000000000000..88222239858b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst @@ -0,0 +1,5 @@ +Introduced :c:func:`PyUnstable_WritePerfMapEntry`, :c:func:`PyUnstable_PerfMapState_Init` and +:c:func:`PyUnstable_PerfMapState_Fini`. These allow extension modules (JIT compilers in +particular) to write to perf-map files in a thread safe manner. The +:doc:`../howto/perf_profiling` also uses these APIs to write +entries in the perf-map file. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 3ee332393083..b91f7b620fdb 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -759,6 +759,31 @@ clear_extension(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +write_perf_map_entry(PyObject *self, PyObject *args) +{ + const void *code_addr; + unsigned int code_size; + const char *entry_name; + + if (!PyArg_ParseTuple(args, "KIs", &code_addr, &code_size, &entry_name)) + return NULL; + + int ret = PyUnstable_WritePerfMapEntry(code_addr, code_size, entry_name); + if (ret == -1) { + PyErr_SetString(PyExc_OSError, "Failed to write performance map entry"); + return NULL; + } + return Py_BuildValue("i", ret); +} + +static PyObject * +perf_map_state_teardown(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) +{ + PyUnstable_PerfMapState_Fini(); + Py_RETURN_NONE; +} + static PyObject * iframe_getcode(PyObject *self, PyObject *frame) { @@ -815,6 +840,8 @@ static PyMethodDef module_functions[] = { _TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF {"get_interp_settings", get_interp_settings, METH_VARARGS, NULL}, {"clear_extension", clear_extension, METH_VARARGS, NULL}, + {"write_perf_map_entry", write_perf_map_entry, METH_VARARGS}, + {"perf_map_state_teardown", perf_map_state_teardown, METH_NOARGS}, {"iframe_getcode", iframe_getcode, METH_O, NULL}, {"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 3b183280e1f2..6a6f223d095d 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -193,75 +193,33 @@ typedef struct trampoline_api_st trampoline_api_t; #define trampoline_api _PyRuntime.ceval.perf.trampoline_api #define perf_map_file _PyRuntime.ceval.perf.map_file -static void * -perf_map_get_file(void) -{ - if (perf_map_file) { - return perf_map_file; - } - char filename[100]; - pid_t pid = getpid(); - // Location and file name of perf map is hard-coded in perf tool. - // Use exclusive create flag wit nofollow to prevent symlink attacks. - int flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC; - snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map", - (intmax_t)pid); - int fd = open(filename, flags, 0600); - if (fd == -1) { - perf_status = PERF_STATUS_FAILED; - PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); - return NULL; - } - perf_map_file = fdopen(fd, "w"); - if (!perf_map_file) { - perf_status = PERF_STATUS_FAILED; - PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename); - close(fd); - return NULL; - } - return perf_map_file; -} - -static int -perf_map_close(void *state) -{ - FILE *fp = (FILE *)state; - int ret = 0; - if (fp) { - ret = fclose(fp); - } - perf_map_file = NULL; - perf_status = PERF_STATUS_NO_INIT; - return ret; -} static void perf_map_write_entry(void *state, const void *code_addr, unsigned int code_size, PyCodeObject *co) { - assert(state != NULL); - FILE *method_file = (FILE *)state; - const char *entry = PyUnicode_AsUTF8(co->co_qualname); - if (entry == NULL) { - _PyErr_WriteUnraisableMsg("Failed to get qualname from code object", - NULL); - return; + const char *entry = ""; + if (co->co_qualname != NULL) { + entry = PyUnicode_AsUTF8(co->co_qualname); } - const char *filename = PyUnicode_AsUTF8(co->co_filename); - if (filename == NULL) { - _PyErr_WriteUnraisableMsg("Failed to get filename from code object", - NULL); + const char *filename = ""; + if (co->co_filename != NULL) { + filename = PyUnicode_AsUTF8(co->co_filename); + } + size_t perf_map_entry_size = snprintf(NULL, 0, "py::%s:%s", entry, filename) + 1; + char* perf_map_entry = (char*) PyMem_RawMalloc(perf_map_entry_size); + if (perf_map_entry == NULL) { return; } - fprintf(method_file, "%" PRIxPTR " %x py::%s:%s\n", (uintptr_t) code_addr, code_size, entry, - filename); - fflush(method_file); + snprintf(perf_map_entry, perf_map_entry_size, "py::%s:%s", entry, filename); + PyUnstable_WritePerfMapEntry(code_addr, code_size, perf_map_entry); + PyMem_RawFree(perf_map_entry); } _PyPerf_Callbacks _Py_perfmap_callbacks = { - &perf_map_get_file, + NULL, &perf_map_write_entry, - &perf_map_close + NULL, }; static int @@ -465,13 +423,6 @@ _PyPerfTrampoline_Init(int activate) if (new_code_arena() < 0) { return -1; } - if (trampoline_api.state == NULL) { - void *state = trampoline_api.init_state(); - if (state == NULL) { - return -1; - } - trampoline_api.state = state; - } extra_code_index = _PyEval_RequestCodeExtraIndex(NULL); if (extra_code_index == -1) { return -1; @@ -491,10 +442,6 @@ _PyPerfTrampoline_Fini(void) tstate->interp->eval_frame = NULL; } free_code_arenas(); - if (trampoline_api.state != NULL) { - trampoline_api.free_state(trampoline_api.state); - trampoline_api.state = NULL; - } extra_code_index = -1; #endif return 0; @@ -507,6 +454,7 @@ _PyPerfTrampoline_AfterFork_Child(void) // Restart trampoline in file in child. int was_active = _PyIsPerfTrampolineActive(); _PyPerfTrampoline_Fini(); + PyUnstable_PerfMapState_Fini(); if (was_active) { _PyPerfTrampoline_Init(1); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 93ad1fe09801..06c43459624c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1775,6 +1775,7 @@ Py_FinalizeEx(void) */ _PyAtExit_Call(tstate->interp); + PyUnstable_PerfMapState_Fini(); /* Copy the core config, PyInterpreterState_Delete() free the core config memory */ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 7510be538caa..33147f012b61 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -52,6 +52,10 @@ extern const char *PyWin_DLLVersionString; #include <emscripten.h> #endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + /*[clinic input] module sys [clinic start generated code]*/ @@ -2144,7 +2148,7 @@ sys_activate_stack_trampoline_impl(PyObject *module, const char *backend) if (strcmp(backend, "perf") == 0) { _PyPerf_Callbacks cur_cb; _PyPerfTrampoline_GetCallbacks(&cur_cb); - if (cur_cb.init_state != _Py_perfmap_callbacks.init_state) { + if (cur_cb.write_state != _Py_perfmap_callbacks.write_state) { if (_PyPerfTrampoline_SetCallbacks(&_Py_perfmap_callbacks) < 0 ) { PyErr_SetString(PyExc_ValueError, "can't activate perf trampoline"); return NULL; @@ -2240,6 +2244,80 @@ sys__getframemodulename_impl(PyObject *module, int depth) } +#ifdef __cplusplus +extern "C" { +#endif + +static PerfMapState perf_map_state; + +PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void) { +#ifndef MS_WINDOWS + char filename[100]; + pid_t pid = getpid(); + // Use nofollow flag to prevent symlink attacks. + int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW | O_CLOEXEC; + snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map", + (intmax_t)pid); + int fd = open(filename, flags, 0600); + if (fd == -1) { + return -1; + } + else{ + perf_map_state.perf_map = fdopen(fd, "a"); + if (perf_map_state.perf_map == NULL) { + close(fd); + return -1; + } + } + perf_map_state.map_lock = PyThread_allocate_lock(); + if (perf_map_state.map_lock == NULL) { + fclose(perf_map_state.perf_map); + return -2; + } +#endif + return 0; +} + +PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry( + const void *code_addr, + unsigned int code_size, + const char *entry_name +) { +#ifndef MS_WINDOWS + if (perf_map_state.perf_map == NULL) { + int ret = PyUnstable_PerfMapState_Init(); + if(ret != 0){ + return ret; + } + } + PyThread_acquire_lock(perf_map_state.map_lock, 1); + fprintf(perf_map_state.perf_map, "%" PRIxPTR " %x %s\n", (uintptr_t) code_addr, code_size, entry_name); + fflush(perf_map_state.perf_map); + PyThread_release_lock(perf_map_state.map_lock); +#endif + return 0; +} + +PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void) { +#ifndef MS_WINDOWS + if (perf_map_state.perf_map != NULL) { + // close the file + PyThread_acquire_lock(perf_map_state.map_lock, 1); + fclose(perf_map_state.perf_map); + PyThread_release_lock(perf_map_state.map_lock); + + // clean up the lock and state + PyThread_free_lock(perf_map_state.map_lock); + perf_map_state.perf_map = NULL; + } +#endif +} + +#ifdef __cplusplus +} +#endif + + static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ SYS_ADDAUDITHOOK_METHODDEF diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 7ba116dcb171..e9056aed5dc0 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -356,6 +356,7 @@ Python/pystate.c - initial - Python/specialize.c - adaptive_opcodes - Python/specialize.c - cache_requirements - Python/stdlib_module_names.h - _Py_stdlib_module_names - +Python/sysmodule.c - perf_map_state - Python/sysmodule.c - _PySys_ImplCacheTag - Python/sysmodule.c - _PySys_ImplName - Python/sysmodule.c - whatstrings - From webhook-mailer at python.org Sun May 21 07:52:35 2023 From: webhook-mailer at python.org (hugovk) Date: Sun, 21 May 2023 11:52:35 -0000 Subject: [Python-checkins] gh-86275: improve Hypothesis configuration for CI and local runs (#104468) Message-ID: <mailman.497.1684669957.13550.python-checkins@python.org> https://github.com/python/cpython/commit/014dd301b5a075a73430eb4e583e851f49d03e29 commit: 014dd301b5a075a73430eb4e583e851f49d03e29 branch: main author: Zac Hatfield-Dodds <zac.hatfield.dodds at gmail.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-21T05:52:29-06:00 summary: gh-86275: improve Hypothesis configuration for CI and local runs (#104468) files: M .github/workflows/build.yml M Lib/test/support/hypothesis_helper.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69b78e5567ad..41abddffa5d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -368,6 +368,14 @@ jobs: echo "HYPOVENV=${VENV_LOC}" >> $GITHUB_ENV echo "VENV_PYTHON=${VENV_PYTHON}" >> $GITHUB_ENV ./python -m venv $VENV_LOC && $VENV_PYTHON -m pip install -U hypothesis + - name: 'Restore Hypothesis database' + id: cache-hypothesis-database + uses: actions/cache at v3 + with: + path: ./hypothesis + key: hypothesis-database-${{ github.head_ref || github.run_id }} + restore-keys: | + - hypothesis-database- - name: "Run tests" working-directory: ${{ env.CPYTHON_BUILDDIR }} run: | @@ -388,6 +396,11 @@ jobs: -x test_subprocess \ -x test_signal \ -x test_sysconfig + - uses: actions/upload-artifact at v3 + if: always() + with: + name: hypothesis-example-db + path: .hypothesis/examples/ build_asan: diff --git a/Lib/test/support/hypothesis_helper.py b/Lib/test/support/hypothesis_helper.py index 76bd2490fe6e..da16eb50c259 100644 --- a/Lib/test/support/hypothesis_helper.py +++ b/Lib/test/support/hypothesis_helper.py @@ -1,4 +1,35 @@ +import os + try: import hypothesis except ImportError: from . import _hypothesis_stubs as hypothesis +else: + # When using the real Hypothesis, we'll configure it to ignore occasional + # slow tests (avoiding flakiness from random VM slowness in CI). + hypothesis.settings.register_profile( + "slow-is-ok", + deadline=None, + suppress_health_check=[hypothesis.HealthCheck.too_slow], + ) + hypothesis.settings.load_profile("slow-is-ok") + + # For local development, we'll write to the default on-local-disk database + # of failing examples, and also use a pull-through cache to automatically + # replay any failing examples discovered in CI. For details on how this + # works, see https://hypothesis.readthedocs.io/en/latest/database.html + if "CI" not in os.environ: + from hypothesis.database import ( + GitHubArtifactDatabase, + MultiplexedDatabase, + ReadOnlyDatabase, + ) + + hypothesis.settings.register_profile( + "cpython-local-dev", + database=MultiplexedDatabase( + hypothesis.settings.default.database, + ReadOnlyDatabase(GitHubArtifactDatabase("python", "cpython")), + ), + ) + hypothesis.settings.load_profile("cpython-local-dev") From webhook-mailer at python.org Sun May 21 08:08:35 2023 From: webhook-mailer at python.org (corona10) Date: Sun, 21 May 2023 12:08:35 -0000 Subject: [Python-checkins] gh-104717: Add comment about manual loop unrolling (gh-104718) Message-ID: <mailman.498.1684670915.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b9fcfa60244da85d8847a05e8d5e75d0a6694f90 commit: b9fcfa60244da85d8847a05e8d5e75d0a6694f90 branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-21T21:08:28+09:00 summary: gh-104717: Add comment about manual loop unrolling (gh-104718) files: M Objects/dictobject.c diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 7436c113f37c..254cd9ad2f9b 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -944,6 +944,7 @@ unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash) } perturb >>= PERTURB_SHIFT; i = mask & (i*5 + perturb + 1); + // Manual loop unrolling ix = dictkeys_get_index(dk, i); if (ix >= 0) { PyDictUnicodeEntry *ep = &ep0[ix]; From webhook-mailer at python.org Sun May 21 09:00:57 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 21 May 2023 13:00:57 -0000 Subject: [Python-checkins] typing docs: Move some classes out of the "Generics" section (#104707) Message-ID: <mailman.499.1684674059.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ab71acd67b5b09926498b8c7f855bdb28ac0ec2f commit: ab71acd67b5b09926498b8c7f855bdb28ac0ec2f branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-21T06:00:50-07:00 summary: typing docs: Move some classes out of the "Generics" section (#104707) - AnyStr can be used in type annotations, contrary to the section header - Unpack can also be used in annotations, and its use is not restricted to generics. It makes more sense with other building blocks like Required. - Protocol is not necessarily generic. Also fix the indentation for two notes associated with Concatenate. Split off from #104642, but I think this change is independently an improvement. files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c300c4257f0e..c90cb411acde 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -616,6 +616,21 @@ These can be used as types in annotations and do not support ``[]``. avoiding type checker errors with classes that can duck type anywhere or are highly dynamic. +.. data:: AnyStr + + ``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as + ``AnyStr = TypeVar('AnyStr', str, bytes)``. + + It is meant to be used for functions that may accept any kind of string + without allowing different kinds of strings to mix. For example:: + + def concat(a: AnyStr, b: AnyStr) -> AnyStr: + return a + b + + concat(u"foo", u"bar") # Ok, output has type 'unicode' + concat(b"foo", b"bar") # Ok, output has type 'bytes' + concat(u"foo", b"bar") # Error, cannot mix unicode and bytes + .. data:: LiteralString Special type that includes only literal strings. A string @@ -917,13 +932,13 @@ These can be used as types in annotations using ``[]``, each having a unique syn # We don't need to pass in the lock ourselves thanks to the decorator. sum_threadsafe([1.1, 2.2, 3.3]) -.. versionadded:: 3.10 + .. versionadded:: 3.10 -.. seealso:: + .. seealso:: - * :pep:`612` -- Parameter Specification Variables (the PEP which introduced - ``ParamSpec`` and ``Concatenate``). - * :class:`ParamSpec` and :class:`Callable`. + * :pep:`612` -- Parameter Specification Variables (the PEP which introduced + ``ParamSpec`` and ``Concatenate``). + * :class:`ParamSpec` and :class:`Callable`. .. class:: Type(Generic[CT_co]) @@ -1208,6 +1223,49 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.10 +.. data:: Unpack + + A typing operator that conceptually marks an object as having been + unpacked. For example, using the unpack operator ``*`` on a + :class:`type variable tuple <TypeVarTuple>` is equivalent to using ``Unpack`` + to mark the type variable tuple as having been unpacked:: + + Ts = TypeVarTuple('Ts') + tup: tuple[*Ts] + # Effectively does: + tup: tuple[Unpack[Ts]] + + In fact, ``Unpack`` can be used interchangeably with ``*`` in the context + of :class:`typing.TypeVarTuple <TypeVarTuple>` and + :class:`builtins.tuple <tuple>` types. You might see ``Unpack`` being used + explicitly in older versions of Python, where ``*`` couldn't be used in + certain places:: + + # In older versions of Python, TypeVarTuple and Unpack + # are located in the `typing_extensions` backports package. + from typing_extensions import TypeVarTuple, Unpack + + Ts = TypeVarTuple('Ts') + tup: tuple[*Ts] # Syntax error on Python <= 3.10! + tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible + + ``Unpack`` can also be used along with :class:`typing.TypedDict` for typing + ``**kwargs`` in a function signature:: + + from typing import TypedDict, Unpack + + class Movie(TypedDict): + name: str + year: int + + # This function expects two keyword arguments - `name` of type `str` + # and `year` of type `int`. + def foo(**kwargs: Unpack[Movie]): ... + + See :pep:`692` for more details on using ``Unpack`` for ``**kwargs`` typing. + + .. versionadded:: 3.11 + Building generic types """""""""""""""""""""" @@ -1409,49 +1467,6 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.11 -.. data:: Unpack - - A typing operator that conceptually marks an object as having been - unpacked. For example, using the unpack operator ``*`` on a - :class:`type variable tuple <TypeVarTuple>` is equivalent to using ``Unpack`` - to mark the type variable tuple as having been unpacked:: - - Ts = TypeVarTuple('Ts') - tup: tuple[*Ts] - # Effectively does: - tup: tuple[Unpack[Ts]] - - In fact, ``Unpack`` can be used interchangeably with ``*`` in the context - of :class:`typing.TypeVarTuple <TypeVarTuple>` and - :class:`builtins.tuple <tuple>` types. You might see ``Unpack`` being used - explicitly in older versions of Python, where ``*`` couldn't be used in - certain places:: - - # In older versions of Python, TypeVarTuple and Unpack - # are located in the `typing_extensions` backports package. - from typing_extensions import TypeVarTuple, Unpack - - Ts = TypeVarTuple('Ts') - tup: tuple[*Ts] # Syntax error on Python <= 3.10! - tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible - - ``Unpack`` can also be used along with :class:`typing.TypedDict` for typing - ``**kwargs`` in a function signature:: - - from typing import TypedDict, Unpack - - class Movie(TypedDict): - name: str - year: int - - # This function expects two keyword arguments - `name` of type `str` - # and `year` of type `int`. - def foo(**kwargs: Unpack[Movie]): ... - - See :pep:`692` for more details on using ``Unpack`` for ``**kwargs`` typing. - - .. versionadded:: 3.11 - .. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False) Parameter specification variable. A specialized version of @@ -1550,20 +1565,93 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.10 -.. data:: AnyStr +Other special directives +"""""""""""""""""""""""" - ``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as - ``AnyStr = TypeVar('AnyStr', str, bytes)``. +These are not used in annotations. They are building blocks for declaring types. - It is meant to be used for functions that may accept any kind of string - without allowing different kinds of strings to mix. For example:: +.. class:: NamedTuple - def concat(a: AnyStr, b: AnyStr) -> AnyStr: - return a + b + Typed version of :func:`collections.namedtuple`. - concat(u"foo", u"bar") # Ok, output has type 'unicode' - concat(b"foo", b"bar") # Ok, output has type 'bytes' - concat(u"foo", b"bar") # Error, cannot mix unicode and bytes + Usage:: + + class Employee(NamedTuple): + name: str + id: int + + This is equivalent to:: + + Employee = collections.namedtuple('Employee', ['name', 'id']) + + To give a field a default value, you can assign to it in the class body:: + + class Employee(NamedTuple): + name: str + id: int = 3 + + employee = Employee('Guido') + assert employee.id == 3 + + Fields with a default value must come after any fields without a default. + + The resulting class has an extra attribute ``__annotations__`` giving a + dict that maps the field names to the field types. (The field names are in + the ``_fields`` attribute and the default values are in the + ``_field_defaults`` attribute, both of which are part of the :func:`~collections.namedtuple` + API.) + + ``NamedTuple`` subclasses can also have docstrings and methods:: + + class Employee(NamedTuple): + """Represents an employee.""" + name: str + id: int = 3 + + def __repr__(self) -> str: + return f'<Employee {self.name}, id={self.id}>' + + ``NamedTuple`` subclasses can be generic:: + + class Group(NamedTuple, Generic[T]): + key: T + group: list[T] + + Backward-compatible usage:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + + .. versionchanged:: 3.6 + Added support for :pep:`526` variable annotation syntax. + + .. versionchanged:: 3.6.1 + Added support for default values, methods, and docstrings. + + .. versionchanged:: 3.8 + The ``_field_types`` and ``__annotations__`` attributes are + now regular dictionaries instead of instances of ``OrderedDict``. + + .. versionchanged:: 3.9 + Removed the ``_field_types`` attribute in favor of the more + standard ``__annotations__`` attribute which has the same information. + + .. versionchanged:: 3.11 + Added support for generic namedtuples. + +.. class:: NewType(name, tp) + + A helper class to indicate a distinct type to a typechecker, + see :ref:`distinct`. At runtime it returns an object that returns + its argument when called. + Usage:: + + UserId = NewType('UserId', int) + first_user = UserId(1) + + .. versionadded:: 3.5.2 + + .. versionchanged:: 3.10 + ``NewType`` is now a class rather than a function. .. class:: Protocol(Generic) @@ -1659,94 +1747,6 @@ These are not used in annotations. They are building blocks for creating generic for more details. -Other special directives -"""""""""""""""""""""""" - -These are not used in annotations. They are building blocks for declaring types. - -.. class:: NamedTuple - - Typed version of :func:`collections.namedtuple`. - - Usage:: - - class Employee(NamedTuple): - name: str - id: int - - This is equivalent to:: - - Employee = collections.namedtuple('Employee', ['name', 'id']) - - To give a field a default value, you can assign to it in the class body:: - - class Employee(NamedTuple): - name: str - id: int = 3 - - employee = Employee('Guido') - assert employee.id == 3 - - Fields with a default value must come after any fields without a default. - - The resulting class has an extra attribute ``__annotations__`` giving a - dict that maps the field names to the field types. (The field names are in - the ``_fields`` attribute and the default values are in the - ``_field_defaults`` attribute, both of which are part of the :func:`~collections.namedtuple` - API.) - - ``NamedTuple`` subclasses can also have docstrings and methods:: - - class Employee(NamedTuple): - """Represents an employee.""" - name: str - id: int = 3 - - def __repr__(self) -> str: - return f'<Employee {self.name}, id={self.id}>' - - ``NamedTuple`` subclasses can be generic:: - - class Group(NamedTuple, Generic[T]): - key: T - group: list[T] - - Backward-compatible usage:: - - Employee = NamedTuple('Employee', [('name', str), ('id', int)]) - - .. versionchanged:: 3.6 - Added support for :pep:`526` variable annotation syntax. - - .. versionchanged:: 3.6.1 - Added support for default values, methods, and docstrings. - - .. versionchanged:: 3.8 - The ``_field_types`` and ``__annotations__`` attributes are - now regular dictionaries instead of instances of ``OrderedDict``. - - .. versionchanged:: 3.9 - Removed the ``_field_types`` attribute in favor of the more - standard ``__annotations__`` attribute which has the same information. - - .. versionchanged:: 3.11 - Added support for generic namedtuples. - -.. class:: NewType(name, tp) - - A helper class to indicate a distinct type to a typechecker, - see :ref:`distinct`. At runtime it returns an object that returns - its argument when called. - Usage:: - - UserId = NewType('UserId', int) - first_user = UserId(1) - - .. versionadded:: 3.5.2 - - .. versionchanged:: 3.10 - ``NewType`` is now a class rather than a function. - .. class:: TypedDict(dict) Special construct to add type hints to a dictionary. From webhook-mailer at python.org Sun May 21 09:31:32 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 21 May 2023 13:31:32 -0000 Subject: [Python-checkins] [3.11] typing docs: Move some classes out of the "Generics" section (GH-104707) (#104721) Message-ID: <mailman.500.1684675894.13550.python-checkins@python.org> https://github.com/python/cpython/commit/abb32de8c4e9541fbd0c6b14dc937193078e6955 commit: abb32de8c4e9541fbd0c6b14dc937193078e6955 branch: 3.11 author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-21T14:31:26+01:00 summary: [3.11] typing docs: Move some classes out of the "Generics" section (GH-104707) (#104721) - AnyStr can be used in type annotations, contrary to the section header - Unpack can also be used in annotations, and its use is not restricted to generics. It makes more sense with other building blocks like Required. - Protocol is not necessarily generic. Also fix the indentation for two notes associated with Concatenate. (cherry picked from commit ab71acd67b5b09926498b8c7f855bdb28ac0ec2f) --------- Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 443045469ad6..33cf1cb8fdfe 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -611,6 +611,21 @@ These can be used as types in annotations and do not support ``[]``. avoiding type checker errors with classes that can duck type anywhere or are highly dynamic. +.. data:: AnyStr + + ``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as + ``AnyStr = TypeVar('AnyStr', str, bytes)``. + + It is meant to be used for functions that may accept any kind of string + without allowing different kinds of strings to mix. For example:: + + def concat(a: AnyStr, b: AnyStr) -> AnyStr: + return a + b + + concat(u"foo", u"bar") # Ok, output has type 'unicode' + concat(b"foo", b"bar") # Ok, output has type 'bytes' + concat(u"foo", b"bar") # Error, cannot mix unicode and bytes + .. data:: LiteralString Special type that includes only literal strings. A string @@ -912,13 +927,13 @@ These can be used as types in annotations using ``[]``, each having a unique syn # We don't need to pass in the lock ourselves thanks to the decorator. sum_threadsafe([1.1, 2.2, 3.3]) -.. versionadded:: 3.10 + .. versionadded:: 3.10 -.. seealso:: + .. seealso:: - * :pep:`612` -- Parameter Specification Variables (the PEP which introduced - ``ParamSpec`` and ``Concatenate``). - * :class:`ParamSpec` and :class:`Callable`. + * :pep:`612` -- Parameter Specification Variables (the PEP which introduced + ``ParamSpec`` and ``Concatenate``). + * :class:`ParamSpec` and :class:`Callable`. .. class:: Type(Generic[CT_co]) @@ -1203,6 +1218,34 @@ These can be used as types in annotations using ``[]``, each having a unique syn .. versionadded:: 3.10 +.. data:: Unpack + + A typing operator that conceptually marks an object as having been + unpacked. For example, using the unpack operator ``*`` on a + :class:`type variable tuple <TypeVarTuple>` is equivalent to using ``Unpack`` + to mark the type variable tuple as having been unpacked:: + + Ts = TypeVarTuple('Ts') + tup: tuple[*Ts] + # Effectively does: + tup: tuple[Unpack[Ts]] + + In fact, ``Unpack`` can be used interchangeably with ``*`` in the context + of :class:`typing.TypeVarTuple <TypeVarTuple>` and + :class:`builtins.tuple <tuple>` types. You might see ``Unpack`` being used + explicitly in older versions of Python, where ``*`` couldn't be used in + certain places:: + + # In older versions of Python, TypeVarTuple and Unpack + # are located in the `typing_extensions` backports package. + from typing_extensions import TypeVarTuple, Unpack + + Ts = TypeVarTuple('Ts') + tup: tuple[*Ts] # Syntax error on Python <= 3.10! + tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible + + .. versionadded:: 3.11 + Building generic types """""""""""""""""""""" @@ -1404,32 +1447,6 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.11 -.. data:: Unpack - - A typing operator that conceptually marks an object as having been - unpacked. For example, using the unpack operator ``*`` on a - :class:`type variable tuple <TypeVarTuple>` is equivalent to using ``Unpack`` - to mark the type variable tuple as having been unpacked:: - - Ts = TypeVarTuple('Ts') - tup: tuple[*Ts] - # Effectively does: - tup: tuple[Unpack[Ts]] - - In fact, ``Unpack`` can be used interchangeably with ``*`` in the context - of types. You might see ``Unpack`` being used explicitly in older versions - of Python, where ``*`` couldn't be used in certain places:: - - # In older versions of Python, TypeVarTuple and Unpack - # are located in the `typing_extensions` backports package. - from typing_extensions import TypeVarTuple, Unpack - - Ts = TypeVarTuple('Ts') - tup: tuple[*Ts] # Syntax error on Python <= 3.10! - tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible - - .. versionadded:: 3.11 - .. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False) Parameter specification variable. A specialized version of @@ -1528,97 +1545,6 @@ These are not used in annotations. They are building blocks for creating generic .. versionadded:: 3.10 -.. data:: AnyStr - - ``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as - ``AnyStr = TypeVar('AnyStr', str, bytes)``. - - It is meant to be used for functions that may accept any kind of string - without allowing different kinds of strings to mix. For example:: - - def concat(a: AnyStr, b: AnyStr) -> AnyStr: - return a + b - - concat(u"foo", u"bar") # Ok, output has type 'unicode' - concat(b"foo", b"bar") # Ok, output has type 'bytes' - concat(u"foo", b"bar") # Error, cannot mix unicode and bytes - -.. class:: Protocol(Generic) - - Base class for protocol classes. Protocol classes are defined like this:: - - class Proto(Protocol): - def meth(self) -> int: - ... - - Such classes are primarily used with static type checkers that recognize - structural subtyping (static duck-typing), for example:: - - class C: - def meth(self) -> int: - return 0 - - def func(x: Proto) -> int: - return x.meth() - - func(C()) # Passes static type check - - See :pep:`544` for more details. Protocol classes decorated with - :func:`runtime_checkable` (described later) act as simple-minded runtime - protocols that check only the presence of given attributes, ignoring their - type signatures. - - Protocol classes can be generic, for example:: - - class GenProto(Protocol[T]): - def meth(self) -> T: - ... - - .. versionadded:: 3.8 - -.. decorator:: runtime_checkable - - Mark a protocol class as a runtime protocol. - - Such a protocol can be used with :func:`isinstance` and :func:`issubclass`. - This raises :exc:`TypeError` when applied to a non-protocol class. This - allows a simple-minded structural check, very similar to "one trick ponies" - in :mod:`collections.abc` such as :class:`~collections.abc.Iterable`. For example:: - - @runtime_checkable - class Closable(Protocol): - def close(self): ... - - assert isinstance(open('/some/file'), Closable) - - @runtime_checkable - class Named(Protocol): - name: str - - import threading - assert isinstance(threading.Thread(name='Bob'), Named) - - .. note:: - - :func:`!runtime_checkable` will check only the presence of the required - methods or attributes, not their type signatures or types. - For example, :class:`ssl.SSLObject` - is a class, therefore it passes an :func:`issubclass` - check against :data:`Callable`. However, the - ``ssl.SSLObject.__init__`` method exists only to raise a - :exc:`TypeError` with a more informative message, therefore making - it impossible to call (instantiate) :class:`ssl.SSLObject`. - - .. note:: - - An :func:`isinstance` check against a runtime-checkable protocol can be - surprisingly slow compared to an ``isinstance()`` check against - a non-protocol class. Consider using alternative idioms such as - :func:`hasattr` calls for structural checks in performance-sensitive - code. - - .. versionadded:: 3.8 - Other special directives """""""""""""""""""""""" @@ -1707,6 +1633,83 @@ These are not used in annotations. They are building blocks for declaring types. .. versionchanged:: 3.10 ``NewType`` is now a class rather than a function. +.. class:: Protocol(Generic) + + Base class for protocol classes. Protocol classes are defined like this:: + + class Proto(Protocol): + def meth(self) -> int: + ... + + Such classes are primarily used with static type checkers that recognize + structural subtyping (static duck-typing), for example:: + + class C: + def meth(self) -> int: + return 0 + + def func(x: Proto) -> int: + return x.meth() + + func(C()) # Passes static type check + + See :pep:`544` for more details. Protocol classes decorated with + :func:`runtime_checkable` (described later) act as simple-minded runtime + protocols that check only the presence of given attributes, ignoring their + type signatures. + + Protocol classes can be generic, for example:: + + class GenProto(Protocol[T]): + def meth(self) -> T: + ... + + .. versionadded:: 3.8 + +.. decorator:: runtime_checkable + + Mark a protocol class as a runtime protocol. + + Such a protocol can be used with :func:`isinstance` and :func:`issubclass`. + This raises :exc:`TypeError` when applied to a non-protocol class. This + allows a simple-minded structural check, very similar to "one trick ponies" + in :mod:`collections.abc` such as :class:`~collections.abc.Iterable`. For example:: + + @runtime_checkable + class Closable(Protocol): + def close(self): ... + + assert isinstance(open('/some/file'), Closable) + + @runtime_checkable + class Named(Protocol): + name: str + + import threading + assert isinstance(threading.Thread(name='Bob'), Named) + + .. note:: + + :func:`!runtime_checkable` will check only the presence of the required + methods or attributes, not their type signatures or types. + For example, :class:`ssl.SSLObject` + is a class, therefore it passes an :func:`issubclass` + check against :data:`Callable`. However, the + ``ssl.SSLObject.__init__`` method exists only to raise a + :exc:`TypeError` with a more informative message, therefore making + it impossible to call (instantiate) :class:`ssl.SSLObject`. + + .. note:: + + An :func:`isinstance` check against a runtime-checkable protocol can be + surprisingly slow compared to an ``isinstance()`` check against + a non-protocol class. Consider using alternative idioms such as + :func:`hasattr` calls for structural checks in performance-sensitive + code. + + .. versionadded:: 3.8 + + .. class:: TypedDict(dict) Special construct to add type hints to a dictionary. From webhook-mailer at python.org Sun May 21 09:45:56 2023 From: webhook-mailer at python.org (markshannon) Date: Sun, 21 May 2023 13:45:56 -0000 Subject: [Python-checkins] GH-101291: Add low level, unstable API for pylong (GH-101685) Message-ID: <mailman.501.1684676757.13550.python-checkins@python.org> https://github.com/python/cpython/commit/93923793f602ea9117f13bfac8cbe01a864eeb01 commit: 93923793f602ea9117f13bfac8cbe01a864eeb01 branch: main author: Mark Shannon <mark at hotpy.org> committer: markshannon <mark at hotpy.org> date: 2023-05-21T14:45:48+01:00 summary: GH-101291: Add low level, unstable API for pylong (GH-101685) Co-authored-by: Petr Viktorin <encukou at gmail.com> files: A Lib/test/test_capi/test_long.py A Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst M Doc/c-api/long.rst M Include/cpython/longintrepr.h M Include/cpython/longobject.h M Include/internal/pycore_long.h M Modules/_testcapi/long.c M Objects/longobject.c diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 4a71c89ad85d..5c1d026a330a 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -322,3 +322,27 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. with :c:func:`PyLong_FromVoidPtr`. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. + + +.. c:function:: int PyUnstable_Long_IsCompact(const PyLongObject* op) + + Return 1 if *op* is compact, 0 otherwise. + + This function makes it possible for performance-critical code to implement + a ?fast path? for small integers. For compact values use + :c:func:`PyUnstable_Long_CompactValue`; for others fall back to a + :c:func:`PyLong_As* <PyLong_AsSize_t>` function or + :c:func:`calling <PyObject_CallMethod>` :meth:`int.to_bytes`. + + The speedup is expected to be negligible for most users. + + Exactly what values are considered compact is an implementation detail + and is subject to change. + +.. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op) + + If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`, + return its value. + + Otherwise, the return value is undefined. + diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index c4cf820da5e4..0f569935fff1 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -98,6 +98,32 @@ PyAPI_FUNC(PyLongObject *) _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); +/* Inline some internals for speed. These should be in pycore_long.h + * if user code didn't need them inlined. */ + +#define _PyLong_SIGN_MASK 3 +#define _PyLong_NON_SIZE_BITS 3 + +static inline int +_PyLong_IsCompact(const PyLongObject* op) { + assert(PyLong_Check(op)); + return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); +} + +#define PyUnstable_Long_IsCompact _PyLong_IsCompact + +static inline Py_ssize_t +_PyLong_CompactValue(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(PyUnstable_Long_IsCompact(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); + return sign * (Py_ssize_t)op->long_value.ob_digit[0]; +} + +#define PyUnstable_Long_CompactValue _PyLong_CompactValue + + #ifdef __cplusplus } #endif diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h index 1a73799d658f..90cc0f267ae8 100644 --- a/Include/cpython/longobject.h +++ b/Include/cpython/longobject.h @@ -93,3 +93,8 @@ PyAPI_FUNC(PyObject *) _PyLong_GCD(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) _PyLong_Rshift(PyObject *, size_t); PyAPI_FUNC(PyObject *) _PyLong_Lshift(PyObject *, size_t); + + +PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op); +PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op); + diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index fe86581e81f6..64c00cb14754 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -118,6 +118,21 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( #define SIGN_NEGATIVE 2 #define NON_SIZE_BITS 3 +/* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined + * in Include/cpython/longobject.h, since they need to be inline. + * + * "Compact" values have at least one bit to spare, + * so that addition and subtraction can be performed on the values + * without risk of overflow. + * + * The inline functions need tag bits. + * For readability, rather than do `#define SIGN_MASK _PyLong_SIGN_MASK` + * we define them to the numbers in both places and then assert that + * they're the same. + */ +static_assert(SIGN_MASK == _PyLong_SIGN_MASK, "SIGN_MASK does not match _PyLong_SIGN_MASK"); +static_assert(NON_SIZE_BITS == _PyLong_NON_SIZE_BITS, "NON_SIZE_BITS does not match _PyLong_NON_SIZE_BITS"); + /* All *compact" values are guaranteed to fit into * a Py_ssize_t with at least one bit to spare. * In other words, for 64 bit machines, compact @@ -131,11 +146,6 @@ _PyLong_IsNonNegativeCompact(const PyLongObject* op) { return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); } -static inline int -_PyLong_IsCompact(const PyLongObject* op) { - assert(PyLong_Check(op)); - return op->long_value.lv_tag < (2 << NON_SIZE_BITS); -} static inline int _PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { @@ -144,21 +154,6 @@ _PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); } -/* Returns a *compact* value, iff `_PyLong_IsCompact` is true for `op`. - * - * "Compact" values have at least one bit to spare, - * so that addition and subtraction can be performed on the values - * without risk of overflow. - */ -static inline Py_ssize_t -_PyLong_CompactValue(const PyLongObject *op) -{ - assert(PyLong_Check(op)); - assert(_PyLong_IsCompact(op)); - Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); - return sign * (Py_ssize_t)op->long_value.ob_digit[0]; -} - static inline bool _PyLong_IsZero(const PyLongObject *op) { diff --git a/Lib/test/test_capi/test_long.py b/Lib/test/test_capi/test_long.py new file mode 100644 index 000000000000..8928fd94a1d6 --- /dev/null +++ b/Lib/test/test_capi/test_long.py @@ -0,0 +1,39 @@ +import unittest +import sys + +from test.support import import_helper + +# Skip this test if the _testcapi module isn't available. +_testcapi = import_helper.import_module('_testcapi') + + +class LongTests(unittest.TestCase): + + def test_compact(self): + for n in { + # Edge cases + *(2**n for n in range(66)), + *(-2**n for n in range(66)), + *(2**n - 1 for n in range(66)), + *(-2**n + 1 for n in range(66)), + # Essentially random + *(37**n for n in range(14)), + *(-37**n for n in range(14)), + }: + with self.subTest(n=n): + is_compact, value = _testcapi.call_long_compact_api(n) + if is_compact: + self.assertEqual(n, value) + + def test_compact_known(self): + # Sanity-check some implementation details (we don't guarantee + # that these are/aren't compact) + self.assertEqual(_testcapi.call_long_compact_api(-1), (True, -1)) + self.assertEqual(_testcapi.call_long_compact_api(0), (True, 0)) + self.assertEqual(_testcapi.call_long_compact_api(256), (True, 256)) + self.assertEqual(_testcapi.call_long_compact_api(sys.maxsize), + (False, -1)) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst b/Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst new file mode 100644 index 000000000000..465af3b209a0 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst @@ -0,0 +1,3 @@ +Added unstable C API for extracting the value of "compact" integers: +:c:func:`PyUnstable_Long_IsCompact` and +:c:func:`PyUnstable_Long_CompactValue`. diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 1be8de5e5762..61dd96596dad 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -534,6 +534,18 @@ test_long_numbits(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } +static PyObject * +check_long_compact_api(PyObject *self, PyObject *arg) +{ + assert(PyLong_Check(arg)); + int is_compact = PyUnstable_Long_IsCompact((PyLongObject*)arg); + Py_ssize_t value = -1; + if (is_compact) { + value = PyUnstable_Long_CompactValue((PyLongObject*)arg); + } + return Py_BuildValue("in", is_compact, value); +} + static PyMethodDef test_methods[] = { {"test_long_and_overflow", test_long_and_overflow, METH_NOARGS}, {"test_long_api", test_long_api, METH_NOARGS}, @@ -543,6 +555,7 @@ static PyMethodDef test_methods[] = { {"test_long_long_and_overflow",test_long_long_and_overflow, METH_NOARGS}, {"test_long_numbits", test_long_numbits, METH_NOARGS}, {"test_longlong_api", test_longlong_api, METH_NOARGS}, + {"call_long_compact_api", check_long_compact_api, METH_O}, {NULL}, }; diff --git a/Objects/longobject.c b/Objects/longobject.c index 853e934e2107..5fca55e5c3a2 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6366,3 +6366,17 @@ _PyLong_FiniTypes(PyInterpreterState *interp) { _PyStructSequence_FiniBuiltin(interp, &Int_InfoType); } + +#undef PyUnstable_Long_IsCompact + +int +PyUnstable_Long_IsCompact(const PyLongObject* op) { + return _PyLong_IsCompact(op); +} + +#undef PyUnstable_Long_CompactValue + +Py_ssize_t +PyUnstable_Long_CompactValue(const PyLongObject* op) { + return _PyLong_CompactValue(op); +} From webhook-mailer at python.org Sun May 21 12:07:35 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 21 May 2023 16:07:35 -0000 Subject: [Python-checkins] gh-104719: Restore Tokenize module constants (#104722) Message-ID: <mailman.502.1684685256.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ffe47cb623999db05959ec4b5168d1c87a1e40ef commit: ffe47cb623999db05959ec4b5168d1c87a1e40ef branch: main author: Marta G?mez Mac?as <mgmacias at google.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-21T17:07:28+01:00 summary: gh-104719: Restore Tokenize module constants (#104722) files: M Lib/tokenize.py diff --git a/Lib/tokenize.py b/Lib/tokenize.py index bfe40c627fde..cef2773feac2 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -56,6 +56,107 @@ def exact_type(self): else: return self.type +def group(*choices): return '(' + '|'.join(choices) + ')' +def any(*choices): return group(*choices) + '*' +def maybe(*choices): return group(*choices) + '?' + +# Note: we use unicode matching for names ("\w") but ascii matching for +# number literals. +Whitespace = r'[ \f\t]*' +Comment = r'#[^\r\n]*' +Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) +Name = r'\w+' + +Hexnumber = r'0[xX](?:_?[0-9a-fA-F])+' +Binnumber = r'0[bB](?:_?[01])+' +Octnumber = r'0[oO](?:_?[0-7])+' +Decnumber = r'(?:0(?:_?0)*|[1-9](?:_?[0-9])*)' +Intnumber = group(Hexnumber, Binnumber, Octnumber, Decnumber) +Exponent = r'[eE][-+]?[0-9](?:_?[0-9])*' +Pointfloat = group(r'[0-9](?:_?[0-9])*\.(?:[0-9](?:_?[0-9])*)?', + r'\.[0-9](?:_?[0-9])*') + maybe(Exponent) +Expfloat = r'[0-9](?:_?[0-9])*' + Exponent +Floatnumber = group(Pointfloat, Expfloat) +Imagnumber = group(r'[0-9](?:_?[0-9])*[jJ]', Floatnumber + r'[jJ]') +Number = group(Imagnumber, Floatnumber, Intnumber) + +# Return the empty string, plus all of the valid string prefixes. +def _all_string_prefixes(): + # The valid string prefixes. Only contain the lower case versions, + # and don't contain any permutations (include 'fr', but not + # 'rf'). The various permutations will be generated. + _valid_string_prefixes = ['b', 'r', 'u', 'f', 'br', 'fr'] + # if we add binary f-strings, add: ['fb', 'fbr'] + result = {''} + for prefix in _valid_string_prefixes: + for t in _itertools.permutations(prefix): + # create a list with upper and lower versions of each + # character + for u in _itertools.product(*[(c, c.upper()) for c in t]): + result.add(''.join(u)) + return result + + at functools.lru_cache +def _compile(expr): + return re.compile(expr, re.UNICODE) + +# Note that since _all_string_prefixes includes the empty string, +# StringPrefix can be the empty string (making it optional). +StringPrefix = group(*_all_string_prefixes()) + +# Tail end of ' string. +Single = r"[^'\\]*(?:\\.[^'\\]*)*'" +# Tail end of " string. +Double = r'[^"\\]*(?:\\.[^"\\]*)*"' +# Tail end of ''' string. +Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" +# Tail end of """ string. +Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' +Triple = group(StringPrefix + "'''", StringPrefix + '"""') +# Single-line ' or " string. +String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') + +# Sorting in reverse order puts the long operators before their prefixes. +# Otherwise if = came before ==, == would get recognized as two instances +# of =. +Special = group(*map(re.escape, sorted(EXACT_TOKEN_TYPES, reverse=True))) +Funny = group(r'\r?\n', Special) + +PlainToken = group(Number, Funny, String, Name) +Token = Ignore + PlainToken + +# First (or only) line of ' or " string. +ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + + group("'", r'\\\r?\n'), + StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + + group('"', r'\\\r?\n')) +PseudoExtras = group(r'\\\r?\n|\Z', Comment, Triple) +PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) + +# For a given string prefix plus quotes, endpats maps it to a regex +# to match the remainder of that string. _prefix can be empty, for +# a normal single or triple quoted string (with no prefix). +endpats = {} +for _prefix in _all_string_prefixes(): + endpats[_prefix + "'"] = Single + endpats[_prefix + '"'] = Double + endpats[_prefix + "'''"] = Single3 + endpats[_prefix + '"""'] = Double3 +del _prefix + +# A set of all of the single and triple quoted string prefixes, +# including the opening quotes. +single_quoted = set() +triple_quoted = set() +for t in _all_string_prefixes(): + for u in (t + '"', t + "'"): + single_quoted.add(u) + for u in (t + '"""', t + "'''"): + triple_quoted.add(u) +del t, u + +tabsize = 8 class TokenError(Exception): pass From webhook-mailer at python.org Sun May 21 14:42:33 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 21 May 2023 18:42:33 -0000 Subject: [Python-checkins] gh-104719: IDLE - delete useless monkeypatch of tokenize (#104726) Message-ID: <mailman.503.1684694554.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0c5e79bcdf99a6a07c65b0ea6d7701b6e041481c commit: 0c5e79bcdf99a6a07c65b0ea6d7701b6e041481c branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-21T18:42:26Z summary: gh-104719: IDLE - delete useless monkeypatch of tokenize (#104726) files: M Lib/idlelib/editor.py diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 21402ad71391..df36be876601 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1643,19 +1643,13 @@ def tokeneater(self, type, token, start, end, line, self.finished = 1 def run(self): - save_tabsize = tokenize.tabsize - tokenize.tabsize = self.tabwidth try: - try: - tokens = tokenize.generate_tokens(self.readline) - for token in tokens: - self.tokeneater(*token) - except (tokenize.TokenError, SyntaxError): - # since we cut off the tokenizer early, we can trigger - # spurious errors - pass - finally: - tokenize.tabsize = save_tabsize + tokens = tokenize.generate_tokens(self.readline) + for token in tokens: + self.tokeneater(*token) + except (tokenize.TokenError, SyntaxError): + # Stopping the tokenizer early can trigger spurious errors. + pass return self.blkopenline, self.indentedline ### end autoindent code ### From webhook-mailer at python.org Sun May 21 15:16:23 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 21 May 2023 19:16:23 -0000 Subject: [Python-checkins] [3.11] gh-104719: IDLE - delete useless monkeypatch of tokenize (GH-104726) (#104727) Message-ID: <mailman.504.1684696584.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e033edab12986a9848d883a147c2a929760c7e9b commit: e033edab12986a9848d883a147c2a929760c7e9b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-21T19:16:12Z summary: [3.11] gh-104719: IDLE - delete useless monkeypatch of tokenize (GH-104726) (#104727) gh-104719: IDLE - delete useless monkeypatch of tokenize (GH-104726) (cherry picked from commit 0c5e79bcdf99a6a07c65b0ea6d7701b6e041481c) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> files: M Lib/idlelib/editor.py diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 21402ad71391..df36be876601 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1643,19 +1643,13 @@ def tokeneater(self, type, token, start, end, line, self.finished = 1 def run(self): - save_tabsize = tokenize.tabsize - tokenize.tabsize = self.tabwidth try: - try: - tokens = tokenize.generate_tokens(self.readline) - for token in tokens: - self.tokeneater(*token) - except (tokenize.TokenError, SyntaxError): - # since we cut off the tokenizer early, we can trigger - # spurious errors - pass - finally: - tokenize.tabsize = save_tabsize + tokens = tokenize.generate_tokens(self.readline) + for token in tokens: + self.tokeneater(*token) + except (tokenize.TokenError, SyntaxError): + # Stopping the tokenizer early can trigger spurious errors. + pass return self.blkopenline, self.indentedline ### end autoindent code ### From webhook-mailer at python.org Sun May 21 15:17:24 2023 From: webhook-mailer at python.org (gpshead) Date: Sun, 21 May 2023 19:17:24 -0000 Subject: [Python-checkins] [3.11] gh-103606: Improve error message from logging.config.FileConfig (GH-103628) (#104687) Message-ID: <mailman.505.1684696645.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2ade563abc95281be595b6dc58a519e84b74d6e0 commit: 2ade563abc95281be595b6dc58a519e84b74d6e0 branch: 3.11 author: Prince Roshan <princekrroshan01 at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-21T12:17:18-07:00 summary: [3.11] gh-103606: Improve error message from logging.config.FileConfig (GH-103628) (#104687) * gh-103606: Improve error message from logging.config.FileConfig (GH-103628) (cherry picked from commit 152227b569c3a9b87fe0483706f704762ced6d75) plus backport the followup exception change fix to that in #104701 files: 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 45dc975db474..619e04060668 100644 --- a/Doc/library/logging.config.rst +++ b/Doc/library/logging.config.rst @@ -87,6 +87,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in provides a mechanism to present the choices and load the chosen configuration). + It will raise :exc:`FileNotFoundError` if the file + doesn't exist and :exc:`RuntimeError` if the file is invalid or + empty. + :param fname: A filename, or a file-like object, or an instance derived from :class:`~configparser.RawConfigParser`. If a ``RawConfigParser``-derived instance is passed, it is used as @@ -126,6 +130,10 @@ in :mod:`logging` itself) and defining handlers which are declared either in .. versionadded:: 3.10 The *encoding* parameter is added. + .. versionchanged:: 3.11.4 + An exception will be thrown if the provided file + doesn't exist or is invalid or empty. + .. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT, verify=None) Starts up a socket server on the specified port, and listens for new diff --git a/Lib/logging/config.py b/Lib/logging/config.py index f9ef7b53a3d6..7e78a64a2f08 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -28,6 +28,8 @@ import io import logging import logging.handlers +import os +import queue import re import struct import threading @@ -58,15 +60,24 @@ def fileConfig(fname, defaults=None, disable_existing_loggers=True, encoding=Non """ import configparser + if isinstance(fname, str): + if not os.path.exists(fname): + raise FileNotFoundError(f"{fname} doesn't exist") + elif not os.path.getsize(fname): + raise RuntimeError(f'{fname} is an empty file') + if isinstance(fname, configparser.RawConfigParser): cp = fname else: - cp = configparser.ConfigParser(defaults) - if hasattr(fname, 'readline'): - cp.read_file(fname) - else: - encoding = io.text_encoding(encoding) - cp.read(fname, encoding=encoding) + try: + cp = configparser.ConfigParser(defaults) + if hasattr(fname, 'readline'): + cp.read_file(fname) + else: + encoding = io.text_encoding(encoding) + cp.read(fname, encoding=encoding) + except configparser.ParsingError as e: + raise RuntimeError(f'{fname} is invalid: {e}') formatters = _create_formatters(cp) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 350f4a57e2bb..76bd8724e29b 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -1645,6 +1645,42 @@ def test_config_set_handler_names(self): self.apply_config(test_config) self.assertEqual(logging.getLogger().handlers[0].name, 'hand1') + def test_exception_if_confg_file_is_invalid(self): + test_config = """ + [loggers] + keys=root + + [handlers] + keys=hand1 + + [formatters] + keys=form1 + + [logger_root] + handlers=hand1 + + [handler_hand1] + class=StreamHandler + formatter=form1 + + [formatter_form1] + format=%(levelname)s ++ %(message)s + + prince + """ + + file = io.StringIO(textwrap.dedent(test_config)) + self.assertRaises(RuntimeError, logging.config.fileConfig, file) + + def test_exception_if_confg_file_is_empty(self): + fd, fn = tempfile.mkstemp(prefix='test_empty_', suffix='.ini') + os.close(fd) + self.assertRaises(RuntimeError, logging.config.fileConfig, fn) + os.remove(fn) + + def test_exception_if_config_file_does_not_exist(self): + self.assertRaises(FileNotFoundError, logging.config.fileConfig, 'filenotfound') + def test_defaults_do_no_interpolation(self): """bpo-33802 defaults should not get interpolated""" ini = textwrap.dedent(""" From webhook-mailer at python.org Sun May 21 15:45:51 2023 From: webhook-mailer at python.org (hugovk) Date: Sun, 21 May 2023 19:45:51 -0000 Subject: [Python-checkins] gh-103857: Document utcnow and utcfromtimestamp deprecations in What's New (#104542) Message-ID: <mailman.506.1684698351.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5841fbc1a2aa5dd9e1c3d8d369f2bba8a99b285b commit: 5841fbc1a2aa5dd9e1c3d8d369f2bba8a99b285b branch: main author: Hugo van Kemenade <hugovk at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-21T13:45:44-06:00 summary: gh-103857: Document utcnow and utcfromtimestamp deprecations in What's New (#104542) Co-authored-by: Paul Ganssle <1377457+pganssle at users.noreply.github.com> files: M Doc/whatsnew/3.12.rst M Modules/_datetimemodule.c diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8a0a59ba7301..14f03ef755c7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -774,6 +774,16 @@ Deprecated ``int``, convert to int explicitly with ``~int(x)``. (Contributed by Tim Hoffmann in :gh:`103487`.) +* :class:`datetime.datetime`'s + :meth:`~datetime.datetime.utcnow` and + :meth:`~datetime.datetime.utcfromtimestamp` are deprecated and will be + removed in a future version. Instead, use timezone-aware objects to represent + datetimes in UTC: respectively, call + :meth:`~datetime.datetime.now` and + :meth:`~datetime.datetime.fromtimestamp` with the *tz* parameter set to + :attr:`datetime.UTC`. + (Contributed by Paul Ganssle in :gh:`103857`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8b417bdd0fb5..19e11780ec6e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -5190,7 +5190,7 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) if (PyErr_WarnEx(PyExc_DeprecationWarning, "datetime.utcfromtimestamp() is deprecated and scheduled for removal " "in a future version. Use timezone-aware objects to represent " - "datetimes in UTC: datetime.now(datetime.UTC).", 1)) + "datetimes in UTC: datetime.fromtimestamp(timestamp, datetime.UTC).", 1)) { return NULL; } From webhook-mailer at python.org Sun May 21 16:23:20 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 21 May 2023 20:23:20 -0000 Subject: [Python-checkins] gh-104050: Annotate Argument Clinic return converters (#104706) Message-ID: <mailman.507.1684700601.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c482e9a4e6f9c0b88ea248c4a0e0aa97223b5233 commit: c482e9a4e6f9c0b88ea248c4a0e0aa97223b5233 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-21T20:23:14Z summary: gh-104050: Annotate Argument Clinic return converters (#104706) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 863bd66bef75..a1e8947529a0 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1966,15 +1966,6 @@ def dump(self): extensions['py'] = PythonLanguage -# maps strings to callables. -# these callables must be of the form: -# def foo(*, ...) -# The callable may have any number of keyword-only parameters. -# The callable must return a CConverter object. -# The callable should not call builtins.print. -return_converters = {} - - def file_changed(filename: str, new_contents: str) -> bool: """Return true if file contents changed (meaning we must update it)""" try: @@ -3005,6 +2996,16 @@ def parser_name(self): # note however that they will never be called with keyword-only parameters. legacy_converters: ConverterDict = {} +# maps strings to callables. +# these callables must be of the form: +# def foo(*, ...) +# The callable may have any number of keyword-only parameters. +# The callable must return a CReturnConverter object. +# The callable should not call builtins.print. +ReturnConverterType = Callable[..., "CReturnConverter"] +ReturnConverterDict = dict[str, ReturnConverterType] +return_converters: ReturnConverterDict = {} + TypeSet = set[bltns.type[Any]] @@ -3966,8 +3967,10 @@ def set_template_dict(self, template_dict): template_dict['base_type_ptr'] = type_ptr - -def add_c_return_converter(f, name=None): +def add_c_return_converter( + f: ReturnConverterType, + name: str | None = None +) -> ReturnConverterType: if not name: name = f.__name__ if not name.endswith('_return_converter'): @@ -3978,9 +3981,15 @@ def add_c_return_converter(f, name=None): class CReturnConverterAutoRegister(type): - def __init__(cls, name, bases, classdict): + def __init__( + cls: ReturnConverterType, + name: str, + bases: tuple[type, ...], + classdict: dict[str, Any] + ) -> None: add_c_return_converter(cls) + class CReturnConverter(metaclass=CReturnConverterAutoRegister): # The C type to use for this variable. @@ -3992,7 +4001,12 @@ class CReturnConverter(metaclass=CReturnConverterAutoRegister): # Or the magic value "unspecified" if there is no default. default: object = None - def __init__(self, *, py_default=None, **kwargs): + def __init__( + self, + *, + py_default: str | None = None, + **kwargs + ) -> None: self.py_default = py_default try: self.return_converter_init(**kwargs) @@ -4000,11 +4014,10 @@ def __init__(self, *, py_default=None, **kwargs): s = ', '.join(name + '=' + repr(value) for name, value in kwargs.items()) sys.exit(self.__class__.__name__ + '(' + s + ')\n' + str(e)) - def return_converter_init(self): - pass + def return_converter_init(self) -> None: ... - def declare(self, data): - line = [] + def declare(self, data: CRenderData) -> None: + line: list[str] = [] add = line.append add(self.type) if not self.type.endswith('*'): @@ -4013,50 +4026,70 @@ def declare(self, data): data.declarations.append(''.join(line)) data.return_value = data.converter_retval - def err_occurred_if(self, expr, data): + def err_occurred_if( + self, + expr: str, + data: CRenderData + ) -> None: line = f'if (({expr}) && PyErr_Occurred()) {{\n goto exit;\n}}\n' data.return_conversion.append(line) - def err_occurred_if_null_pointer(self, variable, data): + def err_occurred_if_null_pointer( + self, + variable: str, + data: CRenderData + ) -> None: line = f'if ({variable} == NULL) {{\n goto exit;\n}}\n' data.return_conversion.append(line) - def render(self, function, data): - """ - function is a clinic.Function instance. - data is a CRenderData instance. - """ - pass + def render( + self, + function: Function, + data: CRenderData + ) -> None: ... + add_c_return_converter(CReturnConverter, 'object') + class bool_return_converter(CReturnConverter): type = 'int' - def render(self, function, data): + def render( + self, + function: Function, + data: CRenderData + ) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == -1", data) data.return_conversion.append( f'return_value = PyBool_FromLong((long){data.converter_retval});\n' ) + class long_return_converter(CReturnConverter): type = 'long' conversion_fn = 'PyLong_FromLong' cast = '' unsigned_cast = '' - def render(self, function, data): + def render( + self, + function: Function, + data: CRenderData + ) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data) data.return_conversion.append( f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n' ) + class int_return_converter(long_return_converter): type = 'int' cast = '(long)' + class init_return_converter(long_return_converter): """ Special return converter for __init__ functions. @@ -4064,23 +4097,30 @@ class init_return_converter(long_return_converter): type = 'int' cast = '(long)' - def render(self, function, data): - pass + def render( + self, + function: Function, + data: CRenderData + ) -> None: ... + class unsigned_long_return_converter(long_return_converter): type = 'unsigned long' conversion_fn = 'PyLong_FromUnsignedLong' unsigned_cast = '(unsigned long)' + class unsigned_int_return_converter(unsigned_long_return_converter): type = 'unsigned int' cast = '(unsigned long)' unsigned_cast = '(unsigned int)' + class Py_ssize_t_return_converter(long_return_converter): type = 'Py_ssize_t' conversion_fn = 'PyLong_FromSsize_t' + class size_t_return_converter(long_return_converter): type = 'size_t' conversion_fn = 'PyLong_FromSize_t' @@ -4091,13 +4131,18 @@ class double_return_converter(CReturnConverter): type = 'double' cast = '' - def render(self, function, data): + def render( + self, + function: Function, + data: CRenderData + ) -> None: self.declare(data) self.err_occurred_if(f"{data.converter_retval} == -1.0", data) data.return_conversion.append( f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n' ) + class float_return_converter(double_return_converter): type = 'float' cast = '(double)' From webhook-mailer at python.org Sun May 21 16:49:40 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 21 May 2023 20:49:40 -0000 Subject: [Python-checkins] gh-104050: Add basic type hints to Argument Clinic clinic class (#104705) Message-ID: <mailman.508.1684702182.13550.python-checkins@python.org> https://github.com/python/cpython/commit/bf6dd8f5fd98a1833646eb22269cad076836ebba commit: bf6dd8f5fd98a1833646eb22269cad076836ebba branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-21T20:49:34Z summary: gh-104050: Add basic type hints to Argument Clinic clinic class (#104705) Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index a1e8947529a0..513586ee0191 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1989,6 +1989,11 @@ def write_file(filename: str, new_contents: str): raise +ClassDict = dict[str, "Class"] +DestinationDict = dict[str, Destination] +ModuleDict = dict[str, "Module"] +ParserDict = dict[str, "DSLParser"] + clinic = None class Clinic: @@ -2035,23 +2040,30 @@ class Clinic: """ - def __init__(self, language, printer=None, *, verify=True, filename=None): + def __init__( + self, + language: CLanguage, + printer: BlockPrinter | None = None, + *, + verify: bool = True, + filename: str | None = None + ) -> None: # maps strings to Parser objects. # (instantiated from the "parsers" global.) - self.parsers = {} - self.language = language + self.parsers: ParserDict = {} + self.language: CLanguage = language if printer: fail("Custom printers are broken right now") self.printer = printer or BlockPrinter(language) self.verify = verify self.filename = filename - self.modules = {} - self.classes = {} - self.functions = [] + self.modules: ModuleDict = {} + self.classes: ClassDict = {} + self.functions: list[Function] = [] self.line_prefix = self.line_suffix = '' - self.destinations = {} + self.destinations: DestinationDict = {} self.add_destination("block", "buffer") self.add_destination("suppress", "suppress") self.add_destination("buffer", "buffer") @@ -2072,10 +2084,13 @@ def __init__(self, language, printer=None, *, verify=True, filename=None): 'impl_definition': d('block'), } - self.destination_buffers_stack = [] - self.ifndef_symbols = set() + DestBufferType = dict[str, Callable[..., Any]] + DestBufferList = list[DestBufferType] + + self.destination_buffers_stack: DestBufferList = [] + self.ifndef_symbols: set[str] = set() - self.presets = {} + self.presets: dict[str, dict[Any, Any]] = {} preset = None for line in self.presets_text.strip().split('\n'): line = line.strip() @@ -2103,18 +2118,27 @@ def __init__(self, language, printer=None, *, verify=True, filename=None): global clinic clinic = self - def add_destination(self, name, type, *args): + def add_destination( + self, + name: str, + type: str, + *args + ) -> None: if name in self.destinations: fail("Destination already exists: " + repr(name)) self.destinations[name] = Destination(name, type, self, *args) - def get_destination(self, name): + def get_destination(self, name: str) -> Destination: d = self.destinations.get(name) if not d: fail("Destination does not exist: " + repr(name)) return d - def get_destination_buffer(self, name, item=0): + def get_destination_buffer( + self, + name: str, + item: int = 0 + ): d = self.get_destination(name) return d.buffers[item] @@ -2240,6 +2264,7 @@ def parse_file( if not find_start_re.search(raw): return + assert isinstance(language, CLanguage) clinic = Clinic(language, verify=verify, filename=filename) src_out, clinic_out = clinic.parse(raw) @@ -2275,8 +2300,6 @@ def parse(self, block: Block) -> None: block.output = s.getvalue() -ModuleDict = dict[str, "Module"] - class Module: def __init__( self, @@ -2294,8 +2317,6 @@ def __repr__(self) -> str: return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">" -ClassDict = dict[str, "Class"] - class Class: def __init__( self, From webhook-mailer at python.org Sun May 21 17:24:33 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Sun, 21 May 2023 21:24:33 -0000 Subject: [Python-checkins] gh-104050: Add more type annotations to Argument Clinic (#104631) Message-ID: <mailman.509.1684704274.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6ba8406cb6e656e47e908f8c7354e07ed0f2d774 commit: 6ba8406cb6e656e47e908f8c7354e07ed0f2d774 branch: main author: Erlend E. Aasland <erlend.aasland at protonmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-21T21:24:26Z summary: gh-104050: Add more type annotations to Argument Clinic (#104631) Annotate methods of the following classes: - class Function - class Parameter - class LandMine files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 513586ee0191..1d7b778da709 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2416,6 +2416,9 @@ def __repr__(self) -> str: INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW """.replace(",", "").strip().split() +ParamDict = dict[str, "Parameter"] +ReturnConverterType = Callable[..., "CReturnConverter"] + class Function: """ Mutable duck type for inspect.Function. @@ -2428,12 +2431,22 @@ class Function: (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) """ - def __init__(self, parameters=None, *, name, - module, cls=None, c_basename=None, - full_name=None, - return_converter, return_annotation=inspect.Signature.empty, - docstring=None, kind=CALLABLE, coexist=False, - docstring_only=False): + def __init__( + self, + parameters: ParamDict | None = None, + *, + name: str, + module: Module, + cls: Class | None = None, + c_basename: str | None = None, + full_name: str | None = None, + return_converter: ReturnConverterType, + return_annotation = inspect.Signature.empty, + docstring: str | None = None, + kind: str = CALLABLE, + coexist: bool = False, + docstring_only: bool = False + ) -> None: self.parameters = parameters or {} self.return_annotation = return_annotation self.name = name @@ -2467,7 +2480,7 @@ def render_parameters(self): return self.__render_parameters__ @property - def methoddef_flags(self): + def methoddef_flags(self) -> str | None: if self.kind in (METHOD_INIT, METHOD_NEW): return None flags = [] @@ -2481,10 +2494,10 @@ def methoddef_flags(self): flags.append('METH_COEXIST') return '|'.join(flags) - def __repr__(self): + def __repr__(self) -> str: return '<clinic.Function ' + self.name + '>' - def copy(self, **overrides): + def copy(self, **overrides) -> "Function": kwargs = { 'name': self.name, 'module': self.module, 'parameters': self.parameters, 'cls': self.cls, 'c_basename': self.c_basename, @@ -2507,9 +2520,18 @@ class Parameter: Mutable duck type of inspect.Parameter. """ - def __init__(self, name, kind, *, default=inspect.Parameter.empty, - function, converter, annotation=inspect.Parameter.empty, - docstring=None, group=0): + def __init__( + self, + name: str, + kind: str, + *, + default = inspect.Parameter.empty, + function: Function, + converter: "CConverter", + annotation = inspect.Parameter.empty, + docstring: str | None = None, + group: int = 0 + ) -> None: self.name = name self.kind = kind self.default = default @@ -2519,22 +2541,22 @@ def __init__(self, name, kind, *, default=inspect.Parameter.empty, self.docstring = docstring or '' self.group = group - def __repr__(self): + def __repr__(self) -> str: return '<clinic.Parameter ' + self.name + '>' - def is_keyword_only(self): + def is_keyword_only(self) -> bool: return self.kind == inspect.Parameter.KEYWORD_ONLY - def is_positional_only(self): + def is_positional_only(self) -> bool: return self.kind == inspect.Parameter.POSITIONAL_ONLY - def is_vararg(self): + def is_vararg(self) -> bool: return self.kind == inspect.Parameter.VAR_POSITIONAL - def is_optional(self): + def is_optional(self) -> bool: return not self.is_vararg() and (self.default is not unspecified) - def copy(self, **overrides): + def copy(self, **overrides) -> "Parameter": kwargs = { 'name': self.name, 'kind': self.kind, 'default':self.default, 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, @@ -2547,7 +2569,7 @@ def copy(self, **overrides): kwargs['converter'] = converter return Parameter(**kwargs) - def get_displayname(self, i): + def get_displayname(self, i: int) -> str: if i == 0: return '"argument"' if not self.is_positional_only(): @@ -2558,13 +2580,13 @@ def get_displayname(self, i): class LandMine: # try to access any - def __init__(self, message): + def __init__(self, message: str) -> None: self.__message__ = message - def __repr__(self): + def __repr__(self) -> str: return '<LandMine ' + repr(self.__message__) + ">" - def __getattribute__(self, name): + def __getattribute__(self, name: str): if name in ('__repr__', '__message__'): return super().__getattribute__(name) # raise RuntimeError(repr(name)) @@ -3023,7 +3045,6 @@ def parser_name(self): # The callable may have any number of keyword-only parameters. # The callable must return a CReturnConverter object. # The callable should not call builtins.print. -ReturnConverterType = Callable[..., "CReturnConverter"] ReturnConverterDict = dict[str, ReturnConverterType] return_converters: ReturnConverterDict = {} From webhook-mailer at python.org Sun May 21 17:32:46 2023 From: webhook-mailer at python.org (serhiy-storchaka) Date: Sun, 21 May 2023 21:32:46 -0000 Subject: [Python-checkins] gh-98836: Extend PyUnicode_FromFormat() (GH-98838) Message-ID: <mailman.510.1684704767.13550.python-checkins@python.org> https://github.com/python/cpython/commit/f3466bc04008660c4a5c3ed6f70144f138ae2e7f commit: f3466bc04008660c4a5c3ed6f70144f138ae2e7f branch: main author: Serhiy Storchaka <storchaka at gmail.com> committer: serhiy-storchaka <storchaka at gmail.com> date: 2023-05-22T00:32:39+03:00 summary: gh-98836: Extend PyUnicode_FromFormat() (GH-98838) * Support for conversion specifiers o (octal) and X (uppercase hexadecimal). * Support for length modifiers j (intmax_t) and t (ptrdiff_t). * Length modifiers are now applied to all integer conversions. * Support for wchar_t C strings (%ls and %lV). * Support for variable width and precision (*). * Support for flag - (left alignment). files: A Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst M Doc/c-api/unicode.rst M Doc/whatsnew/3.12.rst M Lib/test/test_capi/test_unicode.py M Modules/_ssl.c M Modules/_testcapi/unicode.c M Modules/selectmodule.c M Modules/socketmodule.c M Objects/unicodeobject.c M Parser/tokenizer.c diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index ab3a2e274d93..6771f378bfbc 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -394,98 +394,149 @@ APIs: arguments, calculate the size of the resulting Python Unicode string and return a string with the values formatted into it. The variable arguments must be C types and must correspond exactly to the format characters in the *format* - ASCII-encoded string. The following format characters are allowed: - - .. % This should be exactly the same as the table in PyErr_Format. - - .. tabularcolumns:: |l|l|L| - - +-------------------+---------------------+----------------------------------+ - | Format Characters | Type | Comment | - +===================+=====================+==================================+ - | :attr:`%%` | *n/a* | The literal % character. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%c` | int | A single character, | - | | | represented as a C int. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%d` | int | Equivalent to | - | | | ``printf("%d")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%u` | unsigned int | Equivalent to | - | | | ``printf("%u")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%ld` | long | Equivalent to | - | | | ``printf("%ld")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%li` | long | Equivalent to | - | | | ``printf("%li")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%lu` | unsigned long | Equivalent to | - | | | ``printf("%lu")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%lld` | long long | Equivalent to | - | | | ``printf("%lld")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%lli` | long long | Equivalent to | - | | | ``printf("%lli")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%llu` | unsigned long long | Equivalent to | - | | | ``printf("%llu")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%zd` | :c:type:`\ | Equivalent to | - | | Py_ssize_t` | ``printf("%zd")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%zi` | :c:type:`\ | Equivalent to | - | | Py_ssize_t` | ``printf("%zi")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%zu` | size_t | Equivalent to | - | | | ``printf("%zu")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%i` | int | Equivalent to | - | | | ``printf("%i")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%x` | int | Equivalent to | - | | | ``printf("%x")``. [1]_ | - +-------------------+---------------------+----------------------------------+ - | :attr:`%s` | const char\* | A null-terminated C character | - | | | array. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%p` | const void\* | The hex representation of a C | - | | | pointer. Mostly equivalent to | - | | | ``printf("%p")`` except that | - | | | it is guaranteed to start with | - | | | the literal ``0x`` regardless | - | | | of what the platform's | - | | | ``printf`` yields. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%A` | PyObject\* | The result of calling | - | | | :func:`ascii`. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%U` | PyObject\* | A Unicode object. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%V` | PyObject\*, | A Unicode object (which may be | - | | const char\* | ``NULL``) and a null-terminated | - | | | C character array as a second | - | | | parameter (which will be used, | - | | | if the first parameter is | - | | | ``NULL``). | - +-------------------+---------------------+----------------------------------+ - | :attr:`%S` | PyObject\* | The result of calling | - | | | :c:func:`PyObject_Str`. | - +-------------------+---------------------+----------------------------------+ - | :attr:`%R` | PyObject\* | The result of calling | - | | | :c:func:`PyObject_Repr`. | - +-------------------+---------------------+----------------------------------+ + ASCII-encoded string. + + A conversion specifier contains two or more characters and has the following + components, which must occur in this order: + + #. The ``'%'`` character, which marks the start of the specifier. + + #. Conversion flags (optional), which affect the result of some conversion + types. + + #. Minimum field width (optional). + If specified as an ``'*'`` (asterisk), the actual width is given in the + next argument, which must be of type :c:expr:`int`, and the object to + convert comes after the minimum field width and optional precision. + + #. Precision (optional), given as a ``'.'`` (dot) followed by the precision. + If specified as ``'*'`` (an asterisk), the actual precision is given in + the next argument, which must be of type :c:expr:`int`, and the value to + convert comes after the precision. + + #. Length modifier (optional). + + #. Conversion type. + + The conversion flag characters are: + + .. tabularcolumns:: |l|L| + + +-------+-------------------------------------------------------------+ + | Flag | Meaning | + +=======+=============================================================+ + | ``0`` | The conversion will be zero padded for numeric values. | + +-------+-------------------------------------------------------------+ + | ``-`` | The converted value is left adjusted (overrides the ``0`` | + | | flag if both are given). | + +-------+-------------------------------------------------------------+ + + The length modifiers for following integer conversions (``d``, ``i``, + ``o``, ``u``, ``x``, or ``X``) specify the type of the argument + (:c:expr:`int` by default): + + .. tabularcolumns:: |l|L| + + +----------+-----------------------------------------------------+ + | Modifier | Types | + +==========+=====================================================+ + | ``l`` | :c:expr:`long` or :c:expr:`unsigned long` | + +----------+-----------------------------------------------------+ + | ``ll`` | :c:expr:`long long` or :c:expr:`unsigned long long` | + +----------+-----------------------------------------------------+ + | ``j`` | :c:expr:`intmax_t` or :c:expr:`uintmax_t` | + +----------+-----------------------------------------------------+ + | ``z`` | :c:expr:`size_t` or :c:expr:`ssize_t` | + +----------+-----------------------------------------------------+ + | ``t`` | :c:expr:`ptrdiff_t` | + +----------+-----------------------------------------------------+ + + The length modifier ``l`` for following conversions ``s`` or ``V`` specify + that the type of the argument is :c:expr:`const wchar_t*`. + + The conversion specifiers are: + + .. list-table:: + :widths: auto + :header-rows: 1 + + * - Conversion Specifier + - Type + - Comment + + * - ``%`` + - *n/a* + - The literal ``%`` character. + + * - ``d``, ``i`` + - Specified by the length modifier + - The decimal representation of a signed C integer. + + * - ``u`` + - Specified by the length modifier + - The decimal representation of an unsigned C integer. + + * - ``o`` + - Specified by the length modifier + - The octal representation of an unsigned C integer. + + * - ``x`` + - Specified by the length modifier + - The hexadecimal representation of an unsigned C integer (lowercase). + + * - ``X`` + - Specified by the length modifier + - The hexadecimal representation of an unsigned C integer (uppercase). + + * - ``c`` + - :c:expr:`int` + - A single character. + + * - ``s`` + - :c:expr:`const char*` or :c:expr:`const wchar_t*` + - A null-terminated C character array. + + * - ``p`` + - :c:expr:`const void*` + - The hex representation of a C pointer. + Mostly equivalent to ``printf("%p")`` except that it is guaranteed to + start with the literal ``0x`` regardless of what the platform's + ``printf`` yields. + + * - ``A`` + - :c:expr:`PyObject*` + - The result of calling :func:`ascii`. + + * - ``U`` + - :c:expr:`PyObject*` + - A Unicode object. + + * - ``V`` + - :c:expr:`PyObject*`, :c:expr:`const char*` or :c:expr:`const wchar_t*` + - A Unicode object (which may be ``NULL``) and a null-terminated + C character array as a second parameter (which will be used, + if the first parameter is ``NULL``). + + * - ``S`` + - :c:expr:`PyObject*` + - The result of calling :c:func:`PyObject_Str`. + + * - ``R`` + - :c:expr:`PyObject*` + - The result of calling :c:func:`PyObject_Repr`. .. note:: The width formatter unit is number of characters rather than bytes. - The precision formatter unit is number of bytes for ``"%s"`` and + The precision formatter unit is number of bytes or :c:expr:`wchar_t` + items (if the length modifier ``l`` is used) for ``"%s"`` and ``"%V"`` (if the ``PyObject*`` argument is ``NULL``), and a number of characters for ``"%A"``, ``"%U"``, ``"%S"``, ``"%R"`` and ``"%V"`` (if the ``PyObject*`` argument is not ``NULL``). - .. [1] For integer specifiers (d, u, ld, li, lu, lld, lli, llu, zd, zi, - zu, i, x): the 0-conversion flag has effect even when a precision is given. + .. note:: + Unlike to C :c:func:`printf` the ``0`` flag has effect even when + a precision is given for integer conversions (``d``, ``i``, ``u``, ``o``, + ``x``, or ``X``). .. versionchanged:: 3.2 Support for ``"%lld"`` and ``"%llu"`` added. @@ -498,6 +549,13 @@ APIs: ``"%V"``, ``"%S"``, ``"%R"`` added. .. versionchanged:: 3.12 + Support for conversion specifiers ``o`` and ``X``. + Support for length modifiers ``j`` and ``t``. + Length modifiers are now applied to all integer conversions. + Length modifier ``l`` is now applied to conversion specifiers ``s`` and ``V``. + Support for variable width and precision ``*``. + Support for flag ``-``. + An unrecognized format character now sets a :exc:`SystemError`. In previous versions it caused all the rest of the format string to be copied as-is to the result string, and any extra arguments discarded. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 14f03ef755c7..caf21078b9bd 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1402,6 +1402,12 @@ Porting to Python 3.12 :py:meth:`~class.__subclasses__` (using :c:func:`PyObject_CallMethod`, for example). +* Add support of more formatting options (left aligning, octals, uppercase + hexadecimals, ``intmax_t``, ``ptrdiff_t``, ``wchar_t`` C + strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and + :c:func:`PyUnicode_FromFormatV`. + (Contributed by Serhiy Storchaka in :gh:`98836`.) + * An unrecognized format character in :c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV` now sets a :exc:`SystemError`. In previous versions it caused all the rest of the format string to be diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index 00807d968a7c..9c7662065689 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -319,12 +319,17 @@ def test_fromobject(self): def test_from_format(self): """Test PyUnicode_FromFormat()""" + # Length modifiers "j" and "t" are not tested here because ctypes does + # not expose types for intmax_t and ptrdiff_t. + # _testcapi.test_string_from_format() has a wider coverage of all + # formats. import_helper.import_module('ctypes') from ctypes import ( c_char_p, pythonapi, py_object, sizeof, c_int, c_long, c_longlong, c_ssize_t, - c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) + c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p, + sizeof, c_wchar, c_wchar_p) name = "PyUnicode_FromFormat" _PyUnicode_FromFormat = getattr(pythonapi, name) _PyUnicode_FromFormat.argtypes = (c_char_p,) @@ -449,37 +454,28 @@ def check_format(expected, format, *args): check_format("repr= 12", b'repr=%5.2V', None, b'123') - # test integer formats (%i, %d, %u) + # test integer formats (%i, %d, %u, %o, %x, %X) check_format('010', b'%03i', c_int(10)) check_format('0010', b'%0.4i', c_int(10)) - check_format('-123', - b'%i', c_int(-123)) - check_format('-123', - b'%li', c_long(-123)) - check_format('-123', - b'%lli', c_longlong(-123)) - check_format('-123', - b'%zi', c_ssize_t(-123)) - - check_format('-123', - b'%d', c_int(-123)) - check_format('-123', - b'%ld', c_long(-123)) - check_format('-123', - b'%lld', c_longlong(-123)) - check_format('-123', - b'%zd', c_ssize_t(-123)) - - check_format('123', - b'%u', c_uint(123)) - check_format('123', - b'%lu', c_ulong(123)) - check_format('123', - b'%llu', c_ulonglong(123)) - check_format('123', - b'%zu', c_size_t(123)) + for conv, signed, value, expected in [ + (b'i', True, -123, '-123'), + (b'd', True, -123, '-123'), + (b'u', False, 123, '123'), + (b'o', False, 0o123, '123'), + (b'x', False, 0xabc, 'abc'), + (b'X', False, 0xabc, 'ABC'), + ]: + for mod, ctype in [ + (b'', c_int if signed else c_uint), + (b'l', c_long if signed else c_ulong), + (b'll', c_longlong if signed else c_ulonglong), + (b'z', c_ssize_t if signed else c_size_t), + ]: + with self.subTest(format=b'%' + mod + conv): + check_format(expected, + b'%' + mod + conv, ctype(value)) # test long output min_longlong = -(2 ** (8 * sizeof(c_longlong) - 1)) @@ -494,40 +490,144 @@ def check_format(expected, format, *args): PyUnicode_FromFormat(b'%p', c_void_p(-1)) # test padding (width and/or precision) - check_format('123'.rjust(10, '0'), - b'%010i', c_int(123)) - check_format('123'.rjust(100), - b'%100i', c_int(123)) - check_format('123'.rjust(100, '0'), - b'%.100i', c_int(123)) - check_format('123'.rjust(80, '0').rjust(100), - b'%100.80i', c_int(123)) - - check_format('123'.rjust(10, '0'), - b'%010u', c_uint(123)) - check_format('123'.rjust(100), - b'%100u', c_uint(123)) - check_format('123'.rjust(100, '0'), - b'%.100u', c_uint(123)) - check_format('123'.rjust(80, '0').rjust(100), - b'%100.80u', c_uint(123)) - - check_format('123'.rjust(10, '0'), - b'%010x', c_int(0x123)) - check_format('123'.rjust(100), - b'%100x', c_int(0x123)) - check_format('123'.rjust(100, '0'), - b'%.100x', c_int(0x123)) - check_format('123'.rjust(80, '0').rjust(100), - b'%100.80x', c_int(0x123)) + check_format('123', b'%2i', c_int(123)) + check_format(' 123', b'%10i', c_int(123)) + check_format('0000000123', b'%010i', c_int(123)) + check_format('123 ', b'%-10i', c_int(123)) + check_format('123 ', b'%-010i', c_int(123)) + check_format('123', b'%.2i', c_int(123)) + check_format('0000123', b'%.7i', c_int(123)) + check_format(' 123', b'%10.2i', c_int(123)) + check_format(' 0000123', b'%10.7i', c_int(123)) + check_format('0000000123', b'%010.7i', c_int(123)) + check_format('0000123 ', b'%-10.7i', c_int(123)) + check_format('0000123 ', b'%-010.7i', c_int(123)) + + check_format('-123', b'%2i', c_int(-123)) + check_format(' -123', b'%10i', c_int(-123)) + check_format('-000000123', b'%010i', c_int(-123)) + check_format('-123 ', b'%-10i', c_int(-123)) + check_format('-123 ', b'%-010i', c_int(-123)) + check_format('-123', b'%.2i', c_int(-123)) + check_format('-0000123', b'%.7i', c_int(-123)) + check_format(' -123', b'%10.2i', c_int(-123)) + check_format(' -0000123', b'%10.7i', c_int(-123)) + check_format('-000000123', b'%010.7i', c_int(-123)) + check_format('-0000123 ', b'%-10.7i', c_int(-123)) + check_format('-0000123 ', b'%-010.7i', c_int(-123)) + + check_format('123', b'%2u', c_uint(123)) + check_format(' 123', b'%10u', c_uint(123)) + check_format('0000000123', b'%010u', c_uint(123)) + check_format('123 ', b'%-10u', c_uint(123)) + check_format('123 ', b'%-010u', c_uint(123)) + check_format('123', b'%.2u', c_uint(123)) + check_format('0000123', b'%.7u', c_uint(123)) + check_format(' 123', b'%10.2u', c_uint(123)) + check_format(' 0000123', b'%10.7u', c_uint(123)) + check_format('0000000123', b'%010.7u', c_uint(123)) + check_format('0000123 ', b'%-10.7u', c_uint(123)) + check_format('0000123 ', b'%-010.7u', c_uint(123)) + + check_format('123', b'%2o', c_uint(0o123)) + check_format(' 123', b'%10o', c_uint(0o123)) + check_format('0000000123', b'%010o', c_uint(0o123)) + check_format('123 ', b'%-10o', c_uint(0o123)) + check_format('123 ', b'%-010o', c_uint(0o123)) + check_format('123', b'%.2o', c_uint(0o123)) + check_format('0000123', b'%.7o', c_uint(0o123)) + check_format(' 123', b'%10.2o', c_uint(0o123)) + check_format(' 0000123', b'%10.7o', c_uint(0o123)) + check_format('0000000123', b'%010.7o', c_uint(0o123)) + check_format('0000123 ', b'%-10.7o', c_uint(0o123)) + check_format('0000123 ', b'%-010.7o', c_uint(0o123)) + + check_format('abc', b'%2x', c_uint(0xabc)) + check_format(' abc', b'%10x', c_uint(0xabc)) + check_format('0000000abc', b'%010x', c_uint(0xabc)) + check_format('abc ', b'%-10x', c_uint(0xabc)) + check_format('abc ', b'%-010x', c_uint(0xabc)) + check_format('abc', b'%.2x', c_uint(0xabc)) + check_format('0000abc', b'%.7x', c_uint(0xabc)) + check_format(' abc', b'%10.2x', c_uint(0xabc)) + check_format(' 0000abc', b'%10.7x', c_uint(0xabc)) + check_format('0000000abc', b'%010.7x', c_uint(0xabc)) + check_format('0000abc ', b'%-10.7x', c_uint(0xabc)) + check_format('0000abc ', b'%-010.7x', c_uint(0xabc)) + + check_format('ABC', b'%2X', c_uint(0xabc)) + check_format(' ABC', b'%10X', c_uint(0xabc)) + check_format('0000000ABC', b'%010X', c_uint(0xabc)) + check_format('ABC ', b'%-10X', c_uint(0xabc)) + check_format('ABC ', b'%-010X', c_uint(0xabc)) + check_format('ABC', b'%.2X', c_uint(0xabc)) + check_format('0000ABC', b'%.7X', c_uint(0xabc)) + check_format(' ABC', b'%10.2X', c_uint(0xabc)) + check_format(' 0000ABC', b'%10.7X', c_uint(0xabc)) + check_format('0000000ABC', b'%010.7X', c_uint(0xabc)) + check_format('0000ABC ', b'%-10.7X', c_uint(0xabc)) + check_format('0000ABC ', b'%-010.7X', c_uint(0xabc)) # test %A check_format(r"%A:'abc\xe9\uabcd\U0010ffff'", b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') # test %V - check_format('repr=abc', - b'repr=%V', 'abc', b'xyz') + check_format('abc', + b'%V', 'abc', b'xyz') + check_format('xyz', + b'%V', None, b'xyz') + + # test %ls + check_format('abc', b'%ls', c_wchar_p('abc')) + check_format('\u4eba\u6c11', b'%ls', c_wchar_p('\u4eba\u6c11')) + check_format('\U0001f4bb+\U0001f40d', + b'%ls', c_wchar_p('\U0001f4bb+\U0001f40d')) + check_format(' ab', b'%5.2ls', c_wchar_p('abc')) + check_format(' \u4eba\u6c11', b'%5ls', c_wchar_p('\u4eba\u6c11')) + check_format(' \U0001f4bb+\U0001f40d', + b'%5ls', c_wchar_p('\U0001f4bb+\U0001f40d')) + check_format('\u4eba', b'%.1ls', c_wchar_p('\u4eba\u6c11')) + check_format('\U0001f4bb' if sizeof(c_wchar) > 2 else '\ud83d', + b'%.1ls', c_wchar_p('\U0001f4bb+\U0001f40d')) + check_format('\U0001f4bb+' if sizeof(c_wchar) > 2 else '\U0001f4bb', + b'%.2ls', c_wchar_p('\U0001f4bb+\U0001f40d')) + + # test %lV + check_format('abc', + b'%lV', 'abc', c_wchar_p('xyz')) + check_format('xyz', + b'%lV', None, c_wchar_p('xyz')) + check_format('\u4eba\u6c11', + b'%lV', None, c_wchar_p('\u4eba\u6c11')) + check_format('\U0001f4bb+\U0001f40d', + b'%lV', None, c_wchar_p('\U0001f4bb+\U0001f40d')) + check_format(' ab', + b'%5.2lV', None, c_wchar_p('abc')) + check_format(' \u4eba\u6c11', + b'%5lV', None, c_wchar_p('\u4eba\u6c11')) + check_format(' \U0001f4bb+\U0001f40d', + b'%5lV', None, c_wchar_p('\U0001f4bb+\U0001f40d')) + check_format('\u4eba', + b'%.1lV', None, c_wchar_p('\u4eba\u6c11')) + check_format('\U0001f4bb' if sizeof(c_wchar) > 2 else '\ud83d', + b'%.1lV', None, c_wchar_p('\U0001f4bb+\U0001f40d')) + check_format('\U0001f4bb+' if sizeof(c_wchar) > 2 else '\U0001f4bb', + b'%.2lV', None, c_wchar_p('\U0001f4bb+\U0001f40d')) + + # test variable width and precision + check_format(' abc', b'%*s', c_int(5), b'abc') + check_format('ab', b'%.*s', c_int(2), b'abc') + check_format(' ab', b'%*.*s', c_int(5), c_int(2), b'abc') + check_format(' abc', b'%*U', c_int(5), 'abc') + check_format('ab', b'%.*U', c_int(2), 'abc') + check_format(' ab', b'%*.*U', c_int(5), c_int(2), 'abc') + check_format(' ab', b'%*.*V', c_int(5), c_int(2), None, b'abc') + check_format(' ab', b'%*.*lV', c_int(5), c_int(2), + None, c_wchar_p('abc')) + check_format(' 123', b'%*i', c_int(8), c_int(123)) + check_format('00123', b'%.*i', c_int(5), c_int(123)) + check_format(' 00123', b'%*.*i', c_int(8), c_int(5), c_int(123)) # test %p # We cannot test the exact result, @@ -564,10 +664,11 @@ def check_format(expected, format, *args): check_format('', b'%s', b'') - # check for crashes + # test invalid format strings. these tests are just here + # to check for crashes and should not be considered as specifications for fmt in (b'%', b'%0', b'%01', b'%.', b'%.1', b'%0%s', b'%1%s', b'%.%s', b'%.1%s', b'%1abc', - b'%l', b'%ll', b'%z', b'%ls', b'%lls', b'%zs'): + b'%l', b'%ll', b'%z', b'%lls', b'%zs'): with self.subTest(fmt=fmt): self.assertRaisesRegex(SystemError, 'invalid format string', PyUnicode_FromFormat, fmt, b'abc') diff --git a/Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst b/Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst new file mode 100644 index 000000000000..e3730eb3f89e --- /dev/null +++ b/Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst @@ -0,0 +1,4 @@ +Add support of more formatting options (left aligning, octals, uppercase +hexadecimals, :c:expr:`intmax_t`, :c:expr:`ptrdiff_t`, :c:expr:`wchar_t` C +strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and +:c:func:`PyUnicode_FromFormatV`. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 016a5a5cbca5..5bf6b3bc19b2 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1330,10 +1330,8 @@ _get_peer_alt_names (_sslmodulestate *state, X509 *certificate) { p[0], p[1], p[2], p[3] ); } else if (name->d.ip->length == 16) { - /* PyUnicode_FromFormat() does not support %X */ unsigned char *p = name->d.ip->data; - len = sprintf( - buf, + v = PyUnicode_FromFormat( "%X:%X:%X:%X:%X:%X:%X:%X", p[0] << 8 | p[1], p[2] << 8 | p[3], @@ -1344,7 +1342,6 @@ _get_peer_alt_names (_sslmodulestate *state, X509 *certificate) { p[12] << 8 | p[13], p[14] << 8 | p[15] ); - v = PyUnicode_FromStringAndSize(buf, len); } else { v = PyUnicode_FromString("<invalid>"); } diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 7dd3b9c0c03e..73929eaffc67 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -1,3 +1,5 @@ +#include <stddef.h> // ptrdiff_t + #define PY_SSIZE_T_CLEAN #include "parts.h" @@ -1130,25 +1132,48 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1( "%c", "c", 'c'); CHECK_FORMAT_1( "%0c", "c", 'c'); CHECK_FORMAT_1("%00c", "c", 'c'); - CHECK_FORMAT_1( "%2c", "c", 'c'); - CHECK_FORMAT_1("%02c", "c", 'c'); - CHECK_FORMAT_1("%.0c", "c", 'c'); - CHECK_FORMAT_1("%.2c", "c", 'c'); + CHECK_FORMAT_1( "%2c", NULL, 'c'); + CHECK_FORMAT_1("%02c", NULL, 'c'); + CHECK_FORMAT_1("%.0c", NULL, 'c'); + CHECK_FORMAT_1("%.2c", NULL, 'c'); // Integers CHECK_FORMAT_1("%d", "123", (int)123); CHECK_FORMAT_1("%i", "123", (int)123); CHECK_FORMAT_1("%u", "123", (unsigned int)123); + CHECK_FORMAT_1("%x", "7b", (unsigned int)123); + CHECK_FORMAT_1("%X", "7B", (unsigned int)123); + CHECK_FORMAT_1("%o", "173", (unsigned int)123); CHECK_FORMAT_1("%ld", "123", (long)123); CHECK_FORMAT_1("%li", "123", (long)123); CHECK_FORMAT_1("%lu", "123", (unsigned long)123); + CHECK_FORMAT_1("%lx", "7b", (unsigned long)123); + CHECK_FORMAT_1("%lX", "7B", (unsigned long)123); + CHECK_FORMAT_1("%lo", "173", (unsigned long)123); CHECK_FORMAT_1("%lld", "123", (long long)123); CHECK_FORMAT_1("%lli", "123", (long long)123); CHECK_FORMAT_1("%llu", "123", (unsigned long long)123); + CHECK_FORMAT_1("%llx", "7b", (unsigned long long)123); + CHECK_FORMAT_1("%llX", "7B", (unsigned long long)123); + CHECK_FORMAT_1("%llo", "173", (unsigned long long)123); CHECK_FORMAT_1("%zd", "123", (Py_ssize_t)123); CHECK_FORMAT_1("%zi", "123", (Py_ssize_t)123); CHECK_FORMAT_1("%zu", "123", (size_t)123); - CHECK_FORMAT_1("%x", "7b", (int)123); + CHECK_FORMAT_1("%zx", "7b", (size_t)123); + CHECK_FORMAT_1("%zX", "7B", (size_t)123); + CHECK_FORMAT_1("%zo", "173", (size_t)123); + CHECK_FORMAT_1("%td", "123", (ptrdiff_t)123); + CHECK_FORMAT_1("%ti", "123", (ptrdiff_t)123); + CHECK_FORMAT_1("%tu", "123", (ptrdiff_t)123); + CHECK_FORMAT_1("%tx", "7b", (ptrdiff_t)123); + CHECK_FORMAT_1("%tX", "7B", (ptrdiff_t)123); + CHECK_FORMAT_1("%to", "173", (ptrdiff_t)123); + CHECK_FORMAT_1("%jd", "123", (intmax_t)123); + CHECK_FORMAT_1("%ji", "123", (intmax_t)123); + CHECK_FORMAT_1("%ju", "123", (uintmax_t)123); + CHECK_FORMAT_1("%jx", "7b", (uintmax_t)123); + CHECK_FORMAT_1("%jX", "7B", (uintmax_t)123); + CHECK_FORMAT_1("%jo", "173", (uintmax_t)123); CHECK_FORMAT_1("%d", "-123", (int)-123); CHECK_FORMAT_1("%i", "-123", (int)-123); @@ -1158,7 +1183,10 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%lli", "-123", (long long)-123); CHECK_FORMAT_1("%zd", "-123", (Py_ssize_t)-123); CHECK_FORMAT_1("%zi", "-123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%x", "ffffff85", (int)-123); + CHECK_FORMAT_1("%td", "-123", (ptrdiff_t)-123); + CHECK_FORMAT_1("%ti", "-123", (ptrdiff_t)-123); + CHECK_FORMAT_1("%jd", "-123", (intmax_t)-123); + CHECK_FORMAT_1("%ji", "-123", (intmax_t)-123); // Integers: width < length CHECK_FORMAT_1("%1d", "123", (int)123); @@ -1183,7 +1211,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%1lli", "-123", (long long)-123); CHECK_FORMAT_1("%1zd", "-123", (Py_ssize_t)-123); CHECK_FORMAT_1("%1zi", "-123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%1x", "ffffff85", (int)-123); // Integers: width > length CHECK_FORMAT_1("%5d", " 123", (int)123); @@ -1208,7 +1235,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%5lli", " -123", (long long)-123); CHECK_FORMAT_1("%5zd", " -123", (Py_ssize_t)-123); CHECK_FORMAT_1("%5zi", " -123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%9x", " ffffff85", (int)-123); // Integers: width > length, 0-flag CHECK_FORMAT_1("%05d", "00123", (int)123); @@ -1233,7 +1259,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%05lli", "-0123", (long long)-123); CHECK_FORMAT_1("%05zd", "-0123", (Py_ssize_t)-123); CHECK_FORMAT_1("%05zi", "-0123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%09x", "0ffffff85", (int)-123); // Integers: precision < length CHECK_FORMAT_1("%.1d", "123", (int)123); @@ -1258,7 +1283,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%.1lli", "-123", (long long)-123); CHECK_FORMAT_1("%.1zd", "-123", (Py_ssize_t)-123); CHECK_FORMAT_1("%.1zi", "-123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%.1x", "ffffff85", (int)-123); // Integers: precision > length CHECK_FORMAT_1("%.5d", "00123", (int)123); @@ -1283,7 +1307,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%.5lli", "-00123", (long long)-123); CHECK_FORMAT_1("%.5zd", "-00123", (Py_ssize_t)-123); CHECK_FORMAT_1("%.5zi", "-00123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%.9x", "0ffffff85", (int)-123); // Integers: width > precision > length CHECK_FORMAT_1("%7.5d", " 00123", (int)123); @@ -1308,7 +1331,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%7.5lli", " -00123", (long long)-123); CHECK_FORMAT_1("%7.5zd", " -00123", (Py_ssize_t)-123); CHECK_FORMAT_1("%7.5zi", " -00123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%10.9x", " 0ffffff85", (int)-123); // Integers: width > precision > length, 0-flag CHECK_FORMAT_1("%07.5d", "0000123", (int)123); @@ -1333,7 +1355,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%07.5lli", "-000123", (long long)-123); CHECK_FORMAT_1("%07.5zd", "-000123", (Py_ssize_t)-123); CHECK_FORMAT_1("%07.5zi", "-000123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%010.9x", "00ffffff85", (int)-123); // Integers: precision > width > length CHECK_FORMAT_1("%5.7d", "0000123", (int)123); @@ -1358,7 +1379,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%5.7lli", "-0000123", (long long)-123); CHECK_FORMAT_1("%5.7zd", "-0000123", (Py_ssize_t)-123); CHECK_FORMAT_1("%5.7zi", "-0000123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%9.10x", "00ffffff85", (int)-123); // Integers: precision > width > length, 0-flag CHECK_FORMAT_1("%05.7d", "0000123", (int)123); @@ -1383,7 +1403,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) CHECK_FORMAT_1("%05.7lli", "-0000123", (long long)-123); CHECK_FORMAT_1("%05.7zd", "-0000123", (Py_ssize_t)-123); CHECK_FORMAT_1("%05.7zi", "-0000123", (Py_ssize_t)-123); - CHECK_FORMAT_1("%09.10x", "00ffffff85", (int)-123); // Integers: precision = 0, arg = 0 (empty string in C) CHECK_FORMAT_1("%.0d", "0", (int)0); @@ -1402,66 +1421,80 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) // Strings CHECK_FORMAT_1("%s", "None", "None"); + CHECK_FORMAT_1("%ls", "None", L"None"); CHECK_FORMAT_1("%U", "None", unicode); CHECK_FORMAT_1("%A", "None", Py_None); CHECK_FORMAT_1("%S", "None", Py_None); CHECK_FORMAT_1("%R", "None", Py_None); CHECK_FORMAT_2("%V", "None", unicode, "ignored"); CHECK_FORMAT_2("%V", "None", NULL, "None"); + CHECK_FORMAT_2("%lV", "None", NULL, L"None"); // Strings: width < length CHECK_FORMAT_1("%1s", "None", "None"); + CHECK_FORMAT_1("%1ls", "None", L"None"); CHECK_FORMAT_1("%1U", "None", unicode); CHECK_FORMAT_1("%1A", "None", Py_None); CHECK_FORMAT_1("%1S", "None", Py_None); CHECK_FORMAT_1("%1R", "None", Py_None); CHECK_FORMAT_2("%1V", "None", unicode, "ignored"); CHECK_FORMAT_2("%1V", "None", NULL, "None"); + CHECK_FORMAT_2("%1lV", "None", NULL, L"None"); // Strings: width > length CHECK_FORMAT_1("%5s", " None", "None"); + CHECK_FORMAT_1("%5ls", " None", L"None"); CHECK_FORMAT_1("%5U", " None", unicode); CHECK_FORMAT_1("%5A", " None", Py_None); CHECK_FORMAT_1("%5S", " None", Py_None); CHECK_FORMAT_1("%5R", " None", Py_None); CHECK_FORMAT_2("%5V", " None", unicode, "ignored"); CHECK_FORMAT_2("%5V", " None", NULL, "None"); + CHECK_FORMAT_2("%5lV", " None", NULL, L"None"); // Strings: precision < length CHECK_FORMAT_1("%.1s", "N", "None"); + CHECK_FORMAT_1("%.1ls", "N", L"None"); CHECK_FORMAT_1("%.1U", "N", unicode); CHECK_FORMAT_1("%.1A", "N", Py_None); CHECK_FORMAT_1("%.1S", "N", Py_None); CHECK_FORMAT_1("%.1R", "N", Py_None); CHECK_FORMAT_2("%.1V", "N", unicode, "ignored"); CHECK_FORMAT_2("%.1V", "N", NULL, "None"); + CHECK_FORMAT_2("%.1lV", "N", NULL, L"None"); // Strings: precision > length CHECK_FORMAT_1("%.5s", "None", "None"); + CHECK_FORMAT_1("%.5ls", "None", L"None"); CHECK_FORMAT_1("%.5U", "None", unicode); CHECK_FORMAT_1("%.5A", "None", Py_None); CHECK_FORMAT_1("%.5S", "None", Py_None); CHECK_FORMAT_1("%.5R", "None", Py_None); CHECK_FORMAT_2("%.5V", "None", unicode, "ignored"); CHECK_FORMAT_2("%.5V", "None", NULL, "None"); + CHECK_FORMAT_2("%.5lV", "None", NULL, L"None"); // Strings: precision < length, width > length CHECK_FORMAT_1("%5.1s", " N", "None"); + CHECK_FORMAT_1("%5.1ls"," N", L"None"); CHECK_FORMAT_1("%5.1U", " N", unicode); CHECK_FORMAT_1("%5.1A", " N", Py_None); CHECK_FORMAT_1("%5.1S", " N", Py_None); CHECK_FORMAT_1("%5.1R", " N", Py_None); CHECK_FORMAT_2("%5.1V", " N", unicode, "ignored"); CHECK_FORMAT_2("%5.1V", " N", NULL, "None"); + CHECK_FORMAT_2("%5.1lV"," N", NULL, L"None"); // Strings: width < length, precision > length CHECK_FORMAT_1("%1.5s", "None", "None"); + CHECK_FORMAT_1("%1.5ls", "None", L"None"); CHECK_FORMAT_1("%1.5U", "None", unicode); CHECK_FORMAT_1("%1.5A", "None", Py_None); CHECK_FORMAT_1("%1.5S", "None", Py_None); CHECK_FORMAT_1("%1.5R", "None", Py_None); CHECK_FORMAT_2("%1.5V", "None", unicode, "ignored"); CHECK_FORMAT_2("%1.5V", "None", NULL, "None"); + CHECK_FORMAT_2("%1.5lV", "None", NULL, L"None"); Py_XDECREF(unicode); Py_RETURN_NONE; diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 79bd5b59ab68..9a4943c9eb2f 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -1849,14 +1849,11 @@ static PyObject * kqueue_event_repr(kqueue_event_Object *s) { - char buf[1024]; - PyOS_snprintf( - buf, sizeof(buf), + return PyUnicode_FromFormat( "<select.kevent ident=%zu filter=%d flags=0x%x fflags=0x%x " "data=0x%llx udata=%p>", (size_t)(s->e.ident), (int)s->e.filter, (unsigned int)s->e.flags, (unsigned int)s->e.fflags, (long long)(s->e.data), (void *)s->e.udata); - return PyUnicode_FromString(buf); } static int diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index c11fb4400eab..a86aaed501fa 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1339,8 +1339,6 @@ setbdaddr(const char *name, bdaddr_t *bdaddr) static PyObject * makebdaddr(bdaddr_t *bdaddr) { - char buf[(6 * 2) + 5 + 1]; - #ifdef MS_WINDOWS int i; unsigned int octets[6]; @@ -1349,16 +1347,14 @@ makebdaddr(bdaddr_t *bdaddr) octets[i] = ((*bdaddr) >> (8 * i)) & 0xFF; } - sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + return PyUnicode_FromFormat("%02X:%02X:%02X:%02X:%02X:%02X", octets[5], octets[4], octets[3], octets[2], octets[1], octets[0]); #else - sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + return PyUnicode_FromFormat("%02X:%02X:%02X:%02X:%02X:%02X", bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); #endif - - return PyUnicode_FromString(buf); } #endif diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7726f2fb17af..ec5684b1d095 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -56,6 +56,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_unicodeobject.h" // struct _Py_unicode_state #include "pycore_unicodeobject_generated.h" // _PyUnicode_InitStaticStrings() #include "stringlib/eq.h" // unicode_eq() +#include <stddef.h> // ptrdiff_t #ifdef MS_WINDOWS #include <windows.h> @@ -2285,14 +2286,15 @@ PyUnicode_AsUCS4Copy(PyObject *string) return as_ucs4(string, NULL, 0, 1); } -/* maximum number of characters required for output of %lld or %p. - We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, - plus 1 for the sign. 53/22 is an upper bound for log10(256). */ -#define MAX_LONG_LONG_CHARS (2 + (SIZEOF_LONG_LONG*53-1) / 22) +/* maximum number of characters required for output of %jo or %jd or %p. + We need at most ceil(log8(256)*sizeof(intmax_t)) digits, + plus 1 for the sign, plus 2 for the 0x prefix (for %p), + plus 1 for the terminal NUL. */ +#define MAX_INTMAX_CHARS (5 + (sizeof(intmax_t)*8-1) / 3) static int unicode_fromformat_write_str(_PyUnicodeWriter *writer, PyObject *str, - Py_ssize_t width, Py_ssize_t precision) + Py_ssize_t width, Py_ssize_t precision, int flags) { Py_ssize_t length, fill, arglen; Py_UCS4 maxchar; @@ -2314,8 +2316,8 @@ unicode_fromformat_write_str(_PyUnicodeWriter *writer, PyObject *str, if (_PyUnicodeWriter_Prepare(writer, arglen, maxchar) == -1) return -1; - if (width > length) { - fill = width - length; + fill = Py_MAX(width - length, 0); + if (fill && !(flags & F_LJUST)) { if (PyUnicode_Fill(writer->buffer, writer->pos, fill, ' ') == -1) return -1; writer->pos += fill; @@ -2324,12 +2326,19 @@ unicode_fromformat_write_str(_PyUnicodeWriter *writer, PyObject *str, _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, str, 0, length); writer->pos += length; + + if (fill && (flags & F_LJUST)) { + if (PyUnicode_Fill(writer->buffer, writer->pos, fill, ' ') == -1) + return -1; + writer->pos += fill; + } + return 0; } static int unicode_fromformat_write_cstr(_PyUnicodeWriter *writer, const char *str, - Py_ssize_t width, Py_ssize_t precision) + Py_ssize_t width, Py_ssize_t precision, int flags) { /* UTF-8 */ Py_ssize_t length; @@ -2349,24 +2358,58 @@ unicode_fromformat_write_cstr(_PyUnicodeWriter *writer, const char *str, if (unicode == NULL) return -1; - res = unicode_fromformat_write_str(writer, unicode, width, -1); + res = unicode_fromformat_write_str(writer, unicode, width, -1, flags); + Py_DECREF(unicode); + return res; +} + +static int +unicode_fromformat_write_wcstr(_PyUnicodeWriter *writer, const wchar_t *str, + Py_ssize_t width, Py_ssize_t precision, int flags) +{ + /* UTF-8 */ + Py_ssize_t length; + PyObject *unicode; + int res; + + if (precision == -1) { + length = wcslen(str); + } + else { + length = 0; + while (length < precision && str[length]) { + length++; + } + } + unicode = PyUnicode_FromWideChar(str, length); + if (unicode == NULL) + return -1; + + res = unicode_fromformat_write_str(writer, unicode, width, -1, flags); Py_DECREF(unicode); return res; } +#define F_LONG 1 +#define F_LONGLONG 2 +#define F_SIZE 3 +#define F_PTRDIFF 4 +#define F_INTMAX 5 +static const char * const formats[] = {"%d", "%ld", "%lld", "%zd", "%td", "%jd"}; +static const char * const formats_o[] = {"%o", "%lo", "%llo", "%zo", "%to", "%jo"}; +static const char * const formats_u[] = {"%u", "%lu", "%llu", "%zu", "%tu", "%ju"}; +static const char * const formats_x[] = {"%x", "%lx", "%llx", "%zx", "%tx", "%jx"}; +static const char * const formats_X[] = {"%X", "%lX", "%llX", "%zX", "%tX", "%jX"}; + static const char* unicode_fromformat_arg(_PyUnicodeWriter *writer, const char *f, va_list *vargs) { const char *p; Py_ssize_t len; - int zeropad; + int flags = 0; Py_ssize_t width; Py_ssize_t precision; - int longflag; - int longlongflag; - int size_tflag; - Py_ssize_t fill; p = f; f++; @@ -2377,15 +2420,31 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, return f; } - zeropad = 0; - if (*f == '0') { - zeropad = 1; - f++; + /* Parse flags. Example: "%-i" => flags=F_LJUST. */ + /* Flags '+', ' ' and '#' are not particularly useful. + * They are not worth the implementation and maintenance costs. + * In addition, '#' should add "0" for "o" conversions for compatibility + * with printf, but it would confuse Python users. */ + while (1) { + switch (*f++) { + case '-': flags |= F_LJUST; continue; + case '0': flags |= F_ZERO; continue; + } + f--; + break; } /* parse the width.precision part, e.g. "%2.5s" => width=2, precision=5 */ width = -1; - if (Py_ISDIGIT((unsigned)*f)) { + if (*f == '*') { + width = va_arg(*vargs, int); + if (width < 0) { + flags |= F_LJUST; + width = -width; + } + f++; + } + else if (Py_ISDIGIT((unsigned)*f)) { width = *f - '0'; f++; while (Py_ISDIGIT((unsigned)*f)) { @@ -2401,7 +2460,14 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, precision = -1; if (*f == '.') { f++; - if (Py_ISDIGIT((unsigned)*f)) { + if (*f == '*') { + precision = va_arg(*vargs, int); + if (precision < 0) { + precision = -2; + } + f++; + } + else if (Py_ISDIGIT((unsigned)*f)) { precision = (*f - '0'); f++; while (Py_ISDIGIT((unsigned)*f)) { @@ -2416,30 +2482,47 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, } } - /* Handle %ld, %lu, %lld and %llu. */ - longflag = 0; - longlongflag = 0; - size_tflag = 0; + int sizemod = 0; if (*f == 'l') { - if (f[1] == 'd' || f[1] == 'u' || f[1] == 'i') { - longflag = 1; - ++f; - } - else if (f[1] == 'l' && - (f[2] == 'd' || f[2] == 'u' || f[2] == 'i')) { - longlongflag = 1; + if (f[1] == 'l') { + sizemod = F_LONGLONG; f += 2; } + else { + sizemod = F_LONG; + ++f; + } } - /* handle the size_t flag. */ - else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u' || f[1] == 'i')) { - size_tflag = 1; + else if (*f == 'z') { + sizemod = F_SIZE; + ++f; + } + else if (*f == 't') { + sizemod = F_PTRDIFF; + ++f; + } + else if (*f == 'j') { + sizemod = F_INTMAX; ++f; } - if (f[0] != '\0' && f[1] == '\0') writer->overallocate = 0; + switch (*f) { + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': + break; + case 'c': case 'p': + if (sizemod || width >= 0 || precision >= 0) goto invalid_format; + break; + case 's': + case 'V': + if (sizemod && sizemod != F_LONG) goto invalid_format; + break; + default: + if (sizemod) goto invalid_format; + break; + } + switch (*f) { case 'c': { @@ -2454,91 +2537,98 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, break; } - case 'i': - case 'd': - case 'u': - case 'x': + case 'd': case 'i': + case 'o': case 'u': case 'x': case 'X': { /* used by sprintf */ - char buffer[MAX_LONG_LONG_CHARS]; - Py_ssize_t arglen; - - if (*f == 'u') { - if (longflag) { - len = sprintf(buffer, "%lu", va_arg(*vargs, unsigned long)); - } - else if (longlongflag) { - len = sprintf(buffer, "%llu", va_arg(*vargs, unsigned long long)); - } - else if (size_tflag) { - len = sprintf(buffer, "%zu", va_arg(*vargs, size_t)); - } - else { - len = sprintf(buffer, "%u", va_arg(*vargs, unsigned int)); - } - } - else if (*f == 'x') { - len = sprintf(buffer, "%x", va_arg(*vargs, int)); - } - else { - if (longflag) { - len = sprintf(buffer, "%li", va_arg(*vargs, long)); - } - else if (longlongflag) { - len = sprintf(buffer, "%lli", va_arg(*vargs, long long)); - } - else if (size_tflag) { - len = sprintf(buffer, "%zi", va_arg(*vargs, Py_ssize_t)); - } - else { - len = sprintf(buffer, "%i", va_arg(*vargs, int)); - } + char buffer[MAX_INTMAX_CHARS]; + const char *fmt = NULL; + switch (*f) { + case 'o': fmt = formats_o[sizemod]; break; + case 'u': fmt = formats_u[sizemod]; break; + case 'x': fmt = formats_x[sizemod]; break; + case 'X': fmt = formats_X[sizemod]; break; + default: fmt = formats[sizemod]; break; + } + int issigned = (*f == 'd' || *f == 'i'); + switch (sizemod) { + case F_LONG: + len = issigned ? + sprintf(buffer, fmt, va_arg(*vargs, long)) : + sprintf(buffer, fmt, va_arg(*vargs, unsigned long)); + break; + case F_LONGLONG: + len = issigned ? + sprintf(buffer, fmt, va_arg(*vargs, long long)) : + sprintf(buffer, fmt, va_arg(*vargs, unsigned long long)); + break; + case F_SIZE: + len = issigned ? + sprintf(buffer, fmt, va_arg(*vargs, Py_ssize_t)) : + sprintf(buffer, fmt, va_arg(*vargs, size_t)); + break; + case F_PTRDIFF: + len = sprintf(buffer, fmt, va_arg(*vargs, ptrdiff_t)); + break; + case F_INTMAX: + len = issigned ? + sprintf(buffer, fmt, va_arg(*vargs, intmax_t)) : + sprintf(buffer, fmt, va_arg(*vargs, uintmax_t)); + break; + default: + len = issigned ? + sprintf(buffer, fmt, va_arg(*vargs, int)) : + sprintf(buffer, fmt, va_arg(*vargs, unsigned int)); + break; } assert(len >= 0); - int negative = (buffer[0] == '-'); - len -= negative; + int sign = (buffer[0] == '-'); + len -= sign; precision = Py_MAX(precision, len); - width = Py_MAX(width, precision + negative); + width = Py_MAX(width, precision + sign); + if ((flags & F_ZERO) && !(flags & F_LJUST)) { + precision = width - sign; + } - arglen = Py_MAX(precision, width); - if (_PyUnicodeWriter_Prepare(writer, arglen, 127) == -1) - return NULL; + Py_ssize_t spacepad = Py_MAX(width - precision - sign, 0); + Py_ssize_t zeropad = Py_MAX(precision - len, 0); - if (width > precision) { - if (negative && zeropad) { - if (_PyUnicodeWriter_WriteChar(writer, '-') == -1) - return NULL; - } + if (_PyUnicodeWriter_Prepare(writer, width, 127) == -1) + return NULL; - Py_UCS4 fillchar = zeropad?'0':' '; - fill = width - precision - negative; - if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1) + if (spacepad && !(flags & F_LJUST)) { + if (PyUnicode_Fill(writer->buffer, writer->pos, spacepad, ' ') == -1) return NULL; - writer->pos += fill; + writer->pos += spacepad; + } - if (negative && !zeropad) { - if (_PyUnicodeWriter_WriteChar(writer, '-') == -1) - return NULL; - } + if (sign) { + if (_PyUnicodeWriter_WriteChar(writer, '-') == -1) + return NULL; } - if (precision > len) { - fill = precision - len; - if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1) + if (zeropad) { + if (PyUnicode_Fill(writer->buffer, writer->pos, zeropad, '0') == -1) return NULL; - writer->pos += fill; + writer->pos += zeropad; } - if (_PyUnicodeWriter_WriteASCIIString(writer, &buffer[negative], len) < 0) + if (_PyUnicodeWriter_WriteASCIIString(writer, &buffer[sign], len) < 0) return NULL; + + if (spacepad && (flags & F_LJUST)) { + if (PyUnicode_Fill(writer->buffer, writer->pos, spacepad, ' ') == -1) + return NULL; + writer->pos += spacepad; + } break; } case 'p': { - char number[MAX_LONG_LONG_CHARS]; + char number[MAX_INTMAX_CHARS]; len = sprintf(number, "%p", va_arg(*vargs, void*)); assert(len >= 0); @@ -2561,10 +2651,17 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, case 's': { - /* UTF-8 */ - const char *s = va_arg(*vargs, const char*); - if (unicode_fromformat_write_cstr(writer, s, width, precision) < 0) - return NULL; + if (sizemod) { + const wchar_t *s = va_arg(*vargs, const wchar_t*); + if (unicode_fromformat_write_wcstr(writer, s, width, precision, flags) < 0) + return NULL; + } + else { + /* UTF-8 */ + const char *s = va_arg(*vargs, const char*); + if (unicode_fromformat_write_cstr(writer, s, width, precision, flags) < 0) + return NULL; + } break; } @@ -2573,7 +2670,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, PyObject *obj = va_arg(*vargs, PyObject *); assert(obj && _PyUnicode_CHECK(obj)); - if (unicode_fromformat_write_str(writer, obj, width, precision) == -1) + if (unicode_fromformat_write_str(writer, obj, width, precision, flags) == -1) return NULL; break; } @@ -2581,15 +2678,27 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, case 'V': { PyObject *obj = va_arg(*vargs, PyObject *); - const char *str = va_arg(*vargs, const char *); + const char *str; + const wchar_t *wstr; + if (sizemod) { + wstr = va_arg(*vargs, const wchar_t*); + } + else { + str = va_arg(*vargs, const char *); + } if (obj) { assert(_PyUnicode_CHECK(obj)); - if (unicode_fromformat_write_str(writer, obj, width, precision) == -1) + if (unicode_fromformat_write_str(writer, obj, width, precision, flags) == -1) + return NULL; + } + else if (sizemod) { + assert(wstr != NULL); + if (unicode_fromformat_write_wcstr(writer, wstr, width, precision, flags) < 0) return NULL; } else { assert(str != NULL); - if (unicode_fromformat_write_cstr(writer, str, width, precision) < 0) + if (unicode_fromformat_write_cstr(writer, str, width, precision, flags) < 0) return NULL; } break; @@ -2603,7 +2712,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, str = PyObject_Str(obj); if (!str) return NULL; - if (unicode_fromformat_write_str(writer, str, width, precision) == -1) { + if (unicode_fromformat_write_str(writer, str, width, precision, flags) == -1) { Py_DECREF(str); return NULL; } @@ -2619,7 +2728,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, repr = PyObject_Repr(obj); if (!repr) return NULL; - if (unicode_fromformat_write_str(writer, repr, width, precision) == -1) { + if (unicode_fromformat_write_str(writer, repr, width, precision, flags) == -1) { Py_DECREF(repr); return NULL; } @@ -2635,7 +2744,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, ascii = PyObject_ASCII(obj); if (!ascii) return NULL; - if (unicode_fromformat_write_str(writer, ascii, width, precision) == -1) { + if (unicode_fromformat_write_str(writer, ascii, width, precision, flags) == -1) { Py_DECREF(ascii); return NULL; } @@ -2644,6 +2753,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, } default: + invalid_format: PyErr_Format(PyExc_SystemError, "invalid format string: %s", p); return NULL; } diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index fb94fbeac42b..fc4afccbfc40 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1556,14 +1556,11 @@ verify_identifier(struct tok_state *tok) tok->cur = (char *)tok->start + PyBytes_GET_SIZE(s); } Py_DECREF(s); - // PyUnicode_FromFormatV() does not support %X - char hex[9]; - (void)PyOS_snprintf(hex, sizeof(hex), "%04X", ch); if (Py_UNICODE_ISPRINTABLE(ch)) { - syntaxerror(tok, "invalid character '%c' (U+%s)", ch, hex); + syntaxerror(tok, "invalid character '%c' (U+%04X)", ch, ch); } else { - syntaxerror(tok, "invalid non-printable character U+%s", hex); + syntaxerror(tok, "invalid non-printable character U+%04X", ch); } return 0; } @@ -2541,9 +2538,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t } if (!Py_UNICODE_ISPRINTABLE(c)) { - char hex[9]; - (void)PyOS_snprintf(hex, sizeof(hex), "%04X", c); - return MAKE_TOKEN(syntaxerror(tok, "invalid non-printable character U+%s", hex)); + return MAKE_TOKEN(syntaxerror(tok, "invalid non-printable character U+%04X", c)); } if( c == '=' && INSIDE_FSTRING_EXPR(current_tok)) { From webhook-mailer at python.org Sun May 21 19:00:54 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 21 May 2023 23:00:54 -0000 Subject: [Python-checkins] gh-104683: `clinic.py`: Improve coverage for the `parse_converter` method (#104729) Message-ID: <mailman.511.1684710055.13550.python-checkins@python.org> https://github.com/python/cpython/commit/64d1b44a5459605af3e8572d4febfde021315633 commit: 64d1b44a5459605af3e8572d4febfde021315633 branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-21T23:00:47Z summary: gh-104683: `clinic.py`: Improve coverage for the `parse_converter` method (#104729) files: M Lib/test/test_clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index f72cb0442f35..bea730380556 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -774,6 +774,45 @@ def test_legacy_converters(self): module, function = block.signatures self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter) + def test_legacy_converters_non_string_constant_annotation(self): + expected_failure_message = """\ +Error on line 0: +Annotations must be either a name, a function call, or a string. +""" + + s = self.parse_function_should_fail('module os\nos.access\n path: 42') + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail('module os\nos.access\n path: 42.42') + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail('module os\nos.access\n path: 42j') + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail('module os\nos.access\n path: b"42"') + self.assertEqual(s, expected_failure_message) + + def test_other_bizarre_things_in_annotations_fail(self): + expected_failure_message = """\ +Error on line 0: +Annotations must be either a name, a function call, or a string. +""" + + s = self.parse_function_should_fail( + 'module os\nos.access\n path: {"some": "dictionary"}' + ) + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail( + 'module os\nos.access\n path: ["list", "of", "strings"]' + ) + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail( + 'module os\nos.access\n path: (x for x in range(42))' + ) + self.assertEqual(s, expected_failure_message) + def test_unused_param(self): block = self.parse(""" module foo From webhook-mailer at python.org Sun May 21 19:20:27 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 21 May 2023 23:20:27 -0000 Subject: [Python-checkins] gh-104686: Fix tracing for decorated classes (#104708) Message-ID: <mailman.512.1684711228.13550.python-checkins@python.org> https://github.com/python/cpython/commit/cd9748409aa877d6d9905730bf68f25cf7a6a723 commit: cd9748409aa877d6d9905730bf68f25cf7a6a723 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-21T16:20:19-07:00 summary: gh-104686: Fix tracing for decorated classes (#104708) files: M Lib/test/test_sys_settrace.py M Python/compile.c diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 0571919066bb..5603c3cdbf3c 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1524,6 +1524,52 @@ def __init__(self): (3, 'return'), (1, 'return')]) + def test_class_creation_with_decorator(self): + def func(): + def decorator(arg): + def _dec(c): + return c + return _dec + + @decorator(6) + @decorator( + len([8]), + ) + class MyObject: + pass + + self.run_and_compare(func, [ + (0, 'call'), + (1, 'line'), + (6, 'line'), + (1, 'call'), + (2, 'line'), + (4, 'line'), + (4, 'return'), + (7, 'line'), + (8, 'line'), + (7, 'line'), + (1, 'call'), + (2, 'line'), + (4, 'line'), + (4, 'return'), + (10, 'line'), + (6, 'call'), + (6, 'line'), + (11, 'line'), + (11, 'return'), + (7, 'line'), + (2, 'call'), + (3, 'line'), + (3, 'return'), + (6, 'line'), + (2, 'call'), + (3, 'line'), + (3, 'return'), + (10, 'line'), + (10, 'return'), + ]) + @support.cpython_only def test_no_line_event_after_creating_generator(self): # Spurious line events before call events only show up with C tracer diff --git a/Python/compile.c b/Python/compile.c index cfe8224a7e27..e4dc9729b694 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2486,6 +2486,10 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) } /* 2. load the 'build_class' function */ + + // these instructions should be attributed to the class line, + // not a decorator line + loc = LOC(s); ADDOP(c, loc, PUSH_NULL); ADDOP(c, loc, LOAD_BUILD_CLASS); From webhook-mailer at python.org Sun May 21 19:29:50 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 21 May 2023 23:29:50 -0000 Subject: [Python-checkins] gh-104683: clinic.py: Modernise `parse_converter()` using pattern-matching (#104696) Message-ID: <mailman.513.1684711791.13550.python-checkins@python.org> https://github.com/python/cpython/commit/4b107d86f38f6778562d4fe5e1d881b52c9d9d6c commit: 4b107d86f38f6778562d4fe5e1d881b52c9d9d6c branch: main author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-21T23:29:43Z summary: gh-104683: clinic.py: Modernise `parse_converter()` using pattern-matching (#104696) files: M Tools/clinic/clinic.py diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 1d7b778da709..d182e5e7764e 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -5016,22 +5016,26 @@ def bad_node(self, node): key = f"{parameter_name}_as_{c_name}" if c_name else parameter_name self.function.parameters[key] = p - def parse_converter(self, annotation): - if (isinstance(annotation, ast.Constant) and - type(annotation.value) is str): - return annotation.value, True, {} + KwargDict = dict[str | None, Any] - if isinstance(annotation, ast.Name): - return annotation.id, False, {} - - if not isinstance(annotation, ast.Call): - fail("Annotations must be either a name, a function call, or a string.") - - name = annotation.func.id - symbols = globals() - - kwargs = {node.arg: eval_ast_expr(node.value, symbols) for node in annotation.keywords} - return name, False, kwargs + @staticmethod + def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]: + match annotation: + case ast.Constant(value=str() as value): + return value, True, {} + case ast.Name(name): + return name, False, {} + case ast.Call(func=ast.Name(name)): + symbols = globals() + kwargs = { + node.arg: eval_ast_expr(node.value, symbols) + for node in annotation.keywords + } + return name, False, kwargs + case _: + fail( + "Annotations must be either a name, a function call, or a string." + ) def parse_special_symbol(self, symbol): if symbol == '*': From webhook-mailer at python.org Sun May 21 19:48:40 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 21 May 2023 23:48:40 -0000 Subject: [Python-checkins] [3.11] gh-104683: `clinic.py`: Improve coverage for the `parse_converter` method (#104729) (#104730) Message-ID: <mailman.514.1684712922.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d691de1d2d16724be75e8ae67ef6b7101e000a2d commit: d691de1d2d16724be75e8ae67ef6b7101e000a2d branch: 3.11 author: Alex Waygood <Alex.Waygood at Gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-21T23:48:25Z summary: [3.11] gh-104683: `clinic.py`: Improve coverage for the `parse_converter` method (#104729) (#104730) files: M Lib/test/test_clinic.py diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 02a54bf154ee..8d4f92fa310c 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -773,6 +773,45 @@ def test_legacy_converters(self): module, function = block.signatures self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter) + def test_legacy_converters_non_string_constant_annotation(self): + expected_failure_message = """\ +Error on line 0: +Annotations must be either a name, a function call, or a string. +""" + + s = self.parse_function_should_fail('module os\nos.access\n path: 42') + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail('module os\nos.access\n path: 42.42') + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail('module os\nos.access\n path: 42j') + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail('module os\nos.access\n path: b"42"') + self.assertEqual(s, expected_failure_message) + + def test_other_bizarre_things_in_annotations_fail(self): + expected_failure_message = """\ +Error on line 0: +Annotations must be either a name, a function call, or a string. +""" + + s = self.parse_function_should_fail( + 'module os\nos.access\n path: {"some": "dictionary"}' + ) + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail( + 'module os\nos.access\n path: ["list", "of", "strings"]' + ) + self.assertEqual(s, expected_failure_message) + + s = self.parse_function_should_fail( + 'module os\nos.access\n path: (x for x in range(42))' + ) + self.assertEqual(s, expected_failure_message) + def parse(self, text): c = FakeClinic() parser = DSLParser(c) From webhook-mailer at python.org Sun May 21 20:29:11 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 22 May 2023 00:29:11 -0000 Subject: [Python-checkins] gh-102856: Tokenize performance improvement (#104731) Message-ID: <mailman.515.1684715352.13550.python-checkins@python.org> https://github.com/python/cpython/commit/8817886ae571f5b5ce4e2e6cfd2458622d0efac1 commit: 8817886ae571f5b5ce4e2e6cfd2458622d0efac1 branch: main author: Marta G?mez Mac?as <mgmacias at google.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-22T00:29:04Z summary: gh-102856: Tokenize performance improvement (#104731) files: M Lib/tokenize.py M Python/Python-tokenize.c diff --git a/Lib/tokenize.py b/Lib/tokenize.py index cef2773feac2..911f0f12f9bb 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -449,16 +449,6 @@ def _tokenize(rl_gen, encoding): source = b"".join(rl_gen).decode(encoding) token = None for token in _generate_tokens_from_c_tokenizer(source, extra_tokens=True): - # TODO: Marta -> limpiar esto - if 6 < token.type <= 54: - token = token._replace(type=OP) - if token.type in {ASYNC, AWAIT}: - token = token._replace(type=NAME) - if token.type == NEWLINE: - l_start, c_start = token.start - l_end, c_end = token.end - token = token._replace(string='\n', start=(l_start, c_start), end=(l_end, c_end+1)) - yield token if token is not None: last_line, _ = token.start @@ -550,8 +540,7 @@ def _generate_tokens_from_c_tokenizer(source, extra_tokens=False): """Tokenize a source reading Python code as unicode strings using the internal C tokenizer""" import _tokenize as c_tokenizer for info in c_tokenizer.TokenizerIter(source, extra_tokens=extra_tokens): - tok, type, lineno, end_lineno, col_off, end_col_off, line = info - yield TokenInfo(type, tok, (lineno, col_off), (end_lineno, end_col_off), line) + yield TokenInfo._make(info) if __name__ == "__main__": diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index ece238672e34..43b44be94583 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -207,7 +207,22 @@ tokenizeriter_next(tokenizeriterobject *it) end_col_offset = _PyPegen_byte_offset_to_character_offset(line, token.end - it->tok->line_start); } - result = Py_BuildValue("(NinnnnN)", str, type, lineno, end_lineno, col_offset, end_col_offset, line); + if (it->tok->tok_extra_tokens) { + // Necessary adjustments to match the original Python tokenize + // implementation + if (type > DEDENT && type < OP) { + type = OP; + } + else if (type == ASYNC || type == AWAIT) { + type = NAME; + } + else if (type == NEWLINE) { + str = PyUnicode_FromString("\n"); + end_col_offset++; + } + } + + result = Py_BuildValue("(iN(nn)(nn)N)", type, str, lineno, col_offset, end_lineno, end_col_offset, line); exit: _PyToken_Free(&token); return result; From webhook-mailer at python.org Sun May 21 20:44:55 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Mon, 22 May 2023 00:44:55 -0000 Subject: [Python-checkins] GH-103092: isolate `_ssl` (#104725) Message-ID: <mailman.516.1684716296.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b9c807a260f63284f16e25b5e98e18191f61a05f commit: b9c807a260f63284f16e25b5e98e18191f61a05f branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-05-22T06:14:48+05:30 summary: GH-103092: isolate `_ssl` (#104725) files: M Modules/_ssl.c M Modules/_ssl.h M Modules/_ssl/debughelpers.c diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 5bf6b3bc19b2..59fd401cac27 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -6150,6 +6150,18 @@ sslmodule_init_strings(PyObject *module) return 0; } +static int +sslmodule_init_lock(PyObject *module) +{ + _sslmodulestate *state = get_ssl_state(module); + state->keylog_lock = PyThread_allocate_lock(); + if (state->keylog_lock == NULL) { + PyErr_NoMemory(); + return -1; + } + return 0; +} + static PyModuleDef_Slot sslmodule_slots[] = { {Py_mod_exec, sslmodule_init_types}, {Py_mod_exec, sslmodule_init_exceptions}, @@ -6158,9 +6170,8 @@ static PyModuleDef_Slot sslmodule_slots[] = { {Py_mod_exec, sslmodule_init_constants}, {Py_mod_exec, sslmodule_init_versioninfo}, {Py_mod_exec, sslmodule_init_strings}, - // XXX gh-103092: fix isolation. - {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, - //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_exec, sslmodule_init_lock}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; @@ -6219,6 +6230,8 @@ static void sslmodule_free(void *m) { sslmodule_clear((PyObject *)m); + _sslmodulestate *state = get_ssl_state(m); + PyThread_free_lock(state->keylog_lock); } static struct PyModuleDef _sslmodule_def = { diff --git a/Modules/_ssl.h b/Modules/_ssl.h index c1da8b46b536..22d93ddcc6d6 100644 --- a/Modules/_ssl.h +++ b/Modules/_ssl.h @@ -33,6 +33,8 @@ typedef struct { PyObject *str_reason; PyObject *str_verify_code; PyObject *str_verify_message; + /* keylog lock */ + PyThread_type_lock keylog_lock; } _sslmodulestate; static struct PyModuleDef _sslmodule_def; diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index 217f22494255..a81f0aad05a8 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -118,30 +118,22 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) PyGILState_STATE threadstate; PySSLSocket *ssl_obj = NULL; /* ssl._SSLSocket, borrowed ref */ int res, e; - static PyThread_type_lock *lock = NULL; threadstate = PyGILState_Ensure(); ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl); assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type)); + PyThread_type_lock lock = get_state_sock(ssl_obj)->keylog_lock; + assert(lock != NULL); if (ssl_obj->ctx->keylog_bio == NULL) { return; } - - /* Allocate a static lock to synchronize writes to keylog file. + /* * The lock is neither released on exit nor on fork(). The lock is * also shared between all SSLContexts although contexts may write to * their own files. IMHO that's good enough for a non-performance * critical debug helper. */ - if (lock == NULL) { - lock = PyThread_allocate_lock(); - if (lock == NULL) { - PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - ssl_obj->exc = PyErr_GetRaisedException(); - return; - } - } PySSL_BEGIN_ALLOW_THREADS PyThread_acquire_lock(lock, 1); From webhook-mailer at python.org Sun May 21 23:49:13 2023 From: webhook-mailer at python.org (gpshead) Date: Mon, 22 May 2023 03:49:13 -0000 Subject: [Python-checkins] gh-104536: Improve `multiprocessing.process._cleanup` logic (#104537) Message-ID: <mailman.517.1684727353.13550.python-checkins@python.org> https://github.com/python/cpython/commit/ef5d00a59207a63c6d5ae0d5d44054847d1bf3b5 commit: ef5d00a59207a63c6d5ae0d5d44054847d1bf3b5 branch: main author: Luccccifer <lukezhang764 at gmail.com> committer: gpshead <greg at krypto.org> date: 2023-05-22T03:48:57Z summary: gh-104536: Improve `multiprocessing.process._cleanup` logic (#104537) Fix a race condition in the internal `multiprocessing.process` cleanup logic that could manifest as an unintended `AttributeError` when calling `BaseProcess.close()`. --------- Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst M Lib/multiprocessing/process.py diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index c03c859baa79..271ba3fd3251 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -61,7 +61,7 @@ def parent_process(): def _cleanup(): # check for processes which have finished for p in list(_children): - if p._popen.poll() is not None: + if (child_popen := p._popen) and child_popen.poll() is not None: _children.discard(p) # diff --git a/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst b/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst new file mode 100644 index 000000000000..b0f5d78f7e61 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst @@ -0,0 +1,3 @@ +Fix a race condition in the internal :mod:`multiprocessing.process` cleanup +logic that could manifest as an unintended ``AttributeError`` when calling +``process.close()``. From webhook-mailer at python.org Mon May 22 00:25:16 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 22 May 2023 04:25:16 -0000 Subject: [Python-checkins] gh-104656: Rename typeparams AST node to type_params (#104657) Message-ID: <mailman.518.1684729517.13550.python-checkins@python.org> https://github.com/python/cpython/commit/a5f244d627a6815cf2d8ccec836b9b52eb3e8de2 commit: a5f244d627a6815cf2d8ccec836b9b52eb3e8de2 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-21T21:25:09-07:00 summary: gh-104656: Rename typeparams AST node to type_params (#104657) files: M Doc/library/ast.rst M Grammar/python.gram M Include/internal/pycore_ast.h M Include/internal/pycore_ast_state.h M Lib/ast.py M Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst M Parser/Python.asdl M Parser/action_helpers.c M Parser/parser.c M Python/Python-ast.c M Python/ast.c M Python/ast_opt.c M Python/compile.c M Python/symtable.c diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index eb6a973cac62..b6b1e076c9f0 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1724,7 +1724,7 @@ Function and class definitions body=[ FunctionDef( name='f', - typeparams=[], + type_params=[], args=arguments( posonlyargs=[], args=[ @@ -1848,7 +1848,7 @@ Function and class definitions body=[ ClassDef( name='Foo', - typeparams=[], + type_params=[], bases=[ Name(id='base1', ctx=Load()), Name(id='base2', ctx=Load())], @@ -1887,7 +1887,7 @@ Async and await body=[ AsyncFunctionDef( name='f', - typeparams=[], + type_params=[], args=arguments( posonlyargs=[], args=[], diff --git a/Grammar/python.gram b/Grammar/python.gram index c79207b9cb51..e6a983429e39 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -640,12 +640,12 @@ type_alias[stmt_ty]: # Type parameter declaration # -------------------------- -type_params[asdl_typeparam_seq*]: '[' t=type_param_seq ']' { - CHECK_VERSION(asdl_typeparam_seq *, 12, "Type parameter lists are", t) } +type_params[asdl_type_param_seq*]: '[' t=type_param_seq ']' { + CHECK_VERSION(asdl_type_param_seq *, 12, "Type parameter lists are", t) } -type_param_seq[asdl_typeparam_seq*]: a[asdl_typeparam_seq*]=','.type_param+ [','] { a } +type_param_seq[asdl_type_param_seq*]: a[asdl_type_param_seq*]=','.type_param+ [','] { a } -type_param[typeparam_ty] (memo): +type_param[type_param_ty] (memo): | a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) } | '*' a=NAME colon=":" e=expression { RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind diff --git a/Include/internal/pycore_ast.h b/Include/internal/pycore_ast.h index 9f1cef054150..06a40239a247 100644 --- a/Include/internal/pycore_ast.h +++ b/Include/internal/pycore_ast.h @@ -51,7 +51,7 @@ typedef struct _pattern *pattern_ty; typedef struct _type_ignore *type_ignore_ty; -typedef struct _typeparam *typeparam_ty; +typedef struct _type_param *type_param_ty; typedef struct { @@ -151,10 +151,11 @@ asdl_type_ignore_seq *_Py_asdl_type_ignore_seq_new(Py_ssize_t size, PyArena typedef struct { _ASDL_SEQ_HEAD - typeparam_ty typed_elements[1]; -} asdl_typeparam_seq; + type_param_ty typed_elements[1]; +} asdl_type_param_seq; -asdl_typeparam_seq *_Py_asdl_typeparam_seq_new(Py_ssize_t size, PyArena *arena); +asdl_type_param_seq *_Py_asdl_type_param_seq_new(Py_ssize_t size, PyArena + *arena); enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, @@ -197,7 +198,7 @@ struct _stmt { union { struct { identifier name; - asdl_typeparam_seq *typeparams; + asdl_type_param_seq *type_params; arguments_ty args; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; @@ -207,7 +208,7 @@ struct _stmt { struct { identifier name; - asdl_typeparam_seq *typeparams; + asdl_type_param_seq *type_params; arguments_ty args; asdl_stmt_seq *body; asdl_expr_seq *decorator_list; @@ -217,7 +218,7 @@ struct _stmt { struct { identifier name; - asdl_typeparam_seq *typeparams; + asdl_type_param_seq *type_params; asdl_expr_seq *bases; asdl_keyword_seq *keywords; asdl_stmt_seq *body; @@ -240,7 +241,7 @@ struct _stmt { struct { expr_ty name; - asdl_typeparam_seq *typeparams; + asdl_type_param_seq *type_params; expr_ty value; } TypeAlias; @@ -649,9 +650,9 @@ struct _type_ignore { } v; }; -enum _typeparam_kind {TypeVar_kind=1, ParamSpec_kind=2, TypeVarTuple_kind=3}; -struct _typeparam { - enum _typeparam_kind kind; +enum _type_param_kind {TypeVar_kind=1, ParamSpec_kind=2, TypeVarTuple_kind=3}; +struct _type_param { + enum _type_param_kind kind; union { struct { identifier name; @@ -681,18 +682,18 @@ mod_ty _PyAST_Interactive(asdl_stmt_seq * body, PyArena *arena); mod_ty _PyAST_Expression(expr_ty body, PyArena *arena); mod_ty _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena); -stmt_ty _PyAST_FunctionDef(identifier name, asdl_typeparam_seq * typeparams, +stmt_ty _PyAST_FunctionDef(identifier name, asdl_type_param_seq * type_params, arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, expr_ty returns, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); -stmt_ty _PyAST_AsyncFunctionDef(identifier name, asdl_typeparam_seq * - typeparams, arguments_ty args, asdl_stmt_seq * +stmt_ty _PyAST_AsyncFunctionDef(identifier name, asdl_type_param_seq * + type_params, arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, expr_ty returns, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); -stmt_ty _PyAST_ClassDef(identifier name, asdl_typeparam_seq * typeparams, +stmt_ty _PyAST_ClassDef(identifier name, asdl_type_param_seq * type_params, asdl_expr_seq * bases, asdl_keyword_seq * keywords, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, int lineno, int col_offset, int end_lineno, int @@ -704,9 +705,9 @@ stmt_ty _PyAST_Delete(asdl_expr_seq * targets, int lineno, int col_offset, int stmt_ty _PyAST_Assign(asdl_expr_seq * targets, expr_ty value, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); -stmt_ty _PyAST_TypeAlias(expr_ty name, asdl_typeparam_seq * typeparams, expr_ty - value, int lineno, int col_offset, int end_lineno, int - end_col_offset, PyArena *arena); +stmt_ty _PyAST_TypeAlias(expr_ty name, asdl_type_param_seq * type_params, + expr_ty value, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); stmt_ty _PyAST_AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); @@ -891,14 +892,14 @@ pattern_ty _PyAST_MatchOr(asdl_pattern_seq * patterns, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena); type_ignore_ty _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena); -typeparam_ty _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int - col_offset, int end_lineno, int end_col_offset, - PyArena *arena); -typeparam_ty _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena); -typeparam_ty _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, - int end_lineno, int end_col_offset, PyArena - *arena); +type_param_ty _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int + col_offset, int end_lineno, int end_col_offset, + PyArena *arena); +type_param_ty _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int + end_lineno, int end_col_offset, PyArena *arena); +type_param_ty _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, + int end_lineno, int end_col_offset, PyArena + *arena); PyObject* PyAST_mod2obj(mod_ty t); diff --git a/Include/internal/pycore_ast_state.h b/Include/internal/pycore_ast_state.h index e723ead577b8..0c0d53f3e5d7 100644 --- a/Include/internal/pycore_ast_state.h +++ b/Include/internal/pycore_ast_state.h @@ -248,8 +248,8 @@ struct ast_state { PyObject *type_comment; PyObject *type_ignore_type; PyObject *type_ignores; - PyObject *typeparam_type; - PyObject *typeparams; + PyObject *type_param_type; + PyObject *type_params; PyObject *unaryop_type; PyObject *upper; PyObject *value; diff --git a/Lib/ast.py b/Lib/ast.py index 08904afb2031..226910ecac0b 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1051,7 +1051,7 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) - self._typeparams_helper(node.typeparams) + self._type_params_helper(node.type_params) with self.delimit_if("(", ")", condition = node.bases or node.keywords): comma = False for e in node.bases: @@ -1083,7 +1083,7 @@ def _function_helper(self, node, fill_suffix): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) - self._typeparams_helper(node.typeparams) + self._type_params_helper(node.type_params) with self.delimit("(", ")"): self.traverse(node.args) if node.returns: @@ -1092,10 +1092,10 @@ def _function_helper(self, node, fill_suffix): with self.block(extra=self.get_type_comment(node)): self._write_docstring_and_traverse_body(node) - def _typeparams_helper(self, typeparams): - if typeparams is not None and len(typeparams) > 0: + def _type_params_helper(self, type_params): + if type_params is not None and len(type_params) > 0: with self.delimit("[", "]"): - self.interleave(lambda: self.write(", "), self.traverse, typeparams) + self.interleave(lambda: self.write(", "), self.traverse, type_params) def visit_TypeVar(self, node): self.write(node.name) @@ -1112,7 +1112,7 @@ def visit_ParamSpec(self, node): def visit_TypeAlias(self, node): self.fill("type ") self.traverse(node.name) - self._typeparams_helper(node.typeparams) + self._type_params_helper(node.type_params) self.write(" = ") self.traverse(node.value) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst index cefe6429ab20..cb8d25650126 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst @@ -8,7 +8,7 @@ attribute. This is implemented as a new AST node ``ast.TypeAlias``. New syntax (``class X[T]: ...``, ``def func[T](): ...``) is added for defining generic functions and classes. This is implemented as a new -``typeparams`` attribute on the AST nodes for classes and functions. +``type_params`` attribute on the AST nodes for classes and functions. This node holds instances of the new AST classes ``ast.TypeVar``, ``ast.ParamSpec``, and ``ast.TypeVarTuple``. diff --git a/Parser/Python.asdl b/Parser/Python.asdl index cfc41ef45b56..dc2eb802b043 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -8,15 +8,15 @@ module Python | Expression(expr body) | FunctionType(expr* argtypes, expr returns) - stmt = FunctionDef(identifier name, typeparam* typeparams, arguments args, + stmt = FunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment) - | AsyncFunctionDef(identifier name, typeparam* typeparams, arguments args, + | AsyncFunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment) | ClassDef(identifier name, - typeparam* typeparams, + type_param* type_params, expr* bases, keyword* keywords, stmt* body, @@ -25,7 +25,7 @@ module Python | Delete(expr* targets) | Assign(expr* targets, expr value, string? type_comment) - | TypeAlias(expr name, typeparam* typeparams, expr value) + | TypeAlias(expr name, type_param* type_params, expr value) | AugAssign(expr target, operator op, expr value) -- 'simple' indicates that we annotate simple name without parens | AnnAssign(expr target, expr annotation, expr? value, int simple) @@ -145,8 +145,8 @@ module Python type_ignore = TypeIgnore(int lineno, string tag) - typeparam = TypeVar(identifier name, expr? bound) - | ParamSpec(identifier name) - | TypeVarTuple(identifier name) - attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) + type_param = TypeVar(identifier name, expr? bound) + | ParamSpec(identifier name) + | TypeVarTuple(identifier name) + attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) } diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 0134e6f16ba8..06d77b64cacb 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -752,7 +752,7 @@ _PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty f assert(function_def != NULL); if (function_def->kind == AsyncFunctionDef_kind) { return _PyAST_AsyncFunctionDef( - function_def->v.FunctionDef.name, function_def->v.FunctionDef.typeparams, + function_def->v.FunctionDef.name, function_def->v.FunctionDef.type_params, function_def->v.FunctionDef.args, function_def->v.FunctionDef.body, decorators, function_def->v.FunctionDef.returns, function_def->v.FunctionDef.type_comment, function_def->lineno, @@ -761,7 +761,7 @@ _PyPegen_function_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty f } return _PyAST_FunctionDef( - function_def->v.FunctionDef.name, function_def->v.FunctionDef.typeparams, + function_def->v.FunctionDef.name, function_def->v.FunctionDef.type_params, function_def->v.FunctionDef.args, function_def->v.FunctionDef.body, decorators, function_def->v.FunctionDef.returns, @@ -776,7 +776,7 @@ _PyPegen_class_def_decorators(Parser *p, asdl_expr_seq *decorators, stmt_ty clas { assert(class_def != NULL); return _PyAST_ClassDef( - class_def->v.ClassDef.name, class_def->v.ClassDef.typeparams, + class_def->v.ClassDef.name, class_def->v.ClassDef.type_params, class_def->v.ClassDef.bases, class_def->v.ClassDef.keywords, class_def->v.ClassDef.body, decorators, class_def->lineno, class_def->col_offset, class_def->end_lineno, diff --git a/Parser/parser.c b/Parser/parser.c index 894846714eff..fc5466fea2b3 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -696,9 +696,9 @@ static asdl_pattern_seq* positional_patterns_rule(Parser *p); static asdl_seq* keyword_patterns_rule(Parser *p); static KeyPatternPair* keyword_pattern_rule(Parser *p); static stmt_ty type_alias_rule(Parser *p); -static asdl_typeparam_seq* type_params_rule(Parser *p); -static asdl_typeparam_seq* type_param_seq_rule(Parser *p); -static typeparam_ty type_param_rule(Parser *p); +static asdl_type_param_seq* type_params_rule(Parser *p); +static asdl_type_param_seq* type_param_seq_rule(Parser *p); +static type_param_ty type_param_rule(Parser *p); static expr_ty type_param_bound_rule(Parser *p); static expr_ty expressions_rule(Parser *p); static expr_ty expression_rule(Parser *p); @@ -10653,7 +10653,7 @@ type_alias_rule(Parser *p) } // type_params: '[' type_param_seq ']' -static asdl_typeparam_seq* +static asdl_type_param_seq* type_params_rule(Parser *p) { if (p->level++ == MAXSTACK) { @@ -10664,7 +10664,7 @@ type_params_rule(Parser *p) p->level--; return NULL; } - asdl_typeparam_seq* _res = NULL; + asdl_type_param_seq* _res = NULL; int _mark = p->mark; { // '[' type_param_seq ']' if (p->error_indicator) { @@ -10674,7 +10674,7 @@ type_params_rule(Parser *p) D(fprintf(stderr, "%*c> type_params[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' type_param_seq ']'")); Token * _literal; Token * _literal_1; - asdl_typeparam_seq* t; + asdl_type_param_seq* t; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' && @@ -10684,7 +10684,7 @@ type_params_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ type_params[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' type_param_seq ']'")); - _res = CHECK_VERSION ( asdl_typeparam_seq* , 12 , "Type parameter lists are" , t ); + _res = CHECK_VERSION ( asdl_type_param_seq* , 12 , "Type parameter lists are" , t ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -10703,7 +10703,7 @@ type_params_rule(Parser *p) } // type_param_seq: ','.type_param+ ','? -static asdl_typeparam_seq* +static asdl_type_param_seq* type_param_seq_rule(Parser *p) { if (p->level++ == MAXSTACK) { @@ -10714,7 +10714,7 @@ type_param_seq_rule(Parser *p) p->level--; return NULL; } - asdl_typeparam_seq* _res = NULL; + asdl_type_param_seq* _res = NULL; int _mark = p->mark; { // ','.type_param+ ','? if (p->error_indicator) { @@ -10724,9 +10724,9 @@ type_param_seq_rule(Parser *p) D(fprintf(stderr, "%*c> type_param_seq[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.type_param+ ','?")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - asdl_typeparam_seq* a; + asdl_type_param_seq* a; if ( - (a = (asdl_typeparam_seq*)_gather_81_rule(p)) // ','.type_param+ + (a = (asdl_type_param_seq*)_gather_81_rule(p)) // ','.type_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -10756,7 +10756,7 @@ type_param_seq_rule(Parser *p) // | '*' NAME // | '**' NAME ":" expression // | '**' NAME -static typeparam_ty +static type_param_ty type_param_rule(Parser *p) { if (p->level++ == MAXSTACK) { @@ -10767,7 +10767,7 @@ type_param_rule(Parser *p) p->level--; return NULL; } - typeparam_ty _res = NULL; + type_param_ty _res = NULL; if (_PyPegen_is_memoized(p, type_param_type, &_res)) { p->level--; return _res; @@ -30199,7 +30199,7 @@ _loop0_82_rule(Parser *p) } D(fprintf(stderr, "%*c> _loop0_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param")); Token * _literal; - typeparam_ty elem; + type_param_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -30266,7 +30266,7 @@ _gather_81_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _gather_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82")); - typeparam_ty elem; + type_param_ty elem; asdl_seq * seq; if ( (elem = type_param_rule(p)) // type_param diff --git a/Python/Python-ast.c b/Python/Python-ast.c index d62cccbb6e24..87906d975d74 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -261,8 +261,8 @@ void _PyAST_Fini(PyInterpreterState *interp) Py_CLEAR(state->type_comment); Py_CLEAR(state->type_ignore_type); Py_CLEAR(state->type_ignores); - Py_CLEAR(state->typeparam_type); - Py_CLEAR(state->typeparams); + Py_CLEAR(state->type_param_type); + Py_CLEAR(state->type_params); Py_CLEAR(state->unaryop_type); Py_CLEAR(state->upper); Py_CLEAR(state->value); @@ -362,7 +362,7 @@ static int init_identifiers(struct ast_state *state) if ((state->type = PyUnicode_InternFromString("type")) == NULL) return 0; if ((state->type_comment = PyUnicode_InternFromString("type_comment")) == NULL) return 0; if ((state->type_ignores = PyUnicode_InternFromString("type_ignores")) == NULL) return 0; - if ((state->typeparams = PyUnicode_InternFromString("typeparams")) == NULL) return 0; + if ((state->type_params = PyUnicode_InternFromString("type_params")) == NULL) return 0; if ((state->upper = PyUnicode_InternFromString("upper")) == NULL) return 0; if ((state->value = PyUnicode_InternFromString("value")) == NULL) return 0; if ((state->values = PyUnicode_InternFromString("values")) == NULL) return 0; @@ -383,7 +383,7 @@ GENERATE_ASDL_SEQ_CONSTRUCTOR(withitem, withitem_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(match_case, match_case_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(pattern, pattern_ty) GENERATE_ASDL_SEQ_CONSTRUCTOR(type_ignore, type_ignore_ty) -GENERATE_ASDL_SEQ_CONSTRUCTOR(typeparam, typeparam_ty) +GENERATE_ASDL_SEQ_CONSTRUCTOR(type_param, type_param_ty) static PyObject* ast2obj_mod(struct ast_state *state, void*); static const char * const Module_fields[]={ @@ -409,7 +409,7 @@ static const char * const stmt_attributes[] = { static PyObject* ast2obj_stmt(struct ast_state *state, void*); static const char * const FunctionDef_fields[]={ "name", - "typeparams", + "type_params", "args", "body", "decorator_list", @@ -418,7 +418,7 @@ static const char * const FunctionDef_fields[]={ }; static const char * const AsyncFunctionDef_fields[]={ "name", - "typeparams", + "type_params", "args", "body", "decorator_list", @@ -427,7 +427,7 @@ static const char * const AsyncFunctionDef_fields[]={ }; static const char * const ClassDef_fields[]={ "name", - "typeparams", + "type_params", "bases", "keywords", "body", @@ -446,7 +446,7 @@ static const char * const Assign_fields[]={ }; static const char * const TypeAlias_fields[]={ "name", - "typeparams", + "type_params", "value", }; static const char * const AugAssign_fields[]={ @@ -775,13 +775,13 @@ static const char * const TypeIgnore_fields[]={ "lineno", "tag", }; -static const char * const typeparam_attributes[] = { +static const char * const type_param_attributes[] = { "lineno", "col_offset", "end_lineno", "end_col_offset", }; -static PyObject* ast2obj_typeparam(struct ast_state *state, void*); +static PyObject* ast2obj_type_param(struct ast_state *state, void*); static const char * const TypeVar_fields[]={ "name", "bound", @@ -1169,13 +1169,13 @@ init_types(struct ast_state *state) "FunctionType(expr* argtypes, expr returns)"); if (!state->FunctionType_type) return 0; state->stmt_type = make_type(state, "stmt", state->AST_type, NULL, 0, - "stmt = FunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" - " | AsyncFunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" - " | ClassDef(identifier name, typeparam* typeparams, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)\n" + "stmt = FunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" + " | AsyncFunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)\n" + " | ClassDef(identifier name, type_param* type_params, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)\n" " | Return(expr? value)\n" " | Delete(expr* targets)\n" " | Assign(expr* targets, expr value, string? type_comment)\n" - " | TypeAlias(expr name, typeparam* typeparams, expr value)\n" + " | TypeAlias(expr name, type_param* type_params, expr value)\n" " | AugAssign(expr target, operator op, expr value)\n" " | AnnAssign(expr target, expr annotation, expr? value, int simple)\n" " | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment)\n" @@ -1206,7 +1206,7 @@ init_types(struct ast_state *state) return 0; state->FunctionDef_type = make_type(state, "FunctionDef", state->stmt_type, FunctionDef_fields, 7, - "FunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); + "FunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); if (!state->FunctionDef_type) return 0; if (PyObject_SetAttr(state->FunctionDef_type, state->returns, Py_None) == -1) @@ -1217,7 +1217,7 @@ init_types(struct ast_state *state) state->AsyncFunctionDef_type = make_type(state, "AsyncFunctionDef", state->stmt_type, AsyncFunctionDef_fields, 7, - "AsyncFunctionDef(identifier name, typeparam* typeparams, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); + "AsyncFunctionDef(identifier name, type_param* type_params, arguments args, stmt* body, expr* decorator_list, expr? returns, string? type_comment)"); if (!state->AsyncFunctionDef_type) return 0; if (PyObject_SetAttr(state->AsyncFunctionDef_type, state->returns, Py_None) == -1) @@ -1227,7 +1227,7 @@ init_types(struct ast_state *state) return 0; state->ClassDef_type = make_type(state, "ClassDef", state->stmt_type, ClassDef_fields, 6, - "ClassDef(identifier name, typeparam* typeparams, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)"); + "ClassDef(identifier name, type_param* type_params, expr* bases, keyword* keywords, stmt* body, expr* decorator_list)"); if (!state->ClassDef_type) return 0; state->Return_type = make_type(state, "Return", state->stmt_type, Return_fields, 1, @@ -1248,7 +1248,7 @@ init_types(struct ast_state *state) return 0; state->TypeAlias_type = make_type(state, "TypeAlias", state->stmt_type, TypeAlias_fields, 3, - "TypeAlias(expr name, typeparam* typeparams, expr value)"); + "TypeAlias(expr name, type_param* type_params, expr value)"); if (!state->TypeAlias_type) return 0; state->AugAssign_type = make_type(state, "AugAssign", state->stmt_type, AugAssign_fields, 3, @@ -1894,33 +1894,33 @@ init_types(struct ast_state *state) TypeIgnore_fields, 2, "TypeIgnore(int lineno, string tag)"); if (!state->TypeIgnore_type) return 0; - state->typeparam_type = make_type(state, "typeparam", state->AST_type, - NULL, 0, - "typeparam = TypeVar(identifier name, expr? bound)\n" - " | ParamSpec(identifier name)\n" - " | TypeVarTuple(identifier name)"); - if (!state->typeparam_type) return 0; - if (!add_attributes(state, state->typeparam_type, typeparam_attributes, 4)) - return 0; - if (PyObject_SetAttr(state->typeparam_type, state->end_lineno, Py_None) == + state->type_param_type = make_type(state, "type_param", state->AST_type, + NULL, 0, + "type_param = TypeVar(identifier name, expr? bound)\n" + " | ParamSpec(identifier name)\n" + " | TypeVarTuple(identifier name)"); + if (!state->type_param_type) return 0; + if (!add_attributes(state, state->type_param_type, type_param_attributes, + 4)) return 0; + if (PyObject_SetAttr(state->type_param_type, state->end_lineno, Py_None) == -1) return 0; - if (PyObject_SetAttr(state->typeparam_type, state->end_col_offset, Py_None) - == -1) + if (PyObject_SetAttr(state->type_param_type, state->end_col_offset, + Py_None) == -1) return 0; - state->TypeVar_type = make_type(state, "TypeVar", state->typeparam_type, + state->TypeVar_type = make_type(state, "TypeVar", state->type_param_type, TypeVar_fields, 2, "TypeVar(identifier name, expr? bound)"); if (!state->TypeVar_type) return 0; if (PyObject_SetAttr(state->TypeVar_type, state->bound, Py_None) == -1) return 0; state->ParamSpec_type = make_type(state, "ParamSpec", - state->typeparam_type, ParamSpec_fields, + state->type_param_type, ParamSpec_fields, 1, "ParamSpec(identifier name)"); if (!state->ParamSpec_type) return 0; state->TypeVarTuple_type = make_type(state, "TypeVarTuple", - state->typeparam_type, + state->type_param_type, TypeVarTuple_fields, 1, "TypeVarTuple(identifier name)"); if (!state->TypeVarTuple_type) return 0; @@ -1967,8 +1967,8 @@ static int obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, PyArena* arena); static int obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* out, PyArena* arena); -static int obj2ast_typeparam(struct ast_state *state, PyObject* obj, - typeparam_ty* out, PyArena* arena); +static int obj2ast_type_param(struct ast_state *state, PyObject* obj, + type_param_ty* out, PyArena* arena); mod_ty _PyAST_Module(asdl_stmt_seq * body, asdl_type_ignore_seq * type_ignores, @@ -2032,7 +2032,7 @@ _PyAST_FunctionType(asdl_expr_seq * argtypes, expr_ty returns, PyArena *arena) } stmt_ty -_PyAST_FunctionDef(identifier name, asdl_typeparam_seq * typeparams, +_PyAST_FunctionDef(identifier name, asdl_type_param_seq * type_params, arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, expr_ty returns, string type_comment, int lineno, int col_offset, int end_lineno, int end_col_offset, @@ -2054,7 +2054,7 @@ _PyAST_FunctionDef(identifier name, asdl_typeparam_seq * typeparams, return NULL; p->kind = FunctionDef_kind; p->v.FunctionDef.name = name; - p->v.FunctionDef.typeparams = typeparams; + p->v.FunctionDef.type_params = type_params; p->v.FunctionDef.args = args; p->v.FunctionDef.body = body; p->v.FunctionDef.decorator_list = decorator_list; @@ -2068,7 +2068,7 @@ _PyAST_FunctionDef(identifier name, asdl_typeparam_seq * typeparams, } stmt_ty -_PyAST_AsyncFunctionDef(identifier name, asdl_typeparam_seq * typeparams, +_PyAST_AsyncFunctionDef(identifier name, asdl_type_param_seq * type_params, arguments_ty args, asdl_stmt_seq * body, asdl_expr_seq * decorator_list, expr_ty returns, string type_comment, int lineno, int col_offset, int end_lineno, int @@ -2090,7 +2090,7 @@ _PyAST_AsyncFunctionDef(identifier name, asdl_typeparam_seq * typeparams, return NULL; p->kind = AsyncFunctionDef_kind; p->v.AsyncFunctionDef.name = name; - p->v.AsyncFunctionDef.typeparams = typeparams; + p->v.AsyncFunctionDef.type_params = type_params; p->v.AsyncFunctionDef.args = args; p->v.AsyncFunctionDef.body = body; p->v.AsyncFunctionDef.decorator_list = decorator_list; @@ -2104,10 +2104,11 @@ _PyAST_AsyncFunctionDef(identifier name, asdl_typeparam_seq * typeparams, } stmt_ty -_PyAST_ClassDef(identifier name, asdl_typeparam_seq * typeparams, asdl_expr_seq - * bases, asdl_keyword_seq * keywords, asdl_stmt_seq * body, - asdl_expr_seq * decorator_list, int lineno, int col_offset, int - end_lineno, int end_col_offset, PyArena *arena) +_PyAST_ClassDef(identifier name, asdl_type_param_seq * type_params, + asdl_expr_seq * bases, asdl_keyword_seq * keywords, + asdl_stmt_seq * body, asdl_expr_seq * decorator_list, int + lineno, int col_offset, int end_lineno, int end_col_offset, + PyArena *arena) { stmt_ty p; if (!name) { @@ -2120,7 +2121,7 @@ _PyAST_ClassDef(identifier name, asdl_typeparam_seq * typeparams, asdl_expr_seq return NULL; p->kind = ClassDef_kind; p->v.ClassDef.name = name; - p->v.ClassDef.typeparams = typeparams; + p->v.ClassDef.type_params = type_params; p->v.ClassDef.bases = bases; p->v.ClassDef.keywords = keywords; p->v.ClassDef.body = body; @@ -2192,8 +2193,8 @@ _PyAST_Assign(asdl_expr_seq * targets, expr_ty value, string type_comment, int } stmt_ty -_PyAST_TypeAlias(expr_ty name, asdl_typeparam_seq * typeparams, expr_ty value, - int lineno, int col_offset, int end_lineno, int +_PyAST_TypeAlias(expr_ty name, asdl_type_param_seq * type_params, expr_ty + value, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { stmt_ty p; @@ -2212,7 +2213,7 @@ _PyAST_TypeAlias(expr_ty name, asdl_typeparam_seq * typeparams, expr_ty value, return NULL; p->kind = TypeAlias_kind; p->v.TypeAlias.name = name; - p->v.TypeAlias.typeparams = typeparams; + p->v.TypeAlias.type_params = type_params; p->v.TypeAlias.value = value; p->lineno = lineno; p->col_offset = col_offset; @@ -3713,17 +3714,17 @@ _PyAST_TypeIgnore(int lineno, string tag, PyArena *arena) return p; } -typeparam_ty +type_param_ty _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { - typeparam_ty p; + type_param_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for TypeVar"); return NULL; } - p = (typeparam_ty)_PyArena_Malloc(arena, sizeof(*p)); + p = (type_param_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TypeVar_kind; @@ -3736,17 +3737,17 @@ _PyAST_TypeVar(identifier name, expr_ty bound, int lineno, int col_offset, int return p; } -typeparam_ty +type_param_ty _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { - typeparam_ty p; + type_param_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for ParamSpec"); return NULL; } - p = (typeparam_ty)_PyArena_Malloc(arena, sizeof(*p)); + p = (type_param_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = ParamSpec_kind; @@ -3758,17 +3759,17 @@ _PyAST_ParamSpec(identifier name, int lineno, int col_offset, int end_lineno, return p; } -typeparam_ty +type_param_ty _PyAST_TypeVarTuple(identifier name, int lineno, int col_offset, int end_lineno, int end_col_offset, PyArena *arena) { - typeparam_ty p; + type_param_ty p; if (!name) { PyErr_SetString(PyExc_ValueError, "field 'name' is required for TypeVarTuple"); return NULL; } - p = (typeparam_ty)_PyArena_Malloc(arena, sizeof(*p)); + p = (type_param_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; p->kind = TypeVarTuple_kind; @@ -3882,10 +3883,10 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.typeparams, - ast2obj_typeparam); + value = ast2obj_list(state, (asdl_seq*)o->v.FunctionDef.type_params, + ast2obj_type_param); if (!value) goto failed; - if (PyObject_SetAttr(result, state->typeparams, value) == -1) + if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_arguments(state, o->v.FunctionDef.args); @@ -3926,10 +3927,10 @@ ast2obj_stmt(struct ast_state *state, void* _o) goto failed; Py_DECREF(value); value = ast2obj_list(state, - (asdl_seq*)o->v.AsyncFunctionDef.typeparams, - ast2obj_typeparam); + (asdl_seq*)o->v.AsyncFunctionDef.type_params, + ast2obj_type_param); if (!value) goto failed; - if (PyObject_SetAttr(result, state->typeparams, value) == -1) + if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_arguments(state, o->v.AsyncFunctionDef.args); @@ -3970,10 +3971,10 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.typeparams, - ast2obj_typeparam); + value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.type_params, + ast2obj_type_param); if (!value) goto failed; - if (PyObject_SetAttr(result, state->typeparams, value) == -1) + if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_list(state, (asdl_seq*)o->v.ClassDef.bases, @@ -4052,10 +4053,10 @@ ast2obj_stmt(struct ast_state *state, void* _o) if (PyObject_SetAttr(result, state->name, value) == -1) goto failed; Py_DECREF(value); - value = ast2obj_list(state, (asdl_seq*)o->v.TypeAlias.typeparams, - ast2obj_typeparam); + value = ast2obj_list(state, (asdl_seq*)o->v.TypeAlias.type_params, + ast2obj_type_param); if (!value) goto failed; - if (PyObject_SetAttr(result, state->typeparams, value) == -1) + if (PyObject_SetAttr(result, state->type_params, value) == -1) goto failed; Py_DECREF(value); value = ast2obj_expr(state, o->v.TypeAlias.value); @@ -5656,9 +5657,9 @@ ast2obj_type_ignore(struct ast_state *state, void* _o) } PyObject* -ast2obj_typeparam(struct ast_state *state, void* _o) +ast2obj_type_param(struct ast_state *state, void* _o) { - typeparam_ty o = (typeparam_ty)_o; + type_param_ty o = (type_param_ty)_o; PyObject *result = NULL, *value = NULL; PyTypeObject *tp; if (!o) { @@ -6074,7 +6075,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; - asdl_typeparam_seq* typeparams; + asdl_type_param_seq* type_params; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; @@ -6098,11 +6099,11 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from FunctionDef"); + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from FunctionDef"); return 1; } else { @@ -6110,27 +6111,27 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "FunctionDef field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + PyErr_Format(PyExc_TypeError, "FunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); - typeparams = _Py_asdl_typeparam_seq_new(len, arena); - if (typeparams == NULL) goto failed; + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { - typeparam_ty val; + type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'FunctionDef' node")) { goto failed; } - res = obj2ast_typeparam(state, tmp2, &val, arena); + res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"typeparams\" changed size during iteration"); + PyErr_SetString(PyExc_RuntimeError, "FunctionDef field \"type_params\" changed size during iteration"); goto failed; } - asdl_seq_SET(typeparams, i, val); + asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } @@ -6257,9 +6258,10 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_FunctionDef(name, typeparams, args, body, decorator_list, - returns, type_comment, lineno, col_offset, - end_lineno, end_col_offset, arena); + *out = _PyAST_FunctionDef(name, type_params, args, body, + decorator_list, returns, type_comment, + lineno, col_offset, end_lineno, + end_col_offset, arena); if (*out == NULL) goto failed; return 0; } @@ -6270,7 +6272,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; - asdl_typeparam_seq* typeparams; + asdl_type_param_seq* type_params; arguments_ty args; asdl_stmt_seq* body; asdl_expr_seq* decorator_list; @@ -6294,11 +6296,11 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from AsyncFunctionDef"); + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from AsyncFunctionDef"); return 1; } else { @@ -6306,27 +6308,27 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + PyErr_Format(PyExc_TypeError, "AsyncFunctionDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); - typeparams = _Py_asdl_typeparam_seq_new(len, arena); - if (typeparams == NULL) goto failed; + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { - typeparam_ty val; + type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'AsyncFunctionDef' node")) { goto failed; } - res = obj2ast_typeparam(state, tmp2, &val, arena); + res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"typeparams\" changed size during iteration"); + PyErr_SetString(PyExc_RuntimeError, "AsyncFunctionDef field \"type_params\" changed size during iteration"); goto failed; } - asdl_seq_SET(typeparams, i, val); + asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } @@ -6453,7 +6455,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_AsyncFunctionDef(name, typeparams, args, body, + *out = _PyAST_AsyncFunctionDef(name, type_params, args, body, decorator_list, returns, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); @@ -6467,7 +6469,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { identifier name; - asdl_typeparam_seq* typeparams; + asdl_type_param_seq* type_params; asdl_expr_seq* bases; asdl_keyword_seq* keywords; asdl_stmt_seq* body; @@ -6490,11 +6492,11 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from ClassDef"); + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from ClassDef"); return 1; } else { @@ -6502,27 +6504,27 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "ClassDef field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + PyErr_Format(PyExc_TypeError, "ClassDef field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); - typeparams = _Py_asdl_typeparam_seq_new(len, arena); - if (typeparams == NULL) goto failed; + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { - typeparam_ty val; + type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'ClassDef' node")) { goto failed; } - res = obj2ast_typeparam(state, tmp2, &val, arena); + res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"typeparams\" changed size during iteration"); + PyErr_SetString(PyExc_RuntimeError, "ClassDef field \"type_params\" changed size during iteration"); goto failed; } - asdl_seq_SET(typeparams, i, val); + asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } @@ -6670,7 +6672,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - *out = _PyAST_ClassDef(name, typeparams, bases, keywords, body, + *out = _PyAST_ClassDef(name, type_params, bases, keywords, body, decorator_list, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; @@ -6847,7 +6849,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } if (isinstance) { expr_ty name; - asdl_typeparam_seq* typeparams; + asdl_type_param_seq* type_params; expr_ty value; if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { @@ -6867,11 +6869,11 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->typeparams, &tmp) < 0) { + if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"typeparams\" missing from TypeAlias"); + PyErr_SetString(PyExc_TypeError, "required field \"type_params\" missing from TypeAlias"); return 1; } else { @@ -6879,27 +6881,27 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* Py_ssize_t len; Py_ssize_t i; if (!PyList_Check(tmp)) { - PyErr_Format(PyExc_TypeError, "TypeAlias field \"typeparams\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); + PyErr_Format(PyExc_TypeError, "TypeAlias field \"type_params\" must be a list, not a %.200s", _PyType_Name(Py_TYPE(tmp))); goto failed; } len = PyList_GET_SIZE(tmp); - typeparams = _Py_asdl_typeparam_seq_new(len, arena); - if (typeparams == NULL) goto failed; + type_params = _Py_asdl_type_param_seq_new(len, arena); + if (type_params == NULL) goto failed; for (i = 0; i < len; i++) { - typeparam_ty val; + type_param_ty val; PyObject *tmp2 = Py_NewRef(PyList_GET_ITEM(tmp, i)); if (_Py_EnterRecursiveCall(" while traversing 'TypeAlias' node")) { goto failed; } - res = obj2ast_typeparam(state, tmp2, &val, arena); + res = obj2ast_type_param(state, tmp2, &val, arena); _Py_LeaveRecursiveCall(); Py_DECREF(tmp2); if (res != 0) goto failed; if (len != PyList_GET_SIZE(tmp)) { - PyErr_SetString(PyExc_RuntimeError, "TypeAlias field \"typeparams\" changed size during iteration"); + PyErr_SetString(PyExc_RuntimeError, "TypeAlias field \"type_params\" changed size during iteration"); goto failed; } - asdl_seq_SET(typeparams, i, val); + asdl_seq_SET(type_params, i, val); } Py_CLEAR(tmp); } @@ -6920,7 +6922,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - *out = _PyAST_TypeAlias(name, typeparams, value, lineno, col_offset, + *out = _PyAST_TypeAlias(name, type_params, value, lineno, col_offset, end_lineno, end_col_offset, arena); if (*out == NULL) goto failed; return 0; @@ -12293,8 +12295,8 @@ obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* } int -obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, - PyArena* arena) +obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, + PyArena* arena) { int isinstance; @@ -12313,12 +12315,12 @@ obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from typeparam"); + PyErr_SetString(PyExc_TypeError, "required field \"lineno\" missing from type_param"); return 1; } else { int res; - if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &lineno, arena); @@ -12330,12 +12332,12 @@ obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, return 1; } if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from typeparam"); + PyErr_SetString(PyExc_TypeError, "required field \"col_offset\" missing from type_param"); return 1; } else { int res; - if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &col_offset, arena); @@ -12352,7 +12354,7 @@ obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, } else { int res; - if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_lineno, arena); @@ -12369,7 +12371,7 @@ obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, } else { int res; - if (_Py_EnterRecursiveCall(" while traversing 'typeparam' node")) { + if (_Py_EnterRecursiveCall(" while traversing 'type_param' node")) { goto failed; } res = obj2ast_int(state, tmp, &end_col_offset, arena); @@ -12486,7 +12488,7 @@ obj2ast_typeparam(struct ast_state *state, PyObject* obj, typeparam_ty* out, return 0; } - PyErr_Format(PyExc_TypeError, "expected some sort of typeparam, but got %R", obj); + PyErr_Format(PyExc_TypeError, "expected some sort of type_param, but got %R", obj); failed: Py_XDECREF(tmp); return 1; @@ -12880,7 +12882,7 @@ astmodule_exec(PyObject *m) if (PyModule_AddObjectRef(m, "TypeIgnore", state->TypeIgnore_type) < 0) { return -1; } - if (PyModule_AddObjectRef(m, "typeparam", state->typeparam_type) < 0) { + if (PyModule_AddObjectRef(m, "type_param", state->type_param_type) < 0) { return -1; } if (PyModule_AddObjectRef(m, "TypeVar", state->TypeVar_type) < 0) { diff --git a/Python/ast.c b/Python/ast.c index 0844f2afa06b..68600ce683b9 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -17,12 +17,12 @@ struct validator { static int validate_stmts(struct validator *, asdl_stmt_seq *); static int validate_exprs(struct validator *, asdl_expr_seq *, expr_context_ty, int); static int validate_patterns(struct validator *, asdl_pattern_seq *, int); -static int validate_typeparams(struct validator *, asdl_typeparam_seq *); +static int validate_type_params(struct validator *, asdl_type_param_seq *); static int _validate_nonempty_seq(asdl_seq *, const char *, const char *); static int validate_stmt(struct validator *, stmt_ty); static int validate_expr(struct validator *, expr_ty, expr_context_ty); static int validate_pattern(struct validator *, pattern_ty, int); -static int validate_typeparam(struct validator *, typeparam_ty); +static int validate_typeparam(struct validator *, type_param_ty); #define VALIDATE_POSITIONS(node) \ if (node->lineno > node->end_lineno) { \ @@ -728,7 +728,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) switch (stmt->kind) { case FunctionDef_kind: ret = validate_body(state, stmt->v.FunctionDef.body, "FunctionDef") && - validate_typeparams(state, stmt->v.FunctionDef.typeparams) && + validate_type_params(state, stmt->v.FunctionDef.type_params) && validate_arguments(state, stmt->v.FunctionDef.args) && validate_exprs(state, stmt->v.FunctionDef.decorator_list, Load, 0) && (!stmt->v.FunctionDef.returns || @@ -736,7 +736,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) break; case ClassDef_kind: ret = validate_body(state, stmt->v.ClassDef.body, "ClassDef") && - validate_typeparams(state, stmt->v.ClassDef.typeparams) && + validate_type_params(state, stmt->v.ClassDef.type_params) && validate_exprs(state, stmt->v.ClassDef.bases, Load, 0) && validate_keywords(state, stmt->v.ClassDef.keywords) && validate_exprs(state, stmt->v.ClassDef.decorator_list, Load, 0); @@ -769,7 +769,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) break; case TypeAlias_kind: ret = validate_expr(state, stmt->v.TypeAlias.name, Store) && - validate_typeparams(state, stmt->v.TypeAlias.typeparams) && + validate_type_params(state, stmt->v.TypeAlias.type_params) && validate_expr(state, stmt->v.TypeAlias.value, Load); break; case For_kind: @@ -919,7 +919,7 @@ validate_stmt(struct validator *state, stmt_ty stmt) break; case AsyncFunctionDef_kind: ret = validate_body(state, stmt->v.AsyncFunctionDef.body, "AsyncFunctionDef") && - validate_typeparams(state, stmt->v.AsyncFunctionDef.typeparams) && + validate_type_params(state, stmt->v.AsyncFunctionDef.type_params) && validate_arguments(state, stmt->v.AsyncFunctionDef.args) && validate_exprs(state, stmt->v.AsyncFunctionDef.decorator_list, Load, 0) && (!stmt->v.AsyncFunctionDef.returns || @@ -993,7 +993,7 @@ validate_patterns(struct validator *state, asdl_pattern_seq *patterns, int star_ } static int -validate_typeparam(struct validator *state, typeparam_ty tp) +validate_typeparam(struct validator *state, type_param_ty tp) { VALIDATE_POSITIONS(tp); int ret = -1; @@ -1014,11 +1014,11 @@ validate_typeparam(struct validator *state, typeparam_ty tp) } static int -validate_typeparams(struct validator *state, asdl_typeparam_seq *tps) +validate_type_params(struct validator *state, asdl_type_param_seq *tps) { Py_ssize_t i; for (i = 0; i < asdl_seq_LEN(tps); i++) { - typeparam_ty tp = asdl_seq_GET(tps, i); + type_param_ty tp = asdl_seq_GET(tps, i); if (tp) { if (!validate_typeparam(state, tp)) return 0; diff --git a/Python/ast_opt.c b/Python/ast_opt.c index c5b3e0754673..274bd134e143 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -642,7 +642,7 @@ static int astfold_withitem(withitem_ty node_, PyArena *ctx_, _PyASTOptimizeStat static int astfold_excepthandler(excepthandler_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); static int astfold_pattern(pattern_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); -static int astfold_typeparam(typeparam_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); +static int astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTOptimizeState *state); #define CALL(FUNC, TYPE, ARG) \ if (!FUNC((ARG), ctx_, state)) \ @@ -881,7 +881,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } switch (node_->kind) { case FunctionDef_kind: - CALL_SEQ(astfold_typeparam, typeparam, node_->v.FunctionDef.typeparams); + CALL_SEQ(astfold_type_param, type_param, node_->v.FunctionDef.type_params); CALL(astfold_arguments, arguments_ty, node_->v.FunctionDef.args); CALL(astfold_body, asdl_seq, node_->v.FunctionDef.body); CALL_SEQ(astfold_expr, expr, node_->v.FunctionDef.decorator_list); @@ -890,7 +890,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } break; case AsyncFunctionDef_kind: - CALL_SEQ(astfold_typeparam, typeparam, node_->v.AsyncFunctionDef.typeparams); + CALL_SEQ(astfold_type_param, type_param, node_->v.AsyncFunctionDef.type_params); CALL(astfold_arguments, arguments_ty, node_->v.AsyncFunctionDef.args); CALL(astfold_body, asdl_seq, node_->v.AsyncFunctionDef.body); CALL_SEQ(astfold_expr, expr, node_->v.AsyncFunctionDef.decorator_list); @@ -899,7 +899,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) } break; case ClassDef_kind: - CALL_SEQ(astfold_typeparam, typeparam, node_->v.ClassDef.typeparams); + CALL_SEQ(astfold_type_param, type_param, node_->v.ClassDef.type_params); CALL_SEQ(astfold_expr, expr, node_->v.ClassDef.bases); CALL_SEQ(astfold_keyword, keyword, node_->v.ClassDef.keywords); CALL(astfold_body, asdl_seq, node_->v.ClassDef.body); @@ -928,7 +928,7 @@ astfold_stmt(stmt_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) break; case TypeAlias_kind: CALL(astfold_expr, expr_ty, node_->v.TypeAlias.name); - CALL_SEQ(astfold_typeparam, typeparam, node_->v.TypeAlias.typeparams); + CALL_SEQ(astfold_type_param, type_param, node_->v.TypeAlias.type_params); CALL(astfold_expr, expr_ty, node_->v.TypeAlias.value); break; case For_kind: @@ -1084,7 +1084,7 @@ astfold_match_case(match_case_ty node_, PyArena *ctx_, _PyASTOptimizeState *stat } static int -astfold_typeparam(typeparam_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) +astfold_type_param(type_param_ty node_, PyArena *ctx_, _PyASTOptimizeState *state) { switch (node_->kind) { case TypeVar_kind: diff --git a/Python/compile.c b/Python/compile.c index e4dc9729b694..f2314ae11c41 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2113,15 +2113,15 @@ wrap_in_stopiteration_handler(struct compiler *c) } static int -compiler_type_params(struct compiler *c, asdl_typeparam_seq *typeparams) +compiler_type_params(struct compiler *c, asdl_type_param_seq *type_params) { - if (!typeparams) { + if (!type_params) { return SUCCESS; } - Py_ssize_t n = asdl_seq_LEN(typeparams); + Py_ssize_t n = asdl_seq_LEN(type_params); for (Py_ssize_t i = 0; i < n; i++) { - typeparam_ty typeparam = asdl_seq_GET(typeparams, i); + type_param_ty typeparam = asdl_seq_GET(type_params, i); location loc = LOC(typeparam); switch(typeparam->kind) { case TypeVar_kind: @@ -2170,7 +2170,7 @@ compiler_type_params(struct compiler *c, asdl_typeparam_seq *typeparams) break; } } - ADDOP_I(c, LOC(asdl_seq_GET(typeparams, 0)), BUILD_TUPLE, n); + ADDOP_I(c, LOC(asdl_seq_GET(type_params, 0)), BUILD_TUPLE, n); return SUCCESS; } @@ -2248,7 +2248,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) expr_ty returns; identifier name; asdl_expr_seq *decos; - asdl_typeparam_seq *typeparams; + asdl_type_param_seq *type_params; Py_ssize_t funcflags; int annotations; int firstlineno; @@ -2260,7 +2260,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) returns = s->v.AsyncFunctionDef.returns; decos = s->v.AsyncFunctionDef.decorator_list; name = s->v.AsyncFunctionDef.name; - typeparams = s->v.AsyncFunctionDef.typeparams; + type_params = s->v.AsyncFunctionDef.type_params; } else { assert(s->kind == FunctionDef_kind); @@ -2268,7 +2268,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) returns = s->v.FunctionDef.returns; decos = s->v.FunctionDef.decorator_list; name = s->v.FunctionDef.name; - typeparams = s->v.FunctionDef.typeparams; + type_params = s->v.FunctionDef.type_params; } RETURN_IF_ERROR(compiler_check_debug_args(c, args)); @@ -2281,7 +2281,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) location loc = LOC(s); - int is_generic = asdl_seq_LEN(typeparams) > 0; + int is_generic = asdl_seq_LEN(type_params) > 0; if (is_generic) { // Used by the CALL to the type parameters function. @@ -2305,17 +2305,17 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) if (num_typeparam_args == 2) { ADDOP_I(c, loc, SWAP, 2); } - PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", name); - if (!typeparams_name) { + PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", name); + if (!type_params_name) { return ERROR; } - if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS, - (void *)typeparams, firstlineno) == -1) { - Py_DECREF(typeparams_name); + if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS, + (void *)type_params, firstlineno) == -1) { + Py_DECREF(type_params_name); return ERROR; } - Py_DECREF(typeparams_name); - RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams)); + Py_DECREF(type_params_name); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); if ((funcflags & 0x01) || (funcflags & 0x02)) { RETURN_IF_ERROR_IN_SCOPE(c, codegen_addop_i(INSTR_SEQUENCE(c), LOAD_FAST, 0, loc)); } @@ -2416,8 +2416,8 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) compiler_exit_scope(c); return ERROR; } - asdl_typeparam_seq *typeparams = s->v.ClassDef.typeparams; - if (asdl_seq_LEN(typeparams) > 0) { + asdl_type_param_seq *type_params = s->v.ClassDef.type_params; + if (asdl_seq_LEN(type_params) > 0) { if (!compiler_set_type_params_in_class(c, loc)) { compiler_exit_scope(c); return ERROR; @@ -2519,23 +2519,23 @@ compiler_class(struct compiler *c, stmt_ty s) } location loc = LOC(s); - asdl_typeparam_seq *typeparams = s->v.ClassDef.typeparams; - int is_generic = asdl_seq_LEN(typeparams) > 0; + asdl_type_param_seq *type_params = s->v.ClassDef.type_params; + int is_generic = asdl_seq_LEN(type_params) > 0; if (is_generic) { Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); ADDOP(c, loc, PUSH_NULL); - PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", + PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", s->v.ClassDef.name); - if (!typeparams_name) { + if (!type_params_name) { return ERROR; } - if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS, - (void *)typeparams, firstlineno) == -1) { - Py_DECREF(typeparams_name); + if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS, + (void *)type_params, firstlineno) == -1) { + Py_DECREF(type_params_name); return ERROR; } - Py_DECREF(typeparams_name); - RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams)); + Py_DECREF(type_params_name); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); _Py_DECLARE_STR(type_params, ".type_params"); RETURN_IF_ERROR_IN_SCOPE(c, compiler_nameop(c, loc, &_Py_STR(type_params), Store)); } @@ -2637,26 +2637,26 @@ static int compiler_typealias(struct compiler *c, stmt_ty s) { location loc = LOC(s); - asdl_typeparam_seq *typeparams = s->v.TypeAlias.typeparams; - int is_generic = asdl_seq_LEN(typeparams) > 0; + asdl_type_param_seq *type_params = s->v.TypeAlias.type_params; + int is_generic = asdl_seq_LEN(type_params) > 0; PyObject *name = s->v.TypeAlias.name->v.Name.id; if (is_generic) { ADDOP(c, loc, PUSH_NULL); - PyObject *typeparams_name = PyUnicode_FromFormat("<generic parameters of %U>", + PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", name); - if (!typeparams_name) { + if (!type_params_name) { return ERROR; } - if (compiler_enter_scope(c, typeparams_name, COMPILER_SCOPE_TYPEPARAMS, - (void *)typeparams, loc.lineno) == -1) { - Py_DECREF(typeparams_name); + if (compiler_enter_scope(c, type_params_name, COMPILER_SCOPE_TYPEPARAMS, + (void *)type_params, loc.lineno) == -1) { + Py_DECREF(type_params_name); return ERROR; } - Py_DECREF(typeparams_name); + Py_DECREF(type_params_name); RETURN_IF_ERROR_IN_SCOPE( c, compiler_addop_load_const(c->c_const_cache, c->u, loc, name) ); - RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, typeparams)); + RETURN_IF_ERROR_IN_SCOPE(c, compiler_type_params(c, type_params)); } else { ADDOP_LOAD_CONST(c, loc, name); diff --git a/Python/symtable.c b/Python/symtable.c index 73cbb2b8e995..e2c00d17480d 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -231,7 +231,7 @@ static int symtable_enter_block(struct symtable *st, identifier name, static int symtable_exit_block(struct symtable *st); static int symtable_visit_stmt(struct symtable *st, stmt_ty s); static int symtable_visit_expr(struct symtable *st, expr_ty s); -static int symtable_visit_typeparam(struct symtable *st, typeparam_ty s); +static int symtable_visit_type_param(struct symtable *st, type_param_ty s); static int symtable_visit_genexp(struct symtable *st, expr_ty s); static int symtable_visit_listcomp(struct symtable *st, expr_ty s); static int symtable_visit_setcomp(struct symtable *st, expr_ty s); @@ -528,7 +528,7 @@ error_at_directive(PySTEntryObject *ste, PyObject *name) static int analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, PyObject *bound, PyObject *local, PyObject *free, - PyObject *global, PyObject *typeparams, PySTEntryObject *class_entry) + PyObject *global, PyObject *type_params, PySTEntryObject *class_entry) { if (flags & DEF_GLOBAL) { if (flags & DEF_NONLOCAL) { @@ -557,7 +557,7 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, return error_at_directive(ste, name); } - if (PySet_Contains(typeparams, name)) { + if (PySet_Contains(type_params, name)) { PyErr_Format(PyExc_SyntaxError, "nonlocal binding not allowed for type parameter '%U'", name); @@ -574,11 +574,11 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags, if (PySet_Discard(global, name) < 0) return 0; if (flags & DEF_TYPE_PARAM) { - if (PySet_Add(typeparams, name) < 0) + if (PySet_Add(type_params, name) < 0) return 0; } else { - if (PySet_Discard(typeparams, name) < 0) + if (PySet_Discard(type_params, name) < 0) return 0; } return 1; @@ -871,12 +871,12 @@ update_symbols(PyObject *symbols, PyObject *scopes, static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, - PyObject *global, PyObject *typeparams, + PyObject *global, PyObject *type_params, PySTEntryObject *class_entry, PyObject **child_free); static int analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, - PyObject *global, PyObject *typeparams, + PyObject *global, PyObject *type_params, PySTEntryObject *class_entry) { PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL; @@ -939,7 +939,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) { long flags = PyLong_AS_LONG(v); if (!analyze_name(ste, scopes, name, flags, - bound, local, free, global, typeparams, class_entry)) + bound, local, free, global, type_params, class_entry)) goto error; } @@ -1002,7 +1002,7 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, !entry->ste_generator; if (!analyze_child_block(entry, newbound, newfree, newglobal, - typeparams, new_class_entry, &child_free)) + type_params, new_class_entry, &child_free)) { goto error; } @@ -1066,11 +1066,11 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, static int analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, - PyObject *global, PyObject *typeparams, + PyObject *global, PyObject *type_params, PySTEntryObject *class_entry, PyObject** child_free) { PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL; - PyObject *temp_typeparams = NULL; + PyObject *temp_type_params = NULL; /* Copy the bound/global/free sets. @@ -1088,30 +1088,30 @@ analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free, temp_global = PySet_New(global); if (!temp_global) goto error; - temp_typeparams = PySet_New(typeparams); - if (!temp_typeparams) + temp_type_params = PySet_New(type_params); + if (!temp_type_params) goto error; if (!analyze_block(entry, temp_bound, temp_free, temp_global, - temp_typeparams, class_entry)) + temp_type_params, class_entry)) goto error; *child_free = temp_free; Py_DECREF(temp_bound); Py_DECREF(temp_global); - Py_DECREF(temp_typeparams); + Py_DECREF(temp_type_params); return 1; error: Py_XDECREF(temp_bound); Py_XDECREF(temp_free); Py_XDECREF(temp_global); - Py_XDECREF(temp_typeparams); + Py_XDECREF(temp_type_params); return 0; } static int symtable_analyze(struct symtable *st) { - PyObject *free, *global, *typeparams; + PyObject *free, *global, *type_params; int r; free = PySet_New(NULL); @@ -1122,16 +1122,16 @@ symtable_analyze(struct symtable *st) Py_DECREF(free); return 0; } - typeparams = PySet_New(NULL); - if (!typeparams) { + type_params = PySet_New(NULL); + if (!type_params) { Py_DECREF(free); Py_DECREF(global); return 0; } - r = analyze_block(st->st_top, NULL, free, global, typeparams, NULL); + r = analyze_block(st->st_top, NULL, free, global, type_params, NULL); Py_DECREF(free); Py_DECREF(global); - Py_DECREF(typeparams); + Py_DECREF(type_params); return r; } @@ -1313,7 +1313,7 @@ symtable_add_def(struct symtable *st, PyObject *name, int flag, } static int -symtable_enter_typeparam_block(struct symtable *st, identifier name, +symtable_enter_type_param_block(struct symtable *st, identifier name, void *ast, int has_defaults, int has_kwdefaults, enum _stmt_kind kind, int lineno, int col_offset, @@ -1472,10 +1472,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ_WITH_NULL(st, expr, s->v.FunctionDef.args->kw_defaults); if (s->v.FunctionDef.decorator_list) VISIT_SEQ(st, expr, s->v.FunctionDef.decorator_list); - if (asdl_seq_LEN(s->v.FunctionDef.typeparams) > 0) { - if (!symtable_enter_typeparam_block( + if (asdl_seq_LEN(s->v.FunctionDef.type_params) > 0) { + if (!symtable_enter_type_param_block( st, s->v.FunctionDef.name, - (void *)s->v.FunctionDef.typeparams, + (void *)s->v.FunctionDef.type_params, s->v.FunctionDef.args->defaults != NULL, has_kwonlydefaults(s->v.FunctionDef.args->kwonlyargs, s->v.FunctionDef.args->kw_defaults), @@ -1483,7 +1483,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) LOCATION(s))) { VISIT_QUIT(st, 0); } - VISIT_SEQ(st, typeparam, s->v.FunctionDef.typeparams); + VISIT_SEQ(st, type_param, s->v.FunctionDef.type_params); } if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args, s->v.FunctionDef.returns)) @@ -1496,7 +1496,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ(st, stmt, s->v.FunctionDef.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); - if (asdl_seq_LEN(s->v.FunctionDef.typeparams) > 0) { + if (asdl_seq_LEN(s->v.FunctionDef.type_params) > 0) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } @@ -1507,14 +1507,14 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_QUIT(st, 0); if (s->v.ClassDef.decorator_list) VISIT_SEQ(st, expr, s->v.ClassDef.decorator_list); - if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) { - if (!symtable_enter_typeparam_block(st, s->v.ClassDef.name, - (void *)s->v.ClassDef.typeparams, + if (asdl_seq_LEN(s->v.ClassDef.type_params) > 0) { + if (!symtable_enter_type_param_block(st, s->v.ClassDef.name, + (void *)s->v.ClassDef.type_params, false, false, s->kind, LOCATION(s))) { VISIT_QUIT(st, 0); } - VISIT_SEQ(st, typeparam, s->v.ClassDef.typeparams); + VISIT_SEQ(st, type_param, s->v.ClassDef.type_params); } VISIT_SEQ(st, expr, s->v.ClassDef.bases); VISIT_SEQ(st, keyword, s->v.ClassDef.keywords); @@ -1524,7 +1524,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_QUIT(st, 0); tmp = st->st_private; st->st_private = s->v.ClassDef.name; - if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) { + if (asdl_seq_LEN(s->v.ClassDef.type_params) > 0) { if (!symtable_add_def(st, &_Py_ID(__type_params__), DEF_LOCAL, LOCATION(s))) { VISIT_QUIT(st, 0); @@ -1539,7 +1539,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) st->st_private = tmp; if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); - if (asdl_seq_LEN(s->v.ClassDef.typeparams) > 0) { + if (asdl_seq_LEN(s->v.ClassDef.type_params) > 0) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } @@ -1550,16 +1550,16 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) assert(s->v.TypeAlias.name->kind == Name_kind); PyObject *name = s->v.TypeAlias.name->v.Name.id; int is_in_class = st->st_cur->ste_type == ClassBlock; - int is_generic = asdl_seq_LEN(s->v.TypeAlias.typeparams) > 0; + int is_generic = asdl_seq_LEN(s->v.TypeAlias.type_params) > 0; if (is_generic) { - if (!symtable_enter_typeparam_block( + if (!symtable_enter_type_param_block( st, name, - (void *)s->v.TypeAlias.typeparams, + (void *)s->v.TypeAlias.type_params, false, false, s->kind, LOCATION(s))) { VISIT_QUIT(st, 0); } - VISIT_SEQ(st, typeparam, s->v.TypeAlias.typeparams); + VISIT_SEQ(st, type_param, s->v.TypeAlias.type_params); } if (!symtable_enter_block(st, name, TypeAliasBlock, (void *)s, LOCATION(s))) @@ -1785,10 +1785,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) s->v.AsyncFunctionDef.args->kw_defaults); if (s->v.AsyncFunctionDef.decorator_list) VISIT_SEQ(st, expr, s->v.AsyncFunctionDef.decorator_list); - if (asdl_seq_LEN(s->v.AsyncFunctionDef.typeparams) > 0) { - if (!symtable_enter_typeparam_block( + if (asdl_seq_LEN(s->v.AsyncFunctionDef.type_params) > 0) { + if (!symtable_enter_type_param_block( st, s->v.AsyncFunctionDef.name, - (void *)s->v.AsyncFunctionDef.typeparams, + (void *)s->v.AsyncFunctionDef.type_params, s->v.AsyncFunctionDef.args->defaults != NULL, has_kwonlydefaults(s->v.AsyncFunctionDef.args->kwonlyargs, s->v.AsyncFunctionDef.args->kw_defaults), @@ -1796,7 +1796,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) LOCATION(s))) { VISIT_QUIT(st, 0); } - VISIT_SEQ(st, typeparam, s->v.AsyncFunctionDef.typeparams); + VISIT_SEQ(st, type_param, s->v.AsyncFunctionDef.type_params); } if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args, s->v.AsyncFunctionDef.returns)) @@ -1811,7 +1811,7 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s) VISIT_SEQ(st, stmt, s->v.AsyncFunctionDef.body); if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); - if (asdl_seq_LEN(s->v.AsyncFunctionDef.typeparams) > 0) { + if (asdl_seq_LEN(s->v.AsyncFunctionDef.type_params) > 0) { if (!symtable_exit_block(st)) VISIT_QUIT(st, 0); } @@ -2110,7 +2110,7 @@ symtable_visit_expr(struct symtable *st, expr_ty e) } static int -symtable_visit_typeparam(struct symtable *st, typeparam_ty tp) +symtable_visit_type_param(struct symtable *st, type_param_ty tp) { if (++st->recursion_depth > st->recursion_limit) { PyErr_SetString(PyExc_RecursionError, From webhook-mailer at python.org Mon May 22 02:34:05 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 22 May 2023 06:34:05 -0000 Subject: [Python-checkins] gh-99834: Update macOS installer to Tcl/Tk 8.6.13. (GH-104738) Message-ID: <mailman.519.1684737246.13550.python-checkins@python.org> https://github.com/python/cpython/commit/13e460086b007691f2ca1c5ff677cdb70d19eba8 commit: 13e460086b007691f2ca1c5ff677cdb70d19eba8 branch: main author: Ned Deily <nad at python.org> committer: ned-deily <nad at python.org> date: 2023-05-22T06:33:50Z summary: gh-99834: Update macOS installer to Tcl/Tk 8.6.13. (GH-104738) files: A Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 5474f87fd6cb..177fc2044f69 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -264,10 +264,10 @@ def library_recipes(): tk_patches = ['tk868_on_10_8_10_9.patch'] else: - tcl_tk_ver='8.6.12' - tcl_checksum='87ea890821d2221f2ab5157bc5eb885f' + tcl_tk_ver='8.6.13' + tcl_checksum='43a1fae7412f61ff11de2cfd05d28cfc3a73762f354a417c62370a54e2caf066' - tk_checksum='1d6dcf6120356e3d211e056dff5e462a' + tk_checksum='2e65fa069a23365440a3c56c556b8673b5e32a283800d8d9b257e3f584ce0675' tk_patches = [ ] diff --git a/Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst b/Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst new file mode 100644 index 000000000000..aeb64d25b09a --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst @@ -0,0 +1 @@ +Update macOS installer to Tcl/Tk 8.6.13. From webhook-mailer at python.org Mon May 22 02:43:52 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 22 May 2023 06:43:52 -0000 Subject: [Python-checkins] Update macOS installer ReadMe and Welcome screens for 3.12.0b1. (GH-104739) Message-ID: <mailman.520.1684737833.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6fba0314765d7c58a33e9859d9cd5bcc35d2fd0a commit: 6fba0314765d7c58a33e9859d9cd5bcc35d2fd0a branch: main author: Ned Deily <nad at python.org> committer: ned-deily <nad at python.org> date: 2023-05-22T06:43:43Z summary: Update macOS installer ReadMe and Welcome screens for 3.12.0b1. (GH-104739) files: M Mac/BuildScript/resources/ReadMe.rtf M Mac/BuildScript/resources/Welcome.rtf diff --git a/Mac/BuildScript/resources/ReadMe.rtf b/Mac/BuildScript/resources/ReadMe.rtf index dbe8c520a7c7..5bc356d52670 100644 --- a/Mac/BuildScript/resources/ReadMe.rtf +++ b/Mac/BuildScript/resources/ReadMe.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2639 +{\rtf1\ansi\ansicpg1252\cocoartf2709 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fswiss\fcharset0 Helvetica-Oblique; \f3\fmodern\fcharset0 CourierNewPSMT;\f4\fmodern\fcharset0 Courier;} {\colortbl;\red255\green255\blue255;} @@ -11,7 +11,7 @@ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\partightenfactor0 \f1\b \cf0 NOTE: -\f0\b0 This is an alpha preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ +\f0\b0 This is a beta preview of Python 3.12.0, the next feature release of Python 3. It is not intended for production use.\ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 \cf0 \ \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf index 1f109ee9f13e..83b7aa9d883a 100644 --- a/Mac/BuildScript/resources/Welcome.rtf +++ b/Mac/BuildScript/resources/Welcome.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2708 +{\rtf1\ansi\ansicpg1252\cocoartf2709 \cocoascreenfonts1\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fswiss\fcharset0 Helvetica-Bold;\f2\fmodern\fcharset0 CourierNewPSMT; } {\colortbl;\red255\green255\blue255;} @@ -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 @@ -25,28 +26,6 @@ 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 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 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: -\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.\ +\f0\b0 This is a beta 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 From webhook-mailer at python.org Mon May 22 04:55:27 2023 From: webhook-mailer at python.org (serhiy-storchaka) Date: Mon, 22 May 2023 08:55:27 -0000 Subject: [Python-checkins] gh-94473: Flatten arguments in tkinter.Canvas.coords() (GH-98479) Message-ID: <mailman.521.1684745729.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9bc80dac47f6d43d0bbfbf10c4cc3848b175e97f commit: 9bc80dac47f6d43d0bbfbf10c4cc3848b175e97f branch: main author: Serhiy Storchaka <storchaka at gmail.com> committer: serhiy-storchaka <storchaka at gmail.com> date: 2023-05-22T11:54:41+03:00 summary: gh-94473: Flatten arguments in tkinter.Canvas.coords() (GH-98479) It now accepts not only "x1, y1, x2, y2, ..." and "[x1, y1, x2, y2, ...]", but also "(x1, y1), (x2, y2), ..." and "[(x1, y1), (x2, y2), ...]". files: A Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst M Doc/whatsnew/3.12.rst M Lib/test/test_tkinter/test_widgets.py M Lib/tkinter/__init__.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index caf21078b9bd..efbd2ca3de12 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -532,6 +532,17 @@ threading profiling functions in all running threads in addition to the calling one. (Contributed by Pablo Galindo in :gh:`93503`.) +tkinter +------- + +* ``tkinter.Canvas.coords()`` now flattens its arguments. + It now accepts not only coordinates as separate arguments + (``x1, y1, x2, y2, ...``) and a sequence of coordinates + (``[x1, y1, x2, y2, ...]``), but also coordinates grouped in pairs + (``(x1, y1), (x2, y2), ...`` and ``[(x1, y1), (x2, y2), ...]``), + like ``create_*()`` methods. + (Contributed by Serhiy Storchaka in :gh:`94473`.) + types ----- diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index b45245162f24..76cc16e5b977 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -901,6 +901,12 @@ def test_coords(self): c.coords(i, [21, 31, 41, 51, 61, 11]) self.assertEqual(c.coords(i), [21.0, 31.0, 41.0, 51.0, 61.0, 11.0]) + c.coords(i, (22, 32), (42, 52), (62, 12)) + self.assertEqual(c.coords(i), [22.0, 32.0, 42.0, 52.0, 62.0, 12.0]) + + c.coords(i, [(23, 33), (43, 53), (63, 13)]) + self.assertEqual(c.coords(i), [23.0, 33.0, 43.0, 53.0, 63.0, 13.0]) + c.coords(i, 20, 30, 60, 10) self.assertEqual(c.coords(i), [20.0, 30.0, 60.0, 10.0]) self.assertEqual(c.bbox(i), (18, 8, 62, 32)) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index bf0b3b921559..c675c511e045 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2817,7 +2817,7 @@ def canvasy(self, screeny, gridspacing=None): def coords(self, *args): """Return a list of coordinates for the item given in ARGS.""" - # XXX Should use _flatten on args + args = _flatten(args) return [self.tk.getdouble(x) for x in self.tk.splitlist( self.tk.call((self._w, 'coords') + args))] diff --git a/Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst b/Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst new file mode 100644 index 000000000000..f70722a6f0f6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst @@ -0,0 +1,3 @@ +Flatten arguments in :meth:`tkinter.Canvas.coords`. It now accepts not only +``x1, y1, x2, y2, ...`` and ``[x1, y1, x2, y2, ...]``, but also ``(x1, y1), +(x2, y2), ...`` and ``[(x1, y1), (x2, y2), ...]``. From webhook-mailer at python.org Mon May 22 06:30:19 2023 From: webhook-mailer at python.org (lysnikolaou) Date: Mon, 22 May 2023 10:30:19 -0000 Subject: [Python-checkins] gh-102856: Allow comments inside multi-line f-string expresions (#104006) Message-ID: <mailman.522.1684751420.13550.python-checkins@python.org> https://github.com/python/cpython/commit/0a7796052acb9cec8b13f8d0a5f304f56f26ec5b commit: 0a7796052acb9cec8b13f8d0a5f304f56f26ec5b branch: main author: Cristi?n Maureira-Fredes <cmaureir at users.noreply.github.com> committer: lysnikolaou <lisandrosnik at gmail.com> date: 2023-05-22T10:30:07Z summary: gh-102856: Allow comments inside multi-line f-string expresions (#104006) files: M Lib/test/test_fstring.py M Parser/tokenizer.c diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index fcb12d25ff9d..3ba2f943e6e9 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -661,15 +661,50 @@ def test_comments(self): self.assertEqual(f'{"#"}', '#') self.assertEqual(f'{d["#"]}', 'hash') - self.assertAllRaise(SyntaxError, "f-string expression part cannot include '#'", - ["f'{1#}'", # error because the expression becomes "(1#)" - "f'{3(#)}'", + self.assertAllRaise(SyntaxError, "'{' was never closed", + ["f'{1#}'", # error because everything after '#' is a comment "f'{#}'", + "f'one: {1#}'", + "f'{1# one} {2 this is a comment still#}'", ]) self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'", ["f'{)#}'", # When wrapped in parens, this becomes # '()#)'. Make sure that doesn't compile. ]) + self.assertEqual(f'''A complex trick: { +2 # two +}''', 'A complex trick: 2') + self.assertEqual(f''' +{ +40 # fourty ++ # plus +2 # two +}''', '\n42') + self.assertEqual(f''' +{ +40 # fourty ++ # plus +2 # two +}''', '\n42') + + self.assertEqual(f''' +# this is not a comment +{ # the following operation it's +3 # this is a number +* 2}''', '\n# this is not a comment\n6') + self.assertEqual(f''' +{# f'a {comment}' +86 # constant +# nothing more +}''', '\n86') + + self.assertAllRaise(SyntaxError, r"f-string: valid expression required before '}'", + ["""f''' +{ +# only a comment +}''' +""", # this is equivalent to f'{}' + ]) def test_many_expressions(self): # Create a string with many expressions in it. Note that diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index fc4afccbfc40..472d41747263 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1818,10 +1818,6 @@ 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 (INSIDE_FSTRING(tok)) { - return MAKE_TOKEN(syntaxerror(tok, "f-string expression part cannot include '#'")); - } - const char* p = NULL; const char *prefix, *type_start; int current_starting_col_offset; From webhook-mailer at python.org Mon May 22 06:40:11 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:40:11 -0000 Subject: [Python-checkins] [3.8] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104121) Message-ID: <mailman.523.1684752012.13550.python-checkins@python.org> https://github.com/python/cpython/commit/2062fce6e18caf589851f7c9ff8963cf2d48ac6b commit: 2062fce6e18caf589851f7c9ff8963cf2d48ac6b branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:39:50+02:00 summary: [3.8] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104121) Do not expose the local server's on-disk location from `SimpleHTTPRequestHandler` when generating a directory index. (unnecessary information disclosure) (cherry picked from commit c7c3a60c88de61a79ded9fdaf6bc6a29da4efb9a) Co-authored-by: Ethan Furman <ethan at stoneleaf.us> Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index ac04543827e6..f09065144b44 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -786,7 +786,7 @@ def list_directory(self, path): displaypath = urllib.parse.unquote(self.path, errors='surrogatepass') except UnicodeDecodeError: - displaypath = urllib.parse.unquote(path) + displaypath = urllib.parse.unquote(self.path) displaypath = html.escape(displaypath, quote=False) enc = sys.getfilesystemencoding() title = 'Directory listing for %s' % displaypath diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 5a49b73c2f84..3806f7ac27a8 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -414,6 +414,14 @@ def test_undecodable_filename(self): self.check_status_and_reason(response, HTTPStatus.OK, data=support.TESTFN_UNDECODABLE) + def test_undecodable_parameter(self): + # sanity check using a valid parameter + response = self.request(self.base_url + '/?x=123').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + # now the bogus encoding + response = self.request(self.base_url + '/?x=%bb').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. diff --git a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst new file mode 100644 index 000000000000..969deb26bfeb --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst @@ -0,0 +1,2 @@ +Do not expose the local on-disk location in directory indexes +produced by :class:`http.client.SimpleHTTPRequestHandler`. From webhook-mailer at python.org Mon May 22 06:40:11 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:40:11 -0000 Subject: [Python-checkins] [3.8] gh-103935: Use `io.open_code()` when executing code in trace and profile modules (GH-103947) (#103954) Message-ID: <mailman.524.1684752013.13550.python-checkins@python.org> https://github.com/python/cpython/commit/9f89c471fb152fd031791f3c598ceba93d91dcf0 commit: 9f89c471fb152fd031791f3c598ceba93d91dcf0 branch: 3.8 author: Steve Dower <steve.dower at python.org> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:40:02+02:00 summary: [3.8] gh-103935: Use `io.open_code()` when executing code in trace and profile modules (GH-103947) (#103954) Co-authored-by: Tian Gao <gaogaotiantian at hotmail.com> files: A Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst M Lib/cProfile.py M Lib/profile.py M Lib/trace.py diff --git a/Lib/cProfile.py b/Lib/cProfile.py index 406a9b7cf11b..44cb90c02297 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -7,6 +7,7 @@ __all__ = ["run", "runctx", "Profile"] import _lsprof +import io import profile as _pyprofile # ____________________________________________________________ @@ -183,7 +184,7 @@ def main(): else: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) - with open(progname, 'rb') as fp: + with io.open_code(progname) as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, diff --git a/Lib/profile.py b/Lib/profile.py index df4450dac6a1..bf43e37d0b24 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -24,6 +24,7 @@ # governing permissions and limitations under the License. +import io import sys import time import marshal @@ -603,7 +604,7 @@ def main(): else: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) - with open(progname, 'rb') as fp: + with io.open_code(progname) as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, diff --git a/Lib/trace.py b/Lib/trace.py index 89f17d485f35..3b5e564978d8 100755 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -49,6 +49,7 @@ """ __all__ = ['Trace', 'CoverageResults'] +import io import linecache import os import sys @@ -732,7 +733,7 @@ def parse_ignore_dir(s): sys.argv = [opts.progname, *opts.arguments] sys.path[0] = os.path.dirname(opts.progname) - with open(opts.progname, 'rb') as fp: + with io.open_code(opts.progname) as fp: code = compile(fp.read(), opts.progname, 'exec') # try to emulate __main__ namespace as much as possible globs = { diff --git a/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst b/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst new file mode 100644 index 000000000000..71b2d87249c4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst @@ -0,0 +1 @@ +Use :func:`io.open_code` for files to be executed instead of raw :func:`open` From webhook-mailer at python.org Mon May 22 06:40:11 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:40:11 -0000 Subject: [Python-checkins] [3.8] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104332) Message-ID: <mailman.525.1684752013.13550.python-checkins@python.org> https://github.com/python/cpython/commit/47ec96a11e3a208c89f025c97fa149201e56aaf0 commit: 47ec96a11e3a208c89f025c97fa149201e56aaf0 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:39:26+02:00 summary: [3.8] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104332) (cherry picked from commit 0aeda297931820436a50b78f4f7f0597274b5df4) Co-authored-by: Sam Carroll <70000253+samcarroll42 at users.noreply.github.com> files: A Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst M Lib/test/test_uu.py M Lib/uu.py diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py index c8709f7a0d66..e5d93d6cd1c4 100644 --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -145,6 +145,34 @@ def test_newlines_escaped(self): uu.encode(inp, out, filename) self.assertIn(safefilename, out.getvalue()) + def test_no_directory_traversal(self): + relative_bad = b"""\ +begin 644 ../../../../../../../../tmp/test1 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad)) + if os.altsep: + relative_bad_bs = relative_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad_bs)) + + absolute_bad = b"""\ +begin 644 /tmp/test2 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad)) + if os.altsep: + absolute_bad_bs = absolute_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad_bs)) + + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Lib/uu.py b/Lib/uu.py old mode 100755 new mode 100644 index 9f1f37f1a641..9fe252a639ea --- a/Lib/uu.py +++ b/Lib/uu.py @@ -130,7 +130,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False): # If the filename isn't ASCII, what's up with that?!? out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii") if os.path.exists(out_file): - raise Error('Cannot overwrite existing file: %s' % out_file) + raise Error(f'Cannot overwrite existing file: {out_file}') + if (out_file.startswith(os.sep) or + f'..{os.sep}' in out_file or ( + os.altsep and + (out_file.startswith(os.altsep) or + f'..{os.altsep}' in out_file)) + ): + raise Error(f'Refusing to write to {out_file} due to directory traversal') if mode is None: mode = int(hdrfields[1], 8) # diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst new file mode 100644 index 000000000000..b7002e81b6b6 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst @@ -0,0 +1,2 @@ +Fixed a security in flaw in :func:`uu.decode` that could allow for +directory traversal based on the input if no ``out_file`` was specified. From webhook-mailer at python.org Mon May 22 06:40:37 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:40:37 -0000 Subject: [Python-checkins] [3.9] gh-103935: Use `io.open_code()` when executing code in trace and profile modules (GH-103947) (#103953) Message-ID: <mailman.526.1684752038.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d1645ce4f1075d0a6ce051aa10f54f35489aa605 commit: d1645ce4f1075d0a6ce051aa10f54f35489aa605 branch: 3.9 author: Steve Dower <steve.dower at python.org> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:40:30+02:00 summary: [3.9] gh-103935: Use `io.open_code()` when executing code in trace and profile modules (GH-103947) (#103953) Co-authored-by: Tian Gao <gaogaotiantian at hotmail.com> files: A Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst M Lib/cProfile.py M Lib/profile.py M Lib/trace.py diff --git a/Lib/cProfile.py b/Lib/cProfile.py index 22a7d0aade85..9ae1fb8859e5 100755 --- a/Lib/cProfile.py +++ b/Lib/cProfile.py @@ -7,6 +7,7 @@ __all__ = ["run", "runctx", "Profile"] import _lsprof +import io import profile as _pyprofile # ____________________________________________________________ @@ -167,7 +168,7 @@ def main(): else: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) - with open(progname, 'rb') as fp: + with io.open_code(progname) as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, diff --git a/Lib/profile.py b/Lib/profile.py index d8599fb4eebd..90c4e4c9ff58 100755 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -24,6 +24,7 @@ # governing permissions and limitations under the License. +import io import sys import time import marshal @@ -587,7 +588,7 @@ def main(): else: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) - with open(progname, 'rb') as fp: + with io.open_code(progname) as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, diff --git a/Lib/trace.py b/Lib/trace.py index c505d8bc72a9..5e1f9cc4715a 100755 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -49,6 +49,7 @@ """ __all__ = ['Trace', 'CoverageResults'] +import io import linecache import os import sys @@ -716,7 +717,7 @@ def parse_ignore_dir(s): sys.argv = [opts.progname, *opts.arguments] sys.path[0] = os.path.dirname(opts.progname) - with open(opts.progname, 'rb') as fp: + with io.open_code(opts.progname) as fp: code = compile(fp.read(), opts.progname, 'exec') # try to emulate __main__ namespace as much as possible globs = { diff --git a/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst b/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst new file mode 100644 index 000000000000..71b2d87249c4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst @@ -0,0 +1 @@ +Use :func:`io.open_code` for files to be executed instead of raw :func:`open` From webhook-mailer at python.org Mon May 22 06:40:57 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:40:57 -0000 Subject: [Python-checkins] [3.9] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104120) Message-ID: <mailman.527.1684752058.13550.python-checkins@python.org> https://github.com/python/cpython/commit/b53d0ff4312cc2a67b9c5752844b140c08514648 commit: b53d0ff4312cc2a67b9c5752844b140c08514648 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:40:50+02:00 summary: [3.9] gh-104049: do not expose on-disk location from SimpleHTTPRequestHandler (GH-104067) (#104120) Do not expose the local server's on-disk location from `SimpleHTTPRequestHandler` when generating a directory index. (unnecessary information disclosure) (cherry picked from commit c7c3a60c88de61a79ded9fdaf6bc6a29da4efb9a) Co-authored-by: Ethan Furman <ethan at stoneleaf.us> Co-authored-by: Gregory P. Smith <greg at krypto.org> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst M Lib/http/server.py M Lib/test/test_httpservers.py diff --git a/Lib/http/server.py b/Lib/http/server.py index cf8933c3dbd9..969df7335fbc 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -791,7 +791,7 @@ def list_directory(self, path): displaypath = urllib.parse.unquote(self.path, errors='surrogatepass') except UnicodeDecodeError: - displaypath = urllib.parse.unquote(path) + displaypath = urllib.parse.unquote(self.path) displaypath = html.escape(displaypath, quote=False) enc = sys.getfilesystemencoding() title = 'Directory listing for %s' % displaypath diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index db9ee29e5fbe..153206da1a31 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -415,6 +415,14 @@ def test_undecodable_filename(self): self.check_status_and_reason(response, HTTPStatus.OK, data=support.TESTFN_UNDECODABLE) + def test_undecodable_parameter(self): + # sanity check using a valid parameter + response = self.request(self.base_url + '/?x=123').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + # now the bogus encoding + response = self.request(self.base_url + '/?x=%bb').read() + self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. diff --git a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst new file mode 100644 index 000000000000..969deb26bfeb --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst @@ -0,0 +1,2 @@ +Do not expose the local on-disk location in directory indexes +produced by :class:`http.client.SimpleHTTPRequestHandler`. From webhook-mailer at python.org Mon May 22 06:41:36 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:41:36 -0000 Subject: [Python-checkins] [3.9] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104331) Message-ID: <mailman.528.1684752097.13550.python-checkins@python.org> https://github.com/python/cpython/commit/3d5dd1eee265ec43dd96d89656c2a1c207dd5815 commit: 3d5dd1eee265ec43dd96d89656c2a1c207dd5815 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:41:30+02:00 summary: [3.9] gh-99889: Fix directory traversal security flaw in uu.decode() (GH-104096) (#104331) (cherry picked from commit 0aeda297931820436a50b78f4f7f0597274b5df4) Co-authored-by: Sam Carroll <70000253+samcarroll42 at users.noreply.github.com> files: A Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst M Lib/test/test_uu.py M Lib/uu.py diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py index 4c639b7bd55a6..410eb8e392478 100644 --- a/Lib/test/test_uu.py +++ b/Lib/test/test_uu.py @@ -145,6 +145,34 @@ def test_newlines_escaped(self): uu.encode(inp, out, filename) self.assertIn(safefilename, out.getvalue()) + def test_no_directory_traversal(self): + relative_bad = b"""\ +begin 644 ../../../../../../../../tmp/test1 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad)) + if os.altsep: + relative_bad_bs = relative_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(relative_bad_bs)) + + absolute_bad = b"""\ +begin 644 /tmp/test2 +$86)C"@`` +` +end +""" + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad)) + if os.altsep: + absolute_bad_bs = absolute_bad.replace(b'/', b'\\') + with self.assertRaisesRegex(uu.Error, 'directory'): + uu.decode(io.BytesIO(absolute_bad_bs)) + + class UUStdIOTest(unittest.TestCase): def setUp(self): diff --git a/Lib/uu.py b/Lib/uu.py old mode 100755 new mode 100644 index 9f1f37f1a6410..9fe252a639eac --- a/Lib/uu.py +++ b/Lib/uu.py @@ -130,7 +130,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False): # If the filename isn't ASCII, what's up with that?!? out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii") if os.path.exists(out_file): - raise Error('Cannot overwrite existing file: %s' % out_file) + raise Error(f'Cannot overwrite existing file: {out_file}') + if (out_file.startswith(os.sep) or + f'..{os.sep}' in out_file or ( + os.altsep and + (out_file.startswith(os.altsep) or + f'..{os.altsep}' in out_file)) + ): + raise Error(f'Refusing to write to {out_file} due to directory traversal') if mode is None: mode = int(hdrfields[1], 8) # diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst new file mode 100644 index 0000000000000..b7002e81b6b67 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst @@ -0,0 +1,2 @@ +Fixed a security in flaw in :func:`uu.decode` that could allow for +directory traversal based on the input if no ``out_file`` was specified. From webhook-mailer at python.org Mon May 22 06:42:44 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:42:44 -0000 Subject: [Python-checkins] [3.9] gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (GH-104575) (GH-104592) (#104593) Message-ID: <mailman.529.1684752165.13550.python-checkins@python.org> https://github.com/python/cpython/commit/d7f8a5fe07b0ff3a419ccec434cc405b21a5a304 commit: d7f8a5fe07b0ff3a419ccec434cc405b21a5a304 branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:42:37+02:00 summary: [3.9] gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) (GH-104575) (GH-104592) (#104593) gh-102153: Start stripping C0 control and space chars in `urlsplit` (GH-102508) `urllib.parse.urlsplit` has already been respecting the WHATWG spec a bit GH-25595. This adds more sanitizing to respect the "Remove any leading C0 control or space from input" [rule](https://url.spec.whatwg.org/GH-url-parsing:~:text=Remove%20any%20leading%20and%20trailing%20C0%20control%20or%20space%20from%20input.) in response to [CVE-2023-24329](https://nvd.nist.gov/vuln/detail/CVE-2023-24329). I simplified the docs by eliding the state of the world explanatory paragraph in this security release only backport. (people will see that in the mainline /3/ docs) (cherry picked from commit 2f630e1ce18ad2e07428296532a68b11dc66ad10) (cherry picked from commit 610cc0ab1b760b2abaac92bd256b96191c46b941) (cherry picked from commit f48a96a28012d28ae37a2f4587a780a5eb779946) Co-authored-by: Illia Volochii <illia.volochii at gmail.com> Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst M Doc/library/urllib.parse.rst M Lib/test/test_urlparse.py M Lib/urllib/parse.py diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index f0f8605128f4..9de30a182f47 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -159,6 +159,10 @@ or on combining URL components into a URL string. ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html', params='', query='', fragment='') + .. warning:: + + :func:`urlparse` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.2 Added IPv6 URL parsing capabilities. @@ -323,8 +327,14 @@ or on combining URL components into a URL string. ``#``, ``@``, or ``:`` will raise a :exc:`ValueError`. If the URL is decomposed before parsing, no error will be raised. - Following the `WHATWG spec`_ that updates RFC 3986, ASCII newline - ``\n``, ``\r`` and tab ``\t`` characters are stripped from the URL. + Following some of the `WHATWG spec`_ that updates RFC 3986, leading C0 + control and space characters are stripped from the URL. ``\n``, + ``\r`` and tab ``\t`` characters are removed from the URL at any position. + + .. warning:: + + :func:`urlsplit` does not perform validation. See :ref:`URL parsing + security <url-parsing-security>` for details. .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of @@ -337,6 +347,9 @@ or on combining URL components into a URL string. .. versionchanged:: 3.9.5 ASCII newline and tab characters are stripped from the URL. + .. versionchanged:: 3.9.17 + Leading WHATWG C0 control and space characters are stripped from the URL. + .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser .. function:: urlunsplit(parts) @@ -413,6 +426,27 @@ or on combining URL components into a URL string. or ``scheme://host/path``). If *url* is not a wrapped URL, it is returned without changes. +.. _url-parsing-security: + +URL parsing security +-------------------- + +The :func:`urlsplit` and :func:`urlparse` APIs do not perform **validation** of +inputs. They may not raise errors on inputs that other applications consider +invalid. They may also succeed on some inputs that might not be considered +URLs elsewhere. Their purpose is for practical functionality rather than +purity. + +Instead of raising an exception on unusual input, they may instead return some +component parts as empty strings. Or components may contain more than perhaps +they should. + +We recommend that users of these APIs where the values may be used anywhere +with security implications code defensively. Do some verification within your +code before trusting a returned component part. Does that ``scheme`` make +sense? Is that a sensible ``path``? Is there anything strange about that +``hostname``? etc. + .. _parsing-ascii-encoded-bytes: Parsing ASCII Encoded Bytes diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index 31943f357f49..574da5bd696e 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -649,6 +649,65 @@ def test_urlsplit_remove_unsafe_bytes(self): self.assertEqual(p.scheme, "http") self.assertEqual(p.geturl(), "http://www.python.org/javascript:alert('msg')/?query=something#fragment") + def test_urlsplit_strip_url(self): + noise = bytes(range(0, 0x20 + 1)) + base_url = "http://User:Pass at www.python.org:080/doc/?query=yes#frag" + + url = noise.decode("utf-8") + base_url + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, "http") + self.assertEqual(p.netloc, "User:Pass at www.python.org:080") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query=yes") + self.assertEqual(p.fragment, "frag") + self.assertEqual(p.username, "User") + self.assertEqual(p.password, "Pass") + self.assertEqual(p.hostname, "www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url) + + url = noise + base_url.encode("utf-8") + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"User:Pass at www.python.org:080") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"query=yes") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, b"User") + self.assertEqual(p.password, b"Pass") + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), base_url.encode("utf-8")) + + # Test that trailing space is preserved as some applications rely on + # this within query strings. + query_spaces_url = "https://www.python.org:88/doc/?query= " + p = urllib.parse.urlsplit(noise.decode("utf-8") + query_spaces_url) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.netloc, "www.python.org:88") + self.assertEqual(p.path, "/doc/") + self.assertEqual(p.query, "query= ") + self.assertEqual(p.port, 88) + self.assertEqual(p.geturl(), query_spaces_url) + + p = urllib.parse.urlsplit("www.pypi.org ") + # That "hostname" gets considered a "path" due to the + # trailing space and our existing logic... YUCK... + # and re-assembles via geturl aka unurlsplit into the original. + # django.core.validators.URLValidator (at least through v3.2) relies on + # this, for better or worse, to catch it in a ValidationError via its + # regular expressions. + # Here we test the basic round trip concept of such a trailing space. + self.assertEqual(urllib.parse.urlunsplit(p), "www.pypi.org ") + + # with scheme as cache-key + url = "//www.python.org/" + scheme = noise.decode("utf-8") + "https" + noise.decode("utf-8") + for _ in range(2): + p = urllib.parse.urlsplit(url, scheme=scheme) + self.assertEqual(p.scheme, "https") + self.assertEqual(p.geturl(), "https://www.python.org/") + def test_attributes_bad_port(self): """Check handling of invalid ports.""" for bytes in (False, True): @@ -656,7 +715,7 @@ def test_attributes_bad_port(self): for port in ("foo", "1.5", "-1", "0x10"): with self.subTest(bytes=bytes, parse=parse, port=port): netloc = "www.example.net:" + port - url = "http://" + netloc + url = "http://" + netloc + "/" if bytes: netloc = netloc.encode("ascii") url = url.encode("ascii") diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index b7965fe3d2b1..5b7193f67c6a 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -25,6 +25,10 @@ scenarios for parsing, and for backward compatibility purposes, some parsing quirks from older RFCs are retained. The testcases in test_urlparse.py provides a good indicator of parsing behavior. + +The WHATWG URL Parser spec should also be considered. We are not compliant with +it either due to existing user code API behavior expectations (Hyrum's Law). +It serves as a useful guide when making changes. """ import re @@ -78,6 +82,10 @@ '0123456789' '+-.') +# Leading and trailing C0 control and space to be stripped per WHATWG spec. +# == "".join([chr(i) for i in range(0, 0x20 + 1)]) +_WHATWG_C0_CONTROL_OR_SPACE = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f ' + # Unsafe bytes to be removed per WHATWG spec _UNSAFE_URL_BYTES_TO_REMOVE = ['\t', '\r', '\n'] @@ -456,6 +464,10 @@ def urlsplit(url, scheme='', allow_fragments=True): """ url, scheme, _coerce_result = _coerce_args(url, scheme) + # Only lstrip url as some applications rely on preserving trailing space. + # (https://url.spec.whatwg.org/#concept-basic-url-parser would strip both) + url = url.lstrip(_WHATWG_C0_CONTROL_OR_SPACE) + scheme = scheme.strip(_WHATWG_C0_CONTROL_OR_SPACE) for b in _UNSAFE_URL_BYTES_TO_REMOVE: url = url.replace(b, "") diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst new file mode 100644 index 000000000000..e57ac4ed3ac5 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst @@ -0,0 +1,3 @@ +:func:`urllib.parse.urlsplit` now strips leading C0 control and space +characters following the specification for URLs defined by WHATWG in +response to CVE-2023-24329. Patch by Illia Volochii. From webhook-mailer at python.org Mon May 22 06:46:52 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:46:52 -0000 Subject: [Python-checkins] [3.11] Add IPv6 into to the docstring for socket.getsockname (GH-102961) (#103137) Message-ID: <mailman.530.1684752414.13550.python-checkins@python.org> https://github.com/python/cpython/commit/1692a16a25e54696a42725fd35e14005492fc09f commit: 1692a16a25e54696a42725fd35e14005492fc09f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:46:45+02:00 summary: [3.11] Add IPv6 into to the docstring for socket.getsockname (GH-102961) (#103137) Add IPv6 into to the docstring for socket.getsockname (GH-102961) (cherry picked from commit ecc5441505cd7cb54f3d38409c732e2e9f102137) Signed-off-by: Brian Haley <haleyb.dev at gmail.com> Co-authored-by: Brian Haley <brianphaley at gmail.com> files: M Modules/socketmodule.c diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 47539d354b49..65d0e10fd253 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3411,7 +3411,8 @@ PyDoc_STRVAR(getsockname_doc, \n\ Return the address of the local endpoint. The format depends on the\n\ address family. For IPv4 sockets, the address info is a pair\n\ -(hostaddr, port)."); +(hostaddr, port). For IPv6 sockets, the address info is a 4-tuple\n\ +(hostaddr, port, flowinfo, scope_id)."); #endif From webhook-mailer at python.org Mon May 22 06:47:19 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:47:19 -0000 Subject: [Python-checkins] [3.11] gh-102978: Fix mock.patch function signatures for class and staticmethod decorators (GH-103228) (#103499) Message-ID: <mailman.531.1684752440.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e95ca78fab1c9ef288fcca72da7404236ba072bd commit: e95ca78fab1c9ef288fcca72da7404236ba072bd branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:47:12+02:00 summary: [3.11] gh-102978: Fix mock.patch function signatures for class and staticmethod decorators (GH-103228) (#103499) Fixes unittest.mock.patch not enforcing function signatures for methods decorated with @classmethod or @staticmethod when patch is called with autospec=True. (cherry picked from commit 59e0de4903c02e72b329e505fddf1ad9794928bc) Co-authored-by: Tomas R <tomas.roun8 at gmail.com> files: A Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst M Lib/unittest/mock.py M Lib/unittest/test/testmock/testhelpers.py M Lib/unittest/test/testmock/testpatch.py M Misc/ACKS diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 54bd3ecdd76f..e78eb350b8c0 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/Lib/unittest/test/testmock/testhelpers.py b/Lib/unittest/test/testmock/testhelpers.py index dc4d004cda8a..74785a83757a 100644 --- a/Lib/unittest/test/testmock/testhelpers.py +++ b/Lib/unittest/test/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/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py index 8ab63a1317d3..cda286bb74d6 100644 --- a/Lib/unittest/test/testmock/testpatch.py +++ b/Lib/unittest/test/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/Misc/ACKS b/Misc/ACKS index d0f32281d899..eba0ffba9a63 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1533,6 +1533,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 Mon May 22 06:49:40 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 22 May 2023 10:49:40 -0000 Subject: [Python-checkins] [3.11] gh-104536: Improve `multiprocessing.process._cleanup` logic (GH-104537) (#104737) Message-ID: <mailman.532.1684752582.13550.python-checkins@python.org> https://github.com/python/cpython/commit/6f94bbf77e28966fe0d789b5aa477f547ccddae9 commit: 6f94bbf77e28966fe0d789b5aa477f547ccddae9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv <lukasz at langa.pl> date: 2023-05-22T12:49:33+02:00 summary: [3.11] gh-104536: Improve `multiprocessing.process._cleanup` logic (GH-104537) (#104737) Fix a race condition in the internal `multiprocessing.process` cleanup logic that could manifest as an unintended `AttributeError` when calling `BaseProcess.close()`. (cherry picked from commit ef5d00a59207a63c6d5ae0d5d44054847d1bf3b5) Co-authored-by: Luccccifer <lukezhang764 at gmail.com> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> Co-authored-by: Gregory P. Smith <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst M Lib/multiprocessing/process.py diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py index c03c859baa79..271ba3fd3251 100644 --- a/Lib/multiprocessing/process.py +++ b/Lib/multiprocessing/process.py @@ -61,7 +61,7 @@ def parent_process(): def _cleanup(): # check for processes which have finished for p in list(_children): - if p._popen.poll() is not None: + if (child_popen := p._popen) and child_popen.poll() is not None: _children.discard(p) # diff --git a/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst b/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst new file mode 100644 index 000000000000..b0f5d78f7e61 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst @@ -0,0 +1,3 @@ +Fix a race condition in the internal :mod:`multiprocessing.process` cleanup +logic that could manifest as an unintended ``AttributeError`` when calling +``process.close()``. From webhook-mailer at python.org Mon May 22 07:30:50 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 22 May 2023 11:30:50 -0000 Subject: [Python-checkins] gh-104741: Add line number attribute to indentation error exception (#104743) Message-ID: <mailman.533.1684755051.13550.python-checkins@python.org> https://github.com/python/cpython/commit/729b252241966f464cc46e176fb854dbcc5296cb commit: 729b252241966f464cc46e176fb854dbcc5296cb branch: main author: Marta G?mez Mac?as <mgmacias at google.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-22T11:30:18Z summary: gh-104741: Add line number attribute to indentation error exception (#104743) files: M Lib/test/test_tabnanny.py M Lib/test/test_tokenize.py M Python/Python-tokenize.c diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index dac47318011d..aa700118f735 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -317,7 +317,7 @@ def test_with_errored_file(self): with TemporaryPyFile(SOURCE_CODES["wrong_indented"]) as file_path: stderr = f"{file_path!r}: Token Error: " stderr += ('unindent does not match any outer indentation level' - ' (<tokenize>, line 3)') + ' (<string>, line 3)') self.validate_cmd(file_path, stderr=stderr, expect_failure=True) def test_with_error_free_file(self): diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index dda7243bfa19..8e7ab3d4b7b5 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -92,9 +92,18 @@ def k(x): readline = BytesIO(indent_error_file).readline with self.assertRaisesRegex(IndentationError, "unindent does not match any " - "outer indentation level"): + "outer indentation level") as e: for tok in tokenize(readline): pass + self.assertEqual(e.exception.lineno, 3) + self.assertEqual(e.exception.filename, '<string>') + self.assertEqual(e.exception.end_lineno, None) + self.assertEqual(e.exception.end_offset, None) + self.assertEqual( + e.exception.msg, + 'unindent does not match any outer indentation level') + self.assertEqual(e.exception.offset, 9) + self.assertEqual(e.exception.text, ' x += 5\n') def test_int(self): # Ordinary integers and binary operators diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index 43b44be94583..f7e32d3af9a9 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -89,11 +89,9 @@ _tokenizer_error(struct tok_state *tok) } return -1; case E_DEDENT: - PyErr_Format(PyExc_IndentationError, - "unindent does not match any outer indentation level " - "(<tokenize>, line %d)", - tok->lineno); - return -1; + msg = "unindent does not match any outer indentation level"; + errtype = PyExc_IndentationError; + break; case E_INTR: if (!PyErr_Occurred()) { PyErr_SetNone(PyExc_KeyboardInterrupt); @@ -131,7 +129,12 @@ _tokenizer_error(struct tok_state *tok) goto exit; } - tmp = Py_BuildValue("(OnnOii)", tok->filename, tok->lineno, 0, error_line, 0, 0); + Py_ssize_t offset = _PyPegen_byte_offset_to_character_offset(error_line, tok->inp - tok->buf); + if (offset == -1) { + result = -1; + goto exit; + } + tmp = Py_BuildValue("(OnnOOO)", tok->filename, tok->lineno, offset, error_line, Py_None, Py_None); if (!tmp) { result = -1; goto exit; From webhook-mailer at python.org Mon May 22 07:45:27 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Mon, 22 May 2023 11:45:27 -0000 Subject: [Python-checkins] gh-101282: Apply BOLT optimizations to libpython for shared builds (#104709) Message-ID: <mailman.534.1684755928.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5360cb3d5608ab375de6cd8c0b408459f3fa953a commit: 5360cb3d5608ab375de6cd8c0b408459f3fa953a branch: main author: Gregory Szorc <gregory.szorc at gmail.com> committer: erlend-aasland <erlend.aasland at protonmail.com> date: 2023-05-22T13:45:20+02:00 summary: gh-101282: Apply BOLT optimizations to libpython for shared builds (#104709) Apply BOLT optimizations to libpython for shared builds. Most of the C code is in libpython so it is critical to apply BOLT there fully realize BOLT benefits. This change also reworks how BOLT instrumentation is applied. It effectively removes the readelf based logic added in gh-101525 and replaces it with a mechanism that saves a copy of the pre-bolt binary and restores that copy when necessary. This allows us to perform BOLT optimizations without having to manually delete the output binary to force a new bolt run. Also: - add a clean-bolt target for purging BOLT files and hook that up to the clean target - .gitignore BOLT related files Before and after this refactor, `make` will no-op after a previous run. Both versions should also share common make DAG deficiencies where targets fail to trigger as often as they need to or can trigger prematurely in certain scenarios. e.g. after this change you may need to `rm profile-bolt-stamp` to force a BOLT run because there aren't appropriate non-phony targets for BOLT's make target to depend on. To make it easier to iterate on custom BOLT settings, the flags to pass to instrumentation and application are now defined in configure and can be overridden by passing BOLT_INSTRUMENT_FLAGS and BOLT_APPLY_FLAGS. files: A Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst M .gitignore M Doc/using/configure.rst M Makefile.pre.in M configure M configure.ac diff --git a/.gitignore b/.gitignore index d9c4a7972f07..ef7642b09bc5 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,10 @@ *.gc?? *.profclang? *.profraw +# Copies of binaries before BOLT optimizations. +*.prebolt +# BOLT profile data. +*.fdata *.dyn .gdb_history .purify @@ -124,6 +128,7 @@ Tools/unicode/data/ /platform /profile-clean-stamp /profile-run-stamp +/profile-bolt-stamp /Python/deepfreeze/*.c /pybuilddir.txt /pyconfig.h diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index ce858ab2c8d7..fbe280d64131 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -314,6 +314,13 @@ also be used to improve performance. is dependent on a combination of the build environment + the other optimization configure args + the CPU architecture, and not all combinations are supported. + BOLT versions before LLVM 16 are known to crash BOLT under some scenarios. + Use of LLVM 16 or newer for BOLT optimization is strongly encouraged. + + The :envvar:`!BOLT_INSTRUMENT_FLAGS` and :envvar:`!BOLT_APPLY_FLAGS` + :program:`configure` variables can be defined to override the default set of + arguments for :program:`llvm-bolt` to instrument and apply BOLT data to + binaries, respectively. .. versionadded:: 3.12 diff --git a/Makefile.pre.in b/Makefile.pre.in index da3a8f6c13f9..eb79c9c4ca18 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -672,21 +672,55 @@ profile-opt: profile-run-stamp -rm -f profile-clean-stamp $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_USE_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST)" -.PHONY: bolt-opt -bolt-opt: @PREBOLT_RULE@ +# List of binaries that BOLT runs on. +BOLT_BINARIES := @BOLT_BINARIES@ + +BOLT_INSTRUMENT_FLAGS := @BOLT_INSTRUMENT_FLAGS@ +BOLT_APPLY_FLAGS := @BOLT_APPLY_FLAGS@ + +.PHONY: clean-bolt +clean-bolt: + # Profile data. rm -f *.fdata - @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 + # Pristine binaries before BOLT optimization. + rm -f *.prebolt + # BOLT instrumented binaries. + rm -f *.bolt_inst + +profile-bolt-stamp: $(BUILDPYTHON) + # Ensure a pristine, pre-BOLT copy of the binary and no profile data from last run. + for bin in $(BOLT_BINARIES); do \ + prebolt="$${bin}.prebolt"; \ + if [ -e "$${prebolt}" ]; then \ + echo "Restoring pre-BOLT binary $${prebolt}"; \ + mv "$${bin}.prebolt" "$${bin}"; \ + fi; \ + cp "$${bin}" "$${prebolt}"; \ + rm -f $${bin}.bolt.*.fdata $${bin}.fdata; \ + done + # Instrument each binary. + for bin in $(BOLT_BINARIES); do \ + @LLVM_BOLT@ "$${bin}" -instrument -instrumentation-file-append-pid -instrumentation-file=$(abspath $${bin}.bolt) -o $${bin}.bolt_inst $(BOLT_INSTRUMENT_FLAGS); \ + mv "$${bin}.bolt_inst" "$${bin}"; \ + done + # Run instrumented binaries to collect data. + $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) || true + # Merge all the data files together. + for bin in $(BOLT_BINARIES); do \ + @MERGE_FDATA@ $${bin}.*.fdata > "$${bin}.fdata"; \ + rm -f $${bin}.*.fdata; \ + done + # Run bolt against the merged data to produce an optimized binary. + for bin in $(BOLT_BINARIES); do \ + @LLVM_BOLT@ "$${bin}.prebolt" -o "$${bin}.bolt" -data="$${bin}.fdata" $(BOLT_APPLY_FLAGS); \ + mv "$${bin}.bolt" "$${bin}"; \ + done + touch $@ +.PHONY: bolt-opt +bolt-opt: + $(MAKE) @PREBOLT_RULE@ + $(MAKE) profile-bolt-stamp # Compile and run with gcov .PHONY: coverage @@ -2623,10 +2657,11 @@ profile-removal: rm -f $(COVERAGE_INFO) rm -rf $(COVERAGE_REPORT) rm -f profile-run-stamp + rm -f profile-bolt-stamp .PHONY: clean -clean: clean-retain-profile - @if test @DEF_MAKE_ALL_RULE@ = profile-opt; then \ +clean: clean-retain-profile clean-bolt + @if test @DEF_MAKE_ALL_RULE@ = profile-opt -o @DEF_MAKE_ALL_RULE@ = bolt-opt; then \ rm -f profile-gen-stamp profile-clean-stamp; \ $(MAKE) profile-removal; \ fi diff --git a/Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst b/Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst new file mode 100644 index 000000000000..cc70d47c6c16 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst @@ -0,0 +1,4 @@ +BOLT optimization is now applied to the libpython shared library if building +a shared library. BOLT instrumentation and application settings can now be +influenced via the ``BOLT_INSTRUMENT_FLAGS`` and ``BOLT_APPLY_FLAGS`` +configure variables. diff --git a/configure b/configure index 7aad4fe89e3c..2b863be108be 100755 --- a/configure +++ b/configure @@ -883,10 +883,11 @@ CFLAGS_NODIST BASECFLAGS CFLAGS_ALIASING OPT +BOLT_APPLY_FLAGS +BOLT_INSTRUMENT_FLAGS +BOLT_BINARIES MERGE_FDATA LLVM_BOLT -ac_ct_READELF -READELF PREBOLT_RULE LLVM_PROF_FOUND LLVM_PROFDATA @@ -1105,6 +1106,8 @@ CPPFLAGS CPP HOSTRUNNER PROFILE_TASK +BOLT_INSTRUMENT_FLAGS +BOLT_APPLY_FLAGS LIBUUID_CFLAGS LIBUUID_LIBS LIBFFI_CFLAGS @@ -1916,6 +1919,10 @@ Some influential environment variables: HOSTRUNNER Program to run CPython for the host platform PROFILE_TASK Python args for PGO generation task + BOLT_INSTRUMENT_FLAGS + Arguments to llvm-bolt when instrumenting binaries + BOLT_APPLY_FLAGS + Arguments to llvm-bolt when creating a BOLT optimized binary LIBUUID_CFLAGS C compiler flags for LIBUUID, overriding pkg-config LIBUUID_LIBS @@ -8106,112 +8113,6 @@ 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 @@ -8474,6 +8375,36 @@ $as_echo "\"Found merge-fdata\"" >&6; } fi fi + +BOLT_BINARIES='$(BUILDPYTHON)' +if test "x$enable_shared" = xyes; then : + + BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)" + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking BOLT_INSTRUMENT_FLAGS" >&5 +$as_echo_n "checking BOLT_INSTRUMENT_FLAGS... " >&6; } +if test -z "${BOLT_INSTRUMENT_FLAGS}" +then + BOLT_INSTRUMENT_FLAGS= +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_INSTRUMENT_FLAGS" >&5 +$as_echo "$BOLT_INSTRUMENT_FLAGS" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking BOLT_APPLY_FLAGS" >&5 +$as_echo_n "checking BOLT_APPLY_FLAGS... " >&6; } +if test -z "${BOLT_APPLY_FLAGS}" +then + BOLT_APPLY_FLAGS=-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 + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 +$as_echo "$BOLT_APPLY_FLAGS" >&6; } + # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be # merged with this chunk of code? diff --git a/configure.ac b/configure.ac index 115998e0753b..786d3414eb0e 100644 --- a/configure.ac +++ b/configure.ac @@ -2028,13 +2028,6 @@ 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],[ @@ -2067,6 +2060,54 @@ if test "$Py_BOLT" = 'true' ; then fi fi +dnl Enable BOLT of libpython if built. +AC_SUBST(BOLT_BINARIES) +BOLT_BINARIES='$(BUILDPYTHON)' +AS_VAR_IF([enable_shared], [yes], [ + BOLT_BINARIES="${BOLT_BINARIES} \$(INSTSONAME)" +]) + +AC_ARG_VAR( + [BOLT_INSTRUMENT_FLAGS], + [Arguments to llvm-bolt when instrumenting binaries] +) +AC_MSG_CHECKING([BOLT_INSTRUMENT_FLAGS]) +if test -z "${BOLT_INSTRUMENT_FLAGS}" +then + BOLT_INSTRUMENT_FLAGS= +fi +AC_MSG_RESULT([$BOLT_INSTRUMENT_FLAGS]) + +AC_ARG_VAR( + [BOLT_APPLY_FLAGS], + [Arguments to llvm-bolt when creating a BOLT optimized binary] +) +AC_MSG_CHECKING([BOLT_APPLY_FLAGS]) +if test -z "${BOLT_APPLY_FLAGS}" +then + AS_VAR_SET( + [BOLT_APPLY_FLAGS], + [m4_join([ ], + [-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] + )] + ) +fi +AC_MSG_RESULT([$BOLT_APPLY_FLAGS]) + # XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be # merged with this chunk of code? From webhook-mailer at python.org Mon May 22 09:03:36 2023 From: webhook-mailer at python.org (JulienPalard) Date: Mon, 22 May 2023 13:03:36 -0000 Subject: [Python-checkins] howto/urllib2: remove link to an outdated french translation (GH-104193) Message-ID: <mailman.535.1684760616.13550.python-checkins@python.org> https://github.com/python/cpython/commit/151b6bfb5d9a15b6e2682e5a3008a3f9ec3086ae commit: 151b6bfb5d9a15b6e2682e5a3008a3f9ec3086ae branch: main author: Mathieu Dupuy <deronnax at gmail.com> committer: JulienPalard <julien at palard.fr> date: 2023-05-22T15:03:29+02:00 summary: howto/urllib2: remove link to an outdated french translation (GH-104193) We now have our own translation and it's not outdated files: M Doc/howto/urllib2.rst diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 61ba6bd7224f..86137fb38c9b 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -6,13 +6,6 @@ :Author: `Michael Foord <https://agileabstractions.com/>`_ -.. note:: - - There is a French translation of an earlier revision of this - HOWTO, available at `urllib2 - Le Manuel manquant - <https://web.archive.org/web/20200910051922/http://www.voidspace.org.uk/python/articles/urllib2_francais.shtml>`_. - - Introduction ============ From webhook-mailer at python.org Mon May 22 10:12:26 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 22 May 2023 14:12:26 -0000 Subject: [Python-checkins] GH-101291: Avoid using macros with casts in low-level long API. (#104742) Message-ID: <mailman.536.1684764748.13550.python-checkins@python.org> https://github.com/python/cpython/commit/e295d8605699ad3d8ec46c8d55a5e47da05b20c6 commit: e295d8605699ad3d8ec46c8d55a5e47da05b20c6 branch: main author: Mark Shannon <mark at hotpy.org> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-05-22T15:12:19+01:00 summary: GH-101291: Avoid using macros with casts in low-level long API. (#104742) files: M Include/cpython/longintrepr.h diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 0f569935fff1..692c69ba76db 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -104,9 +104,10 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); #define _PyLong_SIGN_MASK 3 #define _PyLong_NON_SIZE_BITS 3 + static inline int _PyLong_IsCompact(const PyLongObject* op) { - assert(PyLong_Check(op)); + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); } @@ -115,7 +116,7 @@ _PyLong_IsCompact(const PyLongObject* op) { static inline Py_ssize_t _PyLong_CompactValue(const PyLongObject *op) { - assert(PyLong_Check(op)); + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); assert(PyUnstable_Long_IsCompact(op)); Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); return sign * (Py_ssize_t)op->long_value.ob_digit[0]; From webhook-mailer at python.org Mon May 22 13:57:51 2023 From: webhook-mailer at python.org (JulienPalard) Date: Mon, 22 May 2023 17:57:51 -0000 Subject: [Python-checkins] [3.11] howto/urllib2: remove link to an outdated french translation (GH-104193) (GH-104746) Message-ID: <mailman.537.1684778273.13550.python-checkins@python.org> https://github.com/python/cpython/commit/be20e9c6470775b7900a735c23afb3675354b146 commit: be20e9c6470775b7900a735c23afb3675354b146 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JulienPalard <julien at palard.fr> date: 2023-05-22T19:57:05+02:00 summary: [3.11] howto/urllib2: remove link to an outdated french translation (GH-104193) (GH-104746) howto/urllib2: remove link to an outdated french translation (GH-104193) We now have our own translation and it's not outdated (cherry picked from commit 151b6bfb5d9a15b6e2682e5a3008a3f9ec3086ae) Co-authored-by: Mathieu Dupuy <deronnax at gmail.com> files: M Doc/howto/urllib2.rst diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 61ba6bd7224f..86137fb38c9b 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -6,13 +6,6 @@ :Author: `Michael Foord <https://agileabstractions.com/>`_ -.. note:: - - There is a French translation of an earlier revision of this - HOWTO, available at `urllib2 - Le Manuel manquant - <https://web.archive.org/web/20200910051922/http://www.voidspace.org.uk/python/articles/urllib2_francais.shtml>`_. - - Introduction ============ From webhook-mailer at python.org Mon May 22 15:16:15 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 19:16:15 -0000 Subject: [Python-checkins] Post 3.12.0b1 Message-ID: <mailman.538.1684782977.13550.python-checkins@python.org> https://github.com/python/cpython/commit/c2b127ed3ab44d404c502bd2f8f279253fd081e6 commit: c2b127ed3ab44d404c502bd2f8f279253fd081e6 branch: 3.12 author: Thomas Wouters <thomas at python.org> committer: Yhg1s <thomas at python.org> date: 2023-05-22T21:11:08+02:00 summary: Post 3.12.0b1 files: M Include/patchlevel.h diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 3de9ed9296a4..d71bef922e5b 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.12.0b1" +#define PY_VERSION "3.12.0b1+" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. From webhook-mailer at python.org Mon May 22 15:16:18 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 19:16:18 -0000 Subject: [Python-checkins] Python 3.12.0b1 Message-ID: <mailman.539.1684782979.13550.python-checkins@python.org> https://github.com/python/cpython/commit/5612078f68e9688fbf3b1d8565abc79b77501000 commit: 5612078f68e9688fbf3b1d8565abc79b77501000 branch: main author: Thomas Wouters <thomas at python.org> committer: Yhg1s <thomas at python.org> date: 2023-05-22T14:07:36+02:00 summary: Python 3.12.0b1 files: A Misc/NEWS.d/3.12.0b1.rst D Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst D Misc/NEWS.d/next/Build/2022-12-18-07-24-44.gh-issue-100220.BgSV7C.rst D Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst D Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst D Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst D Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst D Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst D Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst D Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst D Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst D Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst D Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst D Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst D Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst D Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst D Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst D Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst D Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst D Misc/NEWS.d/next/Core and Builtins/2019-12-01-12-58-31.bpo-31821.1FNmwk.rst D Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst D Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-32-11.gh-issue-98003.xWE0Yu.rst D Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst D Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-25-23-24-38.gh-issue-88691.2SWBd1.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-24-14-38-16.gh-issue-103793.kqoH6Q.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst D Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst D Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst D Misc/NEWS.d/next/Documentation/2023-03-07-23-30-29.gh-issue-99202.hhiAJF.rst D Misc/NEWS.d/next/Documentation/2023-03-10-04-59-35.gh-issue-86094.zOYdy8.rst D Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst D Misc/NEWS.d/next/Documentation/2023-04-26-23-55-31.gh-issue-103629.-0reqn.rst D Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst D Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst D Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst D Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst D Misc/NEWS.d/next/Library/2018-07-16-14-10-29.bpo-22708.592iRR.rst D Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst D Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst D Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst D Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst D Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst D Misc/NEWS.d/next/Library/2021-12-03-23-00-56.bpo-44844.tvg2VY.rst D Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst D Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst D Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst D Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst D Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst D Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst D Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst D Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst D Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst D Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst D Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst D Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst D Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst D Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst D Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst D Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst D Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst D Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst D Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst D Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst D Misc/NEWS.d/next/Library/2023-02-19-12-37-08.gh-issue-62432.GnBFIB.rst D Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst D Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst D Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst D Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst D Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst D Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst D Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst D Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst D Misc/NEWS.d/next/Library/2023-03-28-09-13-31.gh-issue-103015.ETTfNf.rst D Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst D Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst D Misc/NEWS.d/next/Library/2023-04-02-17-51-08.gh-issue-103193.xrZbM1.rst D Misc/NEWS.d/next/Library/2023-04-02-22-04-26.gh-issue-75586.526iJm.rst D Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst D Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst D Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst D Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst D Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst D Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst D Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst D Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst D Misc/NEWS.d/next/Library/2023-04-05-01-28-53.gh-issue-103225.QD3JVU.rst D Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst D Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst D Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst D Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst D Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst D Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst D Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst D Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst D Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst D Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst D Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst D Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst D Misc/NEWS.d/next/Library/2023-04-13-13-17-47.gh-issue-103489.ZSZgmu.rst D Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst D Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst D Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst D Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst D Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst D Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst D Misc/NEWS.d/next/Library/2023-04-16-18-29-04.gh-issue-103578.fly1wc.rst D Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst D Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst D Misc/NEWS.d/next/Library/2023-04-19-16-08-53.gh-issue-84976.HwbzlD.rst D Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst D Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst D Misc/NEWS.d/next/Library/2023-04-22-11-20-27.gh-issue-89415.YHk760.rst D Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst D Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst D Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst D Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst D Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst D Misc/NEWS.d/next/Library/2023-04-24-16-00-28.gh-issue-90750.da0Xi8.rst D Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst D Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst D Misc/NEWS.d/next/Library/2023-04-25-17-03-18.gh-issue-103857.Mr2Cak.rst D Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst D Misc/NEWS.d/next/Library/2023-04-25-22-06-00.gh-issue-74940.TOacQ9.rst D Misc/NEWS.d/next/Library/2023-04-25-22-59-06.gh-issue-99944.pst8iT.rst D Misc/NEWS.d/next/Library/2023-04-26-09-38-47.gh-issue-103872.8LBsDz.rst D Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst D Misc/NEWS.d/next/Library/2023-04-26-15-14-36.gh-issue-103583.iCMDFt.rst D Misc/NEWS.d/next/Library/2023-04-26-18-12-13.gh-issue-103636.-KvCgO.rst D Misc/NEWS.d/next/Library/2023-04-27-00-05-32.gh-issue-102628.X230E-.rst D Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst D Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst D Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst D Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst D Misc/NEWS.d/next/Library/2023-04-28-19-08-50.gh-issue-103977.msF70A.rst D Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst D Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst D Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst D Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst D Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst D Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst D Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst D Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst D Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst D Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst D Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst D Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst D Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst D Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst D Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst D Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst D Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst D Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst D Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst D Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst D Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst D Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst D Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst D Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst D Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst D Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst D Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst D Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst D Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst D Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst D Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst D Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst D Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst D Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst D Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst D Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst D Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst D Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst D Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst D Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst D Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst D Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst D Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst D Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst D Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst D Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst D Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst D Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst D Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst D Misc/NEWS.d/next/macOS/2023-04-04-13-37-28.gh-issue-103207.x0vvQp.rst D Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst D Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst D Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst D Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst D Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst M Doc/tools/extensions/pyspecific.py M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index cd8d9febb0d1..3a5b26f77796 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -41,7 +41,7 @@ ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s' GH_ISSUE_URI = 'https://github.com/python/cpython/issues/%s' -SOURCE_URI = 'https://github.com/python/cpython/tree/main/%s' +SOURCE_URI = 'https://github.com/python/cpython/tree/3.12/%s' # monkey-patch reST parser to disable alphabetic and roman enumerated lists from docutils.parsers.rst.states import Body diff --git a/Include/patchlevel.h b/Include/patchlevel.h index aaedd563a905..3de9ed9296a4 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -19,11 +19,11 @@ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 7 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "3.12.0a7+" +#define PY_VERSION "3.12.0b1" /*--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 3aaaee67fa35..cb742992a48e 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 Apr 4 17:52:21 2023 +# Autogenerated by Sphinx on Mon May 22 14:02:15 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -2573,9 +2573,12 @@ '\n' 'Any remaining exceptions that were not handled by any "except*" ' 'clause\n' - 'are re-raised at the end, combined into an exception group along ' - 'with\n' - 'all exceptions that were raised from within "except*" clauses.\n' + 'are re-raised at the end, along with all exceptions that were ' + 'raised\n' + 'from within the "except*" clauses. If this list contains more ' + 'than one\n' + 'exception to reraise, they are combined into an exception ' + 'group.\n' '\n' 'If the raised exception is not an exception group and its type ' 'matches\n' @@ -4587,8 +4590,7 @@ 'case\n' ' performance of a dict insertion, O(n^2) complexity. ' 'See\n' - ' http://www.ocert.org/advisories/ocert-2011-003.html ' - 'for\n' + ' http://ocert.org/advisories/ocert-2011-003.html for\n' ' details.Changing hash values affects the iteration ' 'order of sets.\n' ' Python has never made guarantees about this ordering ' @@ -4651,20 +4653,41 @@ 'traces of\n' ' Python programs.\n' '\n' - 'The debugger?s prompt is "(Pdb)". Typical usage to run a program ' - 'under\n' - 'control of the debugger is:\n' + 'The typical usage to break into the debugger is to insert:\n' '\n' - ' >>> import pdb\n' - ' >>> import mymodule\n' - " >>> pdb.run('mymodule.test()')\n" - ' > <string>(0)?()\n' - ' (Pdb) continue\n' - ' > <string>(1)?()\n' + ' import pdb; pdb.set_trace()\n' + '\n' + 'Or:\n' + '\n' + ' breakpoint()\n' + '\n' + 'at the location you want to break into the debugger, and then ' + 'run the\n' + 'program. You can then step through the code following this ' + 'statement,\n' + 'and continue running without the debugger using the "continue"\n' + 'command.\n' + '\n' + 'New in version 3.7: The built-in "breakpoint()", when called ' + 'with\n' + 'defaults, can be used instead of "import pdb; pdb.set_trace()".\n' + '\n' + ' def double(x):\n' + ' breakpoint()\n' + ' return x * 2\n' + ' val = 3\n' + ' print(f"{val} * 2 is {double(val)}")\n' + '\n' + 'The debugger?s prompt is "(Pdb)", which is the indicator that ' + 'you are\n' + 'in debug mode:\n' + '\n' + ' > ...(3)double()\n' + ' -> return x * 2\n' + ' (Pdb) p x\n' + ' 3\n' ' (Pdb) continue\n' - " NameError: 'spam'\n" - ' > <string>(1)?()\n' - ' (Pdb)\n' + ' 3 * 2 is 6\n' '\n' 'Changed in version 3.3: Tab-completion via the "readline" module ' 'is\n' @@ -4672,13 +4695,12 @@ 'global\n' 'and local names are offered as arguments of the "p" command.\n' '\n' - '"pdb.py" can also be invoked as a script to debug other ' - 'scripts. For\n' - 'example:\n' + 'You can also invoke "pdb" from the command line to debug other\n' + 'scripts. For example:\n' '\n' ' python -m pdb myscript.py\n' '\n' - 'When invoked as a script, pdb will automatically enter ' + 'When invoked as a module, pdb will automatically enter ' 'post-mortem\n' 'debugging if the program being debugged exits abnormally. After ' 'post-\n' @@ -4690,47 +4712,43 @@ 'the\n' 'debugger upon program?s exit.\n' '\n' - 'New in version 3.2: "pdb.py" now accepts a "-c" option that ' - 'executes\n' - 'commands as if given in a ".pdbrc" file, see Debugger Commands.\n' + 'New in version 3.2: "-c" option is introduced to execute ' + 'commands as\n' + 'if given in a ".pdbrc" file, see Debugger Commands.\n' '\n' - 'New in version 3.7: "pdb.py" now accepts a "-m" option that ' - 'execute\n' - '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' - '\n' - 'The typical usage to break into the debugger is to insert:\n' + 'New in version 3.7: "-m" option is introduced to execute ' + 'modules\n' + 'similar to the way "python -m" does. As with a script, the ' + 'debugger\n' + 'will pause execution just before the first line of the module.\n' '\n' - ' import pdb; pdb.set_trace()\n' + 'Typical usage to execute a statement under control of the ' + 'debugger is:\n' '\n' - 'at the location you want to break into the debugger, and then ' - 'run the\n' - 'program. You can then step through the code following this ' - 'statement,\n' - 'and continue running without the debugger using the "continue"\n' - 'command.\n' - '\n' - 'New in version 3.7: The built-in "breakpoint()", when called ' - 'with\n' - 'defaults, can be used instead of "import pdb; pdb.set_trace()".\n' + ' >>> import pdb\n' + ' >>> def f(x):\n' + ' ... print(1 / x)\n' + ' >>> pdb.run("f(2)")\n' + ' > <string>(1)<module>()\n' + ' (Pdb) continue\n' + ' 0.5\n' + ' >>>\n' '\n' 'The typical usage to inspect a crashed program is:\n' '\n' ' >>> import pdb\n' - ' >>> import mymodule\n' - ' >>> mymodule.test()\n' + ' >>> def f(x):\n' + ' ... print(1 / x)\n' + ' ...\n' + ' >>> f(0)\n' ' Traceback (most recent call last):\n' ' File "<stdin>", line 1, in <module>\n' - ' File "./mymodule.py", line 4, in test\n' - ' test2()\n' - ' File "./mymodule.py", line 3, in test2\n' - ' print(spam)\n' - ' NameError: spam\n' + ' File "<stdin>", line 2, in f\n' + ' ZeroDivisionError: division by zero\n' ' >>> pdb.pm()\n' - ' > ./mymodule.py(3)test2()\n' - ' -> print(spam)\n' + ' > <stdin>(2)f()\n' + ' (Pdb) p x\n' + ' 0\n' ' (Pdb)\n' '\n' 'The module defines the following functions; each enters the ' @@ -4914,6 +4932,29 @@ 'implicit\n' 'string concatenation "\';\'\';\'" or "";"";"".\n' '\n' + 'To set a temporary global variable, use a *convenience ' + 'variable*. A\n' + '*convenience variable* is a variable whose name starts with ' + '"$". For\n' + 'example, "$foo = 1" sets a global variable "$foo" which you can ' + 'use in\n' + 'the debugger session. The *convenience variables* are cleared ' + 'when\n' + 'the program resumes execution so it?s less likely to interfere ' + 'with\n' + 'your program compared to using normal variables like "foo = 1".\n' + '\n' + 'There are three preset *convenience variables*:\n' + '\n' + '* "$_frame": the current frame you are debugging\n' + '\n' + '* "$_retval": the return value if the frame is returning\n' + '\n' + '* "$_exception": the exception if the frame is raising an ' + 'exception\n' + '\n' + 'New in version 3.12.\n' + '\n' 'If a file ".pdbrc" exists in the user?s home directory or in ' 'the\n' 'current directory, it is read with "\'utf-8\'" encoding and ' @@ -4949,9 +4990,9 @@ '\n' ' Print a stack trace, with the most recent frame at the ' 'bottom. An\n' - ' arrow indicates the current frame, which determines the ' - 'context of\n' - ' most commands.\n' + ' arrow (">") indicates the current frame, which determines ' + 'the\n' + ' context of most commands.\n' '\n' 'd(own) [count]\n' '\n' @@ -5007,7 +5048,7 @@ 'first\n' ' ask confirmation).\n' '\n' - 'disable [bpnumber ...]\n' + 'disable bpnumber [bpnumber ...]\n' '\n' ' Disable the breakpoints given as a space separated list of\n' ' breakpoint numbers. Disabling a breakpoint means it cannot ' @@ -5016,7 +5057,7 @@ 'breakpoint, it\n' ' remains in the list of breakpoints and can be (re-)enabled.\n' '\n' - 'enable [bpnumber ...]\n' + 'enable bpnumber [bpnumber ...]\n' '\n' ' Enable the breakpoints specified.\n' '\n' @@ -5179,7 +5220,9 @@ '\n' 'a(rgs)\n' '\n' - ' Print the argument list of the current function.\n' + ' Print the arguments of the current function and their ' + 'current\n' + ' values.\n' '\n' 'p expression\n' '\n' @@ -5217,6 +5260,54 @@ 'current\n' ' frame.\n' '\n' + ' Note:\n' + '\n' + ' Display evaluates *expression* and compares to the result ' + 'of the\n' + ' previous evaluation of *expression*, so when the result is\n' + ' mutable, display may not be able to pick up the changes.\n' + '\n' + ' Example:\n' + '\n' + ' lst = []\n' + ' breakpoint()\n' + ' pass\n' + ' lst.append(1)\n' + ' print(lst)\n' + '\n' + ' Display won?t realize "lst" has been changed because the ' + 'result of\n' + ' evaluation is modified in place by "lst.append(1)" before ' + 'being\n' + ' compared:\n' + '\n' + ' > example.py(3)<module>()\n' + ' -> pass\n' + ' (Pdb) display lst\n' + ' display lst: []\n' + ' (Pdb) n\n' + ' > example.py(4)<module>()\n' + ' -> lst.append(1)\n' + ' (Pdb) n\n' + ' > example.py(5)<module>()\n' + ' -> print(lst)\n' + ' (Pdb)\n' + '\n' + ' You can do some tricks with copy mechanism to make it work:\n' + '\n' + ' > example.py(3)<module>()\n' + ' -> pass\n' + ' (Pdb) display lst[:]\n' + ' display lst[:]: []\n' + ' (Pdb) n\n' + ' > example.py(4)<module>()\n' + ' -> lst.append(1)\n' + ' (Pdb) n\n' + ' > example.py(5)<module>()\n' + ' -> print(lst)\n' + ' display lst[:]: [1] [old: []]\n' + ' (Pdb)\n' + '\n' ' New in version 3.2.\n' '\n' 'undisplay [expression]\n' @@ -5283,14 +5374,14 @@ 'current\n' ' stack frame. The exclamation point can be omitted unless the ' 'first\n' - ' word of the statement resembles a debugger command, e.g.:' + ' word of the statement resembles a debugger command, e.g.:\n' '\n' ' (Pdb) ! n=42\n' ' (Pdb)\n' '\n' - ' To set a global variable, you can prefix the assignment command ' - ' with \n' - ' a "global" statement on the same line, e.g.:\n' + ' To set a global variable, you can prefix the assignment ' + 'command\n' + ' with a "global" statement on the same line, e.g.:\n' '\n' " (Pdb) global list_options; list_options = ['-l']\n" ' (Pdb)\n' @@ -5321,7 +5412,8 @@ '\n' 'retval\n' '\n' - ' Print the return value for the last return of a function.\n' + ' Print the return value for the last return of the current ' + 'function.\n' '\n' '-[ Footnotes ]-\n' '\n' @@ -9509,8 +9601,7 @@ ' by carefully chosen inputs that exploit the worst case\n' ' performance of a dict insertion, O(n^2) complexity. ' 'See\n' - ' http://www.ocert.org/advisories/ocert-2011-003.html ' - 'for\n' + ' http://ocert.org/advisories/ocert-2011-003.html for\n' ' details.Changing hash values affects the iteration ' 'order of sets.\n' ' Python has never made guarantees about this ordering ' @@ -10164,20 +10255,37 @@ 'Resolving MRO entries\n' '---------------------\n' '\n' - 'If a base that appears in class definition is not an ' + 'object.__mro_entries__(self, bases)\n' + '\n' + ' If a base that appears in a class definition is not an ' 'instance of\n' - '"type", then an "__mro_entries__" method is searched on it. ' - 'If found,\n' - 'it is called with the original bases tuple. This method must ' - 'return a\n' - 'tuple of classes that will be used instead of this base. The ' - 'tuple may\n' - 'be empty, in such case the original base is ignored.\n' + ' "type", then an "__mro_entries__()" method is searched on ' + 'the base.\n' + ' If an "__mro_entries__()" method is found, the base is ' + 'substituted\n' + ' with the result of a call to "__mro_entries__()" when ' + 'creating the\n' + ' class. The method is called with the original bases tuple ' + 'passed to\n' + ' the *bases* parameter, and must return a tuple of classes ' + 'that will\n' + ' be used instead of the base. The returned tuple may be ' + 'empty: in\n' + ' these cases, the original base is ignored.\n' '\n' 'See also:\n' '\n' - ' **PEP 560** - Core support for typing module and generic ' - 'types\n' + ' "types.resolve_bases()"\n' + ' Dynamically resolve bases that are not instances of ' + '"type".\n' + '\n' + ' "types.get_original_bases()"\n' + ' Retrieve a class?s ?original bases? prior to ' + 'modifications by\n' + ' "__mro_entries__()".\n' + '\n' + ' **PEP 560**\n' + ' Core support for typing module and generic types.\n' '\n' '\n' 'Determining the appropriate metaclass\n' @@ -11153,6 +11261,61 @@ ' The specification for the Python "match" statement.\n' '\n' '\n' + 'Emulating buffer types\n' + '======================\n' + '\n' + 'The buffer protocol provides a way for Python objects to ' + 'expose\n' + 'efficient access to a low-level memory array. This protocol ' + 'is\n' + 'implemented by builtin types such as "bytes" and ' + '"memoryview", and\n' + 'third-party libraries may define additional buffer types.\n' + '\n' + 'While buffer types are usually implemented in C, it is also ' + 'possible\n' + 'to implement the protocol in Python.\n' + '\n' + 'object.__buffer__(self, flags)\n' + '\n' + ' Called when a buffer is requested from *self* (for ' + 'example, by the\n' + ' "memoryview" constructor). The *flags* argument is an ' + 'integer\n' + ' representing the kind of buffer requested, affecting for ' + 'example\n' + ' whether the returned buffer is read-only or writable.\n' + ' "inspect.BufferFlags" provides a convenient way to ' + 'interpret the\n' + ' flags. The method must return a "memoryview" object.\n' + '\n' + 'object.__release_buffer__(self, buffer)\n' + '\n' + ' Called when a buffer is no longer needed. The *buffer* ' + 'argument is\n' + ' a "memoryview" object that was previously returned by\n' + ' "__buffer__()". The method must release any resources ' + 'associated\n' + ' with the buffer. This method should return "None". Buffer ' + 'objects\n' + ' that do not need to perform any cleanup are not required ' + 'to\n' + ' implement this method.\n' + '\n' + 'New in version 3.12.\n' + '\n' + 'See also:\n' + '\n' + ' **PEP 688** - Making the buffer protocol accessible in ' + 'Python\n' + ' Introduces the Python "__buffer__" and ' + '"__release_buffer__"\n' + ' methods.\n' + '\n' + ' "collections.abc.Buffer"\n' + ' ABC for buffer types.\n' + '\n' + '\n' 'Special method lookup\n' '=====================\n' '\n' @@ -11300,8 +11463,8 @@ ' "casefold()" converts it to ""ss"".\n' '\n' ' The casefolding algorithm is described in section 3.13 ' - 'of the\n' - ' Unicode Standard.\n' + '?Default\n' + ' Case Folding? of the Unicode Standard.\n' '\n' ' New in version 3.3.\n' '\n' @@ -11519,8 +11682,9 @@ ' being one of ?Lm?, ?Lt?, ?Lu?, ?Ll?, or ?Lo?. Note ' 'that this is\n' ' different from the Alphabetic property defined in the ' - 'Unicode\n' - ' Standard.\n' + 'section 4.10\n' + ' ?Letters, Alphabetic, and Ideographic? of the Unicode ' + 'Standard.\n' '\n' 'str.isascii()\n' '\n' @@ -11692,8 +11856,8 @@ ' converted to lowercase.\n' '\n' ' The lowercasing algorithm used is described in section ' - '3.13 of the\n' - ' Unicode Standard.\n' + '3.13\n' + ' ?Default Case Folding? of the Unicode Standard.\n' '\n' 'str.lstrip([chars])\n' '\n' @@ -12159,8 +12323,8 @@ ' uppercase), but e.g. ?Lt? (Letter, titlecase).\n' '\n' ' The uppercasing algorithm used is described in section ' - '3.13 of the\n' - ' Unicode Standard.\n' + '3.13\n' + ' ?Default Case Folding? of the Unicode Standard.\n' '\n' 'str.zfill(width)\n' '\n' @@ -12704,9 +12868,10 @@ '\n' 'Any remaining exceptions that were not handled by any "except*" ' 'clause\n' - 'are re-raised at the end, combined into an exception group along ' - 'with\n' - 'all exceptions that were raised from within "except*" clauses.\n' + 'are re-raised at the end, along with all exceptions that were raised\n' + 'from within the "except*" clauses. If this list contains more than ' + 'one\n' + 'exception to reraise, they are combined into an exception group.\n' '\n' 'If the raised exception is not an exception group and its type ' 'matches\n' diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst new file mode 100644 index 000000000000..eb42b45726f5 --- /dev/null +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -0,0 +1,2412 @@ +.. date: 2023-05-02-17-56-32 +.. gh-issue: 99889 +.. nonce: l664SU +.. release date: 2023-05-22 +.. section: Security + +Fixed a security in flaw in :func:`uu.decode` that could allow for directory +traversal based on the input if no ``out_file`` was specified. + +.. + +.. date: 2023-05-01-15-03-25 +.. gh-issue: 104049 +.. nonce: b01Y3g +.. section: Security + +Do not expose the local on-disk location in directory indexes produced by +:class:`http.client.SimpleHTTPRequestHandler`. + +.. + +.. date: 2023-04-17-14-38-12 +.. gh-issue: 99108 +.. nonce: 720lG8 +.. section: Security + +Upgrade built-in :mod:`hashlib` SHA3 implementation to a verified +implementation from the ``HACL*`` project. Used when OpenSSL is not present +or lacks SHA3. + +.. + +.. date: 2023-03-07-20-59-17 +.. gh-issue: 102153 +.. nonce: 14CLSZ +.. section: Security + +:func:`urllib.parse.urlsplit` now strips leading C0 control and space +characters following the specification for URLs defined by WHATWG in +response to CVE-2023-24329. Patch by Illia Volochii. + +.. + +.. date: 2023-05-20-23-08-48 +.. gh-issue: 102856 +.. nonce: Knv9WT +.. section: Core and Builtins + +Implement PEP 701 changes in the :mod:`tokenize` module. Patch by Marta +G?mez Mac?as and Pablo Galindo Salgado + +.. + +.. date: 2023-05-18-13-00-21 +.. gh-issue: 104615 +.. nonce: h_rtw2 +.. section: Core and Builtins + +Fix wrong ordering of assignments in code like ``a, a = x, y``. Contributed +by Carl Meyer. + +.. + +.. date: 2023-05-16-19-17-48 +.. gh-issue: 104572 +.. nonce: eBZQYS +.. section: Core and Builtins + +Improve syntax error message for invalid constructs in :pep:`695` contexts +and in annotations when ``from __future__ import annotations`` is active. + +.. + +.. date: 2023-05-14-18-56-54 +.. gh-issue: 104482 +.. nonce: yaQsv8 +.. section: Core and Builtins + +Fix three error handling bugs in ast.c's validation of pattern matching +statements. + +.. + +.. date: 2023-05-12-13-30-04 +.. gh-issue: 102818 +.. nonce: rnv1mH +.. section: Core and Builtins + +Do not add a frame to the traceback in the ``sys.setprofile`` and +``sys.settrace`` trampoline functions. This ensures that frames are not +duplicated if an exception is raised in the callback function, and ensures +that frames are not omitted if a C callback is used and that does not add +the frame. + +.. + +.. date: 2023-05-11-15-56-07 +.. gh-issue: 104405 +.. nonce: tXV5fn +.. section: Core and Builtins + +Fix an issue where some :term:`bytecode` instructions could ignore +:pep:`523` when "inlining" calls. + +.. + +.. date: 2023-05-10-20-52-29 +.. gh-issue: 103082 +.. nonce: y3LG5Q +.. section: Core and Builtins + +Change behavior of ``sys.monitoring.events.LINE`` events in +``sys.monitoring``: Line events now occur when a new line is reached +dynamically, instead of using a static approximation, as before. This makes +the behavior very similar to that of "line" events in ``sys.settrace``. This +should ease porting of tools from 3.11 to 3.12. + +.. + +.. date: 2023-05-08-10-34-55 +.. gh-issue: 104263 +.. nonce: ctHWI8 +.. section: Core and Builtins + +Fix ``float("nan")`` to produce a quiet NaN on platforms (like MIPS) where +the meaning of the signalling / quiet bit is inverted from its usual +meaning. Also introduce a new macro ``Py_INFINITY`` matching C99's +``INFINITY``, and refactor internals to rely on C99's ``NAN`` and +``INFINITY`` macros instead of hard-coding bit patterns for infinities and +NaNs. Thanks Sebastian Berg. + +.. + +.. date: 2023-05-05-13-18-56 +.. gh-issue: 99113 +.. nonce: hT1ajK +.. section: Core and Builtins + +Multi-phase init extension modules may now indicate that they support +running in subinterpreters that have their own GIL. This is done by using +``Py_MOD_PER_INTERPRETER_GIL_SUPPORTED`` as the value for the +``Py_mod_multiple_interpreters`` module def slot. Otherwise the module, by +default, cannot be imported in such subinterpreters. (This does not affect +the main interpreter or subinterpreters that do not have their own GIL.) In +addition to the isolation that multi-phase init already normally requires, +support for per-interpreter GIL involves one additional constraint: +thread-safety. If the module has external (linked) dependencies and those +libraries have any state that isn't thread-safe then the module must do the +additional work to add thread-safety. This should be an uncommon case. + +.. + +.. date: 2023-05-05-12-14-47 +.. gh-issue: 99113 +.. nonce: -RAdnv +.. section: Core and Builtins + +The GIL is now (optionally) per-interpreter. This is the fundamental change +for PEP 684. This is all made possible by virtue of the isolated state of +each interpreter in the process. The behavior of the main interpreter +remains unchanged. Likewise, interpreters created using +``Py_NewInterpreter()`` are not affected. To get an interpreter with its +own GIL, call ``Py_NewInterpreterFromConfig()``. + +.. + +.. date: 2023-05-03-17-46-47 +.. gh-issue: 104108 +.. nonce: GOxAYt +.. section: Core and Builtins + +Multi-phase init extension modules may now indicate whether or not they +actually support multiple interpreters. By default such modules are +expected to support use in multiple interpreters. In the uncommon case that +one does not, it may use the new ``Py_mod_multiple_interpreters`` module def +slot. A value of ``0`` means the module does not support them. ``1`` means +it does. The default is ``1``. + +.. + +.. date: 2023-05-02-18-29-49 +.. gh-issue: 104142 +.. nonce: _5Et6I +.. section: Core and Builtins + +Fix an issue where :class:`list` or :class:`tuple` repetition could fail to +respect :pep:`683`. + +.. + +.. date: 2023-05-01-21-05-47 +.. gh-issue: 104078 +.. nonce: vRaBsU +.. section: Core and Builtins + +Improve the performance of :c:func:`PyObject_HasAttrString` + +.. + +.. date: 2023-05-01-14-48-29 +.. gh-issue: 104066 +.. nonce: pzoUZQ +.. section: Core and Builtins + +Improve the performance of :func:`hasattr` for module objects with a missing +attribute. + +.. + +.. date: 2023-05-01-14-10-38 +.. gh-issue: 104028 +.. nonce: dxfh13 +.. section: Core and Builtins + +Reduce object creation while calling callback function from gc. Patch by +Dong-hee Na. + +.. + +.. date: 2023-05-01-12-03-52 +.. gh-issue: 104018 +.. nonce: PFxGS4 +.. section: Core and Builtins + +Disallow the "z" format specifier in %-format of bytes objects. + +.. + +.. date: 2023-05-01-08-08-05 +.. gh-issue: 102213 +.. nonce: nfH-4C +.. section: Core and Builtins + +Fix performance loss when accessing an object's attributes with +``__getattr__`` defined. + +.. + +.. date: 2023-04-26-17-56-18 +.. gh-issue: 103895 +.. nonce: ESB6tn +.. section: Core and Builtins + +Improve handling of edge cases in showing ``Exception.__notes__``. Ensures +that the messages always end with a newline and that string/bytes are not +exploded over multiple lines. Patch by Carey Metcalfe. + +.. + +.. date: 2023-04-26-16-26-35 +.. gh-issue: 103907 +.. nonce: kiONZQ +.. section: Core and Builtins + +Don't modify the refcounts of known immortal objects (:const:`True`, +:const:`False`, and :const:`None`) in the main interpreter loop. + +.. + +.. date: 2023-04-26-15-14-23 +.. gh-issue: 103899 +.. nonce: 1pqKPF +.. section: Core and Builtins + +Provide a helpful hint in the :exc:`TypeError` message when accidentally +calling a :term:`module` object that has a callable attribute of the same +name (such as :func:`dis.dis` or :class:`datetime.datetime`). + +.. + +.. date: 2023-04-25-20-56-01 +.. gh-issue: 103845 +.. nonce: V7NYFn +.. section: Core and Builtins + +Remove both line and instruction instrumentation before adding new ones for +monitoring, to avoid newly added instrumentation being removed immediately. + +.. + +.. date: 2023-04-25-08-43-11 +.. gh-issue: 103763 +.. nonce: ZLBZk1 +.. section: Core and Builtins + +Implement :pep:`695`, adding syntactic support for generic classes, generic +functions, and type aliases. + +A new ``type X = ...`` syntax is added for type aliases, which resolves at +runtime to an instance of the new class ``typing.TypeAliasType``. The value +is lazily evaluated and is accessible through the ``.__value__`` attribute. +This is implemented as a new AST node ``ast.TypeAlias``. + +New syntax (``class X[T]: ...``, ``def func[T](): ...``) is added for +defining generic functions and classes. This is implemented as a new +``type_params`` attribute on the AST nodes for classes and functions. This +node holds instances of the new AST classes ``ast.TypeVar``, +``ast.ParamSpec``, and ``ast.TypeVarTuple``. + +``typing.TypeVar``, ``typing.ParamSpec``, ``typing.ParamSpecArgs``, +``typing.ParamSpecKwargs``, ``typing.TypeVarTuple``, and ``typing.Generic`` +are now implemented in C rather than Python. + +There are new bytecode instructions ``LOAD_LOCALS``, +``LOAD_CLASSDICT_OR_GLOBAL``, and ``LOAD_CLASSDICT_OR_DEREF`` to support +correct resolution of names in class namespaces. + +Patch by Eric Traut, Larry Hastings, and Jelle Zijlstra. + +.. + +.. date: 2023-04-24-21-47-38 +.. gh-issue: 103801 +.. nonce: WaBanq +.. section: Core and Builtins + +Adds three minor linting fixes to the wasm module caught that were caught by +ruff. + +.. + +.. date: 2023-04-24-14-38-16 +.. gh-issue: 103793 +.. nonce: kqoH6Q +.. section: Core and Builtins + +Optimized asyncio Task creation by deferring expensive string formatting +(task name generation) from Task creation to the first time ``get_name`` is +called. This makes asyncio benchmarks up to 5% faster. + +.. + +.. date: 2023-04-21-17-03-14 +.. gh-issue: 102310 +.. nonce: anLjDx +.. section: Core and Builtins + +Change the error range for invalid bytes literals. + +.. + +.. date: 2023-04-21-16-12-41 +.. gh-issue: 103590 +.. nonce: 7DHDOE +.. section: Core and Builtins + +Do not wrap a single exception raised from a ``try-except*`` construct in an +:exc:`ExceptionGroup`. + +.. + +.. date: 2023-04-20-16-17-51 +.. gh-issue: 103650 +.. nonce: K1MFXR +.. section: Core and Builtins + +Change the perf map format to remove the '0x' prefix from the addresses + +.. + +.. date: 2023-04-17-16-00-32 +.. gh-issue: 102856 +.. nonce: UunJ7y +.. section: Core and Builtins + +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. + +.. + +.. date: 2023-04-16-14-38-39 +.. gh-issue: 100530 +.. nonce: OR6-sn +.. section: Core and Builtins + +Clarify the error message raised when the called part of a class pattern +isn't actually a class. + +.. + +.. date: 2023-04-14-22-35-23 +.. gh-issue: 101517 +.. nonce: 5EqM-S +.. section: Core and Builtins + +Fix bug in line numbers of instructions emitted for :keyword:`except* +<except_star>`. + +.. + +.. date: 2023-04-13-00-58-55 +.. gh-issue: 103492 +.. nonce: P4k0Ay +.. section: Core and Builtins + +Clarify :exc:`SyntaxWarning` with literal ``is`` comparison by specifying +which literal is problematic, since comparisons using ``is`` with e.g. None +and bool literals are idiomatic. + +.. + +.. date: 2023-04-12-20-22-03 +.. gh-issue: 87729 +.. nonce: 99A7UO +.. section: Core and Builtins + +Add :opcode:`LOAD_SUPER_ATTR` (and a specialization for +``super().method()``) to speed up ``super().method()`` and ``super().attr``. +This makes ``super().method()`` roughly 2.3x faster and brings it within 20% +of the performance of a simple method call. Patch by Vladimir Matveev and +Carl Meyer. + +.. + +.. date: 2023-04-12-20-18-51 +.. gh-issue: 103488 +.. nonce: vYvlHD +.. section: Core and Builtins + +Change the internal offset distinguishing yield and return target addresses, +so that the instruction pointer is correct for exception handling and other +stack unwinding. + +.. + +.. date: 2023-04-12-19-55-24 +.. gh-issue: 82012 +.. nonce: FlcJAh +.. section: Core and Builtins + +The bitwise inversion operator (``~``) on bool is deprecated. It returns the +bitwise inversion of the underlying ``int`` representation such that +``bool(~True) == True``, which can be confusing. Use ``not`` for logical +negation of bools. In the rare case that you really need the bitwise +inversion of the underlying ``int``, convert to int explicitly ``~int(x)``. + +.. + +.. date: 2023-04-09-22-21-57 +.. gh-issue: 77757 +.. nonce: _Ow-u2 +.. section: Core and Builtins + +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. + +.. + +.. date: 2023-04-09-04-30-02 +.. gh-issue: 103333 +.. nonce: gKOetS +.. section: Core and Builtins + +:exc:`AttributeError` now retains the ``name`` attribute when pickled and +unpickled. + +.. + +.. date: 2023-04-08-17-13-07 +.. gh-issue: 103242 +.. nonce: ysI1b3 +.. section: Core and Builtins + +Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not to use deprecated +OpenSSL APIs. Patch by Dong-hee Na. + +.. + +.. date: 2023-04-07-12-18-41 +.. gh-issue: 103323 +.. nonce: 9802br +.. section: Core and Builtins + +We've replaced our use of ``_PyRuntime.tstate_current`` with a thread-local +variable. This is a fairly low-level implementation detail, and there +should be no change in behavior. + +.. + +.. date: 2023-04-02-22-14-57 +.. gh-issue: 84436 +.. nonce: hvMgwF +.. section: Core and Builtins + +The implementation of PEP-683 which adds Immortal Objects by using a fixed +reference count that skips reference counting to make objects truly +immutable. + +.. + +.. date: 2023-04-01-00-46-31 +.. gh-issue: 102700 +.. nonce: 493NB4 +.. section: Core and Builtins + +Allow built-in modules to be submodules. This allows submodules to be +statically linked into a CPython binary. + +.. + +.. date: 2023-03-31-17-24-03 +.. gh-issue: 103082 +.. nonce: isRUcV +.. section: Core and Builtins + +Implement :pep:`669` Low Impact Monitoring for CPython. + +.. + +.. date: 2023-03-25-23-24-38 +.. gh-issue: 88691 +.. nonce: 2SWBd1 +.. section: Core and Builtins + +Reduce the number of inline :opcode:`CACHE` entries for :opcode:`CALL`. + +.. + +.. date: 2023-03-07-17-37-00 +.. gh-issue: 102500 +.. nonce: RUSQhz +.. section: Core and Builtins + +Make the buffer protocol accessible in Python code using the new +``__buffer__`` and ``__release_buffer__`` magic methods. See :pep:`688` for +details. Patch by Jelle Zijlstra. + +.. + +.. date: 2023-01-30-15-40-29 +.. gh-issue: 97933 +.. nonce: nUlp3r +.. section: Core and Builtins + +:pep:`709`: inline list, dict and set comprehensions to improve performance +and reduce bytecode size. + +.. + +.. date: 2022-11-08-12-36-25 +.. gh-issue: 99184 +.. nonce: KIaqzz +.. section: Core and Builtins + +Bypass instance attribute access of ``__name__`` in ``repr`` of +:class:`weakref.ref`. + +.. + +.. date: 2022-10-06-23-32-11 +.. gh-issue: 98003 +.. nonce: xWE0Yu +.. section: Core and Builtins + +Complex function calls are now faster and consume no C stack space. + +.. + +.. bpo: 39610 +.. date: 2020-02-11-15-54-40 +.. nonce: fvgsCl +.. section: Core and Builtins + +``len()`` for 0-dimensional :class:`memoryview`` objects (such as +``memoryview(ctypes.c_uint8(42))``) now raises a :exc:`TypeError`. +Previously this returned ``1``, which was not consistent with ``mem_0d[0]`` +raising an :exc:`IndexError``. + +.. + +.. bpo: 31821 +.. date: 2019-12-01-12-58-31 +.. nonce: 1FNmwk +.. section: Core and Builtins + +Fix :func:`!pause_reading` to work when called from :func:`!connection_made` +in :mod:`asyncio`. + +.. + +.. date: 2023-05-17-21-01-48 +.. gh-issue: 104600 +.. nonce: E6CK35 +.. section: Library + +:func:`functools.update_wrapper` now sets the ``__type_params__`` attribute +(added by :pep:`695`). + +.. + +.. date: 2023-05-17-20-03-01 +.. gh-issue: 104340 +.. nonce: kp_XmX +.. section: Library + +When an ``asyncio`` pipe protocol loses its connection due to an error, and +the caller doesn't await ``wait_closed()`` on the corresponding +``StreamWriter``, don't log a warning about an exception that was never +retrieved. After all, according to the ``StreamWriter.close()`` docs, the +``wait_closed()`` call is optional ("not mandatory"). + +.. + +.. date: 2023-05-17-16-58-23 +.. gh-issue: 104555 +.. nonce: 5rb5oM +.. section: Library + +Fix issue where an :func:`issubclass` check comparing a class ``X`` against +a :func:`runtime-checkable protocol <typing.runtime_checkable>` ``Y`` with +non-callable members would not cause :exc:`TypeError` to be raised if an +:func:`isinstance` call had previously been made comparing an instance of +``X`` to ``Y``. This issue was present in edge cases on Python 3.11, but +became more prominent in 3.12 due to some unrelated changes that were made +to runtime-checkable protocols. Patch by Alex Waygood. + +.. + +.. date: 2023-05-17-08-01-36 +.. gh-issue: 104372 +.. nonce: jpoWs6 +.. section: Library + +Refactored the ``_posixsubprocess`` internals to avoid Python C API usage +between fork and exec when marking ``pass_fds=`` file descriptors +inheritable. + +.. + +.. date: 2023-05-17-03-14-07 +.. gh-issue: 104484 +.. nonce: y6KxL6 +.. section: Library + +Added *case_sensitive* argument to :meth:`pathlib.PurePath.match` + +.. + +.. date: 2023-05-16-11-02-44 +.. gh-issue: 75367 +.. nonce: qLWR35 +.. section: Library + +Fix data descriptor detection in :func:`inspect.getattr_static`. + +.. + +.. date: 2023-05-16-10-07-16 +.. gh-issue: 104536 +.. nonce: hFWD8f +.. section: Library + +Fix a race condition in the internal :mod:`multiprocessing.process` cleanup +logic that could manifest as an unintended ``AttributeError`` when calling +``process.close()``. + +.. + +.. date: 2023-05-12-19-29-28 +.. gh-issue: 103857 +.. nonce: 0IzSxr +.. section: Library + +Update datetime deprecations' stracktrace to point to the calling line + +.. + +.. date: 2023-05-11-21-32-18 +.. gh-issue: 101520 +.. nonce: l9MjRE +.. section: Library + +Move the core functionality of the ``tracemalloc`` module in the ``Python/`` +folder, leaving just the module wrapper in ``Modules/``. + +.. + +.. date: 2023-05-11-07-50-00 +.. gh-issue: 104392 +.. nonce: YSllzt +.. section: Library + +Remove undocumented and unused ``_paramspec_tvars`` attribute from some +classes in :mod:`typing`. + +.. + +.. date: 2023-05-11-01-07-42 +.. gh-issue: 102613 +.. nonce: uMsokt +.. section: Library + +Fix issue where :meth:`pathlib.Path.glob` raised :exc:`RecursionError` when +walking deep directory trees. + +.. + +.. date: 2023-05-10-19-33-36 +.. gh-issue: 103000 +.. nonce: j0KSfD +.. section: Library + +Improve performance of :func:`dataclasses.asdict` for the common case where +*dict_factory* is ``dict``. Patch by David C Ellis. + +.. + +.. date: 2023-05-09-18-46-24 +.. gh-issue: 104301 +.. nonce: gNnbId +.. section: Library + +Allow leading whitespace in disambiguated statements in :mod:`pdb`. + +.. + +.. date: 2023-05-08-23-01-59 +.. gh-issue: 104139 +.. nonce: 83Tnt- +.. section: Library + +Teach :func:`urllib.parse.unsplit` to retain the ``"//"`` when assembling +``itms-services://?action=generate-bugs`` style `Apple Platform Deployment +<https://support.apple.com/en-gb/guide/deployment/depce7cefc4d/web>`_ URLs. + +.. + +.. date: 2023-05-08-20-57-17 +.. gh-issue: 104307 +.. nonce: DSB93G +.. section: Library + +:func:`socket.getnameinfo` now releases the GIL while contacting the DNS +server + +.. + +.. date: 2023-05-08-15-50-59 +.. gh-issue: 104310 +.. nonce: fXVSPY +.. section: Library + +Users may now use ``importlib.util.allowing_all_extensions()`` (a context +manager) to temporarily disable the strict compatibility checks for +importing extension modules in subinterpreters. + +.. + +.. date: 2023-05-08-15-39-00 +.. gh-issue: 87695 +.. nonce: f6iO7v +.. section: Library + +Fix issue where :meth:`pathlib.Path.glob` raised :exc:`OSError` when it +encountered a symlink to an overly long path. + +.. + +.. date: 2023-05-07-19-56-45 +.. gh-issue: 104265 +.. nonce: fVblry +.. section: Library + +Prevent possible crash by disallowing instantiation of the +:class:`!_csv.Reader` and :class:`!_csv.Writer` types. The regression was +introduced in 3.10.0a4 with PR 23224 (:issue:`14935`). Patch by Radislav +Chugunov. + +.. + +.. date: 2023-05-06-20-37-46 +.. gh-issue: 102613 +.. nonce: QZG9iX +.. section: Library + +Improve performance of :meth:`pathlib.Path.glob` when expanding recursive +wildcards ("``**``") by merging adjacent wildcards and de-duplicating +results only when necessary. + +.. + +.. date: 2023-05-05-18-52-22 +.. gh-issue: 65772 +.. nonce: w5P5Wv +.. section: Library + +Remove unneeded comments and code in turtle.py. + +.. + +.. date: 2023-05-03-19-22-24 +.. gh-issue: 90208 +.. nonce: tI00da +.. section: Library + +Fixed issue where :meth:`pathlib.Path.glob` returned incomplete results when +it encountered a :exc:`PermissionError`. This method now suppresses all +:exc:`OSError` exceptions, except those raised from calling +:meth:`~pathlib.Path.is_dir` on the top-level path. + +.. + +.. date: 2023-05-03-16-51-53 +.. gh-issue: 104144 +.. nonce: 653Q0P +.. section: Library + +Optimize :class:`asyncio.TaskGroup` when using +:func:`asyncio.eager_task_factory`. Skip scheduling a done callback if a +TaskGroup task completes eagerly. + +.. + +.. date: 2023-05-03-16-50-24 +.. gh-issue: 104144 +.. nonce: yNkjL8 +.. section: Library + +Optimize :func:`asyncio.gather` when using +:func:`asyncio.eager_task_factory` to complete eagerly if all fututres +completed eagerly. Avoid scheduling done callbacks for futures that complete +eagerly. + +.. + +.. date: 2023-05-03-03-14-33 +.. gh-issue: 104114 +.. nonce: RG26RD +.. section: Library + +Fix issue where :meth:`pathlib.Path.glob` returns paths using the case of +non-wildcard segments for corresponding path segments, rather than the real +filesystem case. + +.. + +.. date: 2023-05-02-21-05-30 +.. gh-issue: 104104 +.. nonce: 9tjplT +.. section: Library + +Improve performance of :meth:`pathlib.Path.glob` by using +:data:`re.IGNORECASE` to implement case-insensitive matching. + +.. + +.. date: 2023-05-02-20-43-03 +.. gh-issue: 104102 +.. nonce: vgSdEJ +.. section: Library + +Improve performance of :meth:`pathlib.Path.glob` when evaluating patterns +that contain ``'../'`` segments. + +.. + +.. date: 2023-05-02-04-49-45 +.. gh-issue: 103822 +.. nonce: m0QdAO +.. section: Library + +Update the return type of ``weekday`` to the newly added Day attribute + +.. + +.. date: 2023-05-01-19-10-05 +.. gh-issue: 103629 +.. nonce: 81bpZz +.. section: Library + +Update the ``repr`` of :class:`typing.Unpack` according to :pep:`692`. + +.. + +.. date: 2023-05-01-17-58-28 +.. gh-issue: 103963 +.. nonce: XWlHx7 +.. section: Library + +Make :mod:`dis` display the names of the args for +:opcode:`CALL_INTRINSIC_*`. + +.. + +.. date: 2023-05-01-16-43-28 +.. gh-issue: 104035 +.. nonce: MrJBw8 +.. section: Library + +Do not ignore user-defined ``__getstate__`` and ``__setstate__`` methods for +slotted frozen dataclasses. + +.. + +.. date: 2023-04-29-18-23-16 +.. gh-issue: 103987 +.. nonce: sRgALL +.. section: Library + +In :mod:`mmap`, fix several bugs that could lead to access to memory-mapped +files after they have been invalidated. + +.. + +.. date: 2023-04-28-19-08-50 +.. gh-issue: 103977 +.. nonce: msF70A +.. section: Library + +Improve import time of :mod:`platform` module. + +.. + +.. date: 2023-04-28-18-04-23 +.. gh-issue: 88773 +.. nonce: xXCNJw +.. section: Library + +Added :func:`turtle.teleport` to the :mod:`turtle` module to move a turtle +to a new point without tracing a line, visible or invisible. Patch by Liam +Gersten. + +.. + +.. date: 2023-04-27-20-03-08 +.. gh-issue: 103935 +.. nonce: Uaf2M0 +.. section: Library + +Use :func:`io.open_code` for files to be executed instead of raw +:func:`open` + +.. + +.. date: 2023-04-27-18-46-31 +.. gh-issue: 68968 +.. nonce: E3tnhy +.. section: Library + +Fixed garbled output of :meth:`~unittest.TestCase.assertEqual` when an input +lacks final newline. + +.. + +.. date: 2023-04-27-00-45-41 +.. gh-issue: 100370 +.. nonce: MgZ3KY +.. section: Library + +Fix potential :exc:`OverflowError` in :meth:`sqlite3.Connection.blobopen` +for 32-bit builds. Patch by Erlend E. Aasland. + +.. + +.. date: 2023-04-27-00-05-32 +.. gh-issue: 102628 +.. nonce: X230E- +.. section: Library + +Substitute CTRL-D with CTRL-Z in :mod:`sqlite3` CLI banner when running on +Windows. + +.. + +.. date: 2023-04-26-18-12-13 +.. gh-issue: 103636 +.. nonce: -KvCgO +.. section: Library + +Module-level attributes ``January`` and ``February`` are deprecated from +:mod:`calendar`. + +.. + +.. date: 2023-04-26-15-14-36 +.. gh-issue: 103583 +.. nonce: iCMDFt +.. section: Library + +Isolate :mod:`!_multibytecodec` and codecs extension modules. Patches by +Erlend E. Aasland. + +.. + +.. date: 2023-04-26-09-54-25 +.. gh-issue: 103848 +.. nonce: aDSnpR +.. section: Library + +Add checks to ensure that ``[`` bracketed ``]`` hosts found by +:func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format. + +.. + +.. date: 2023-04-26-09-38-47 +.. gh-issue: 103872 +.. nonce: 8LBsDz +.. section: Library + +Update the bundled copy of pip to version 23.1.2. + +.. + +.. date: 2023-04-25-22-59-06 +.. gh-issue: 99944 +.. nonce: pst8iT +.. section: Library + +Make :mod:`dis` display the value of oparg of :opcode:`KW_NAMES`. + +.. + +.. date: 2023-04-25-22-06-00 +.. gh-issue: 74940 +.. nonce: TOacQ9 +.. section: Library + +The C.UTF-8 locale is no longer converted to en_US.UTF-8, enabling the use +of UTF-8 encoding on systems which have no locales installed. + +.. + +.. date: 2023-04-25-19-58-13 +.. gh-issue: 103861 +.. nonce: JeozgD +.. section: Library + +Fix ``zipfile.Zipfile`` creating invalid zip files when ``force_zip64`` was +used to add files to them. Patch by Carey Metcalfe. + +.. + +.. date: 2023-04-25-17-03-18 +.. gh-issue: 103857 +.. nonce: Mr2Cak +.. section: Library + +Deprecated :meth:`datetime.datetime.utcnow` and +:meth:`datetime.datetime.utcfromtimestamp`. (Patch by Paul Ganssle) + +.. + +.. date: 2023-04-25-16-31-00 +.. gh-issue: 103839 +.. nonce: tpyLhI +.. section: Library + +Avoid compilation error due to tommath.h not being found when building +Tkinter against Tcl 8.7 built with bundled libtommath. + +.. + +.. date: 2023-04-24-23-07-56 +.. gh-issue: 103791 +.. nonce: bBPWdS +.. section: Library + +:class:`contextlib.suppress` now supports suppressing exceptions raised as +part of an :exc:`ExceptionGroup`. If other exceptions exist on the group, +they are re-raised in a group that does not contain the suppressed +exceptions. + +.. + +.. date: 2023-04-24-16-00-28 +.. gh-issue: 90750 +.. nonce: da0Xi8 +.. section: Library + +Use :meth:`datetime.datetime.fromisocalendar` in the implementation of +:meth:`datetime.datetime.strptime`, which should now accept only valid ISO +dates. (Patch by Paul Ganssle) + +.. + +.. date: 2023-04-24-00-34-23 +.. gh-issue: 103685 +.. nonce: U14jBM +.. section: Library + +Prepare :meth:`tkinter.Menu.index` for Tk 8.7 so that it does not raise +``TclError: expected integer but got ""`` when it should return ``None``. + +.. + +.. date: 2023-04-23-15-39-17 +.. gh-issue: 81403 +.. nonce: zVz9Td +.. section: Library + +: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. + +.. + +.. date: 2023-04-22-22-37-39 +.. gh-issue: 103699 +.. nonce: NizCjc +.. section: Library + +Add ``__orig_bases__`` to non-generic TypedDicts, call-based TypedDicts, and +call-based NamedTuples. Other TypedDicts and NamedTuples already had the +attribute. + +.. + +.. date: 2023-04-22-21-34-13 +.. gh-issue: 103693 +.. nonce: SBtuLQ +.. section: Library + +Add convenience variable feature to :mod:`pdb` + +.. + +.. date: 2023-04-22-12-30-10 +.. gh-issue: 92248 +.. nonce: NcVTKR +.. section: Library + +Deprecate ``type``, ``choices``, and ``metavar`` parameters of +``argparse.BooleanOptionalAction``. + +.. + +.. date: 2023-04-22-11-20-27 +.. gh-issue: 89415 +.. nonce: YHk760 +.. section: Library + +Add :mod:`socket` constants for source-specific multicast. Patch by Reese +Hyde. + +.. + +.. date: 2023-04-22-02-41-06 +.. gh-issue: 103673 +.. nonce: oE7S_k +.. section: Library + +:mod:`socketserver` gains ``ForkingUnixStreamServer`` and +``ForkingUnixDatagramServer`` classes. Patch by Jay Berry. + +.. + +.. date: 2023-04-21-10-25-39 +.. gh-issue: 103636 +.. nonce: YK6NEa +.. section: Library + +Added Enum for months and days in the calendar module. + +.. + +.. date: 2023-04-19-16-08-53 +.. gh-issue: 84976 +.. nonce: HwbzlD +.. section: Library + +Create a new ``Lib/_pydatetime.py`` file that defines the Python version of +the ``datetime`` module, and make ``datetime`` import the contents of the +new library only if the C implementation is missing. Currently, the full +Python implementation is defined and then deleted if the C implementation is +not available, slowing down ``import datetime`` unnecessarily. + +.. + +.. date: 2023-04-17-14-47-28 +.. gh-issue: 103596 +.. nonce: ME1y3_ +.. section: Library + +Attributes/methods are no longer shadowed by same-named enum members, +although they may be shadowed by enum.property's. + +.. + +.. date: 2023-04-16-19-48-21 +.. gh-issue: 103584 +.. nonce: 3mBTuM +.. section: Library + +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``. + +.. + +.. date: 2023-04-16-18-29-04 +.. gh-issue: 103578 +.. nonce: fly1wc +.. section: Library + +Fixed a bug where :mod:`pdb` crashes when reading source file with different +encoding by replacing :func:`io.open` with :func:`io.open_code`. The new +method would also call into the hook set by :func:`PyFile_SetOpenCodeHook`. + +.. + +.. date: 2023-04-15-12-19-14 +.. gh-issue: 103556 +.. nonce: TEf-2m +.. section: Library + +Now creating :class:`inspect.Signature` objects with positional-only +parameter with a default followed by a positional-or-keyword parameter +without one is impossible. + +.. + +.. date: 2023-04-15-11-21-38 +.. gh-issue: 103559 +.. nonce: a9rYHG +.. section: Library + +Update the bundled copy of pip to version 23.1.1. + +.. + +.. date: 2023-04-14-21-16-05 +.. gh-issue: 103548 +.. nonce: lagdpp +.. section: Library + +Improve performance of :meth:`pathlib.Path.absolute` and +:meth:`~pathlib.Path.cwd` by joining paths only when necessary. Also improve +performance of :meth:`pathlib.PurePath.is_absolute` on Posix by skipping +path parsing and normalization. + +.. + +.. date: 2023-04-14-21-12-32 +.. gh-issue: 103538 +.. nonce: M4FK_v +.. section: Library + +Remove ``_tkinter`` module code guarded by definition of the ``TK_AQUA`` +macro which was only needed for Tk 8.4.7 or earlier and was never actually +defined by any build system or documented for manual use. + +.. + +.. date: 2023-04-14-06-32-54 +.. gh-issue: 103533 +.. nonce: n_AfcS +.. section: Library + +Update :mod:`cProfile` to use PEP 669 API + +.. + +.. date: 2023-04-13-19-43-15 +.. gh-issue: 103525 +.. nonce: uY4VYg +.. section: Library + +Fix misleading exception message when mixed ``str`` and ``bytes`` arguments +are supplied to :class:`pathlib.PurePath` and :class:`~pathlib.Path`. + +.. + +.. date: 2023-04-13-13-17-47 +.. gh-issue: 103489 +.. nonce: ZSZgmu +.. section: Library + +Add :meth:`~sqlite3.Connection.getconfig` and +:meth:`~sqlite3.Connection.setconfig` to :class:`~sqlite3.Connection` to +make configuration changes to a database connection. Patch by Erlend E. +Aasland. + +.. + +.. date: 2023-04-12-17-59-55 +.. gh-issue: 103365 +.. nonce: UBEE0U +.. section: Library + +Set default Flag boundary to ``STRICT`` and fix bitwise operations. + +.. + +.. date: 2023-04-12-13-04-16 +.. gh-issue: 103472 +.. nonce: C6bOHv +.. section: Library + +Avoid a potential :exc:`ResourceWarning` in +:class:`http.client.HTTPConnection` by closing the proxy / tunnel's CONNECT +response explicitly. + +.. + +.. date: 2023-04-12-06-00-02 +.. gh-issue: 103462 +.. nonce: w6yBlM +.. section: Library + +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. + +.. + +.. date: 2023-04-11-21-38-39 +.. gh-issue: 103449 +.. nonce: -nxmhb +.. section: Library + +Fix a bug in doc string generation in :func:`dataclasses.dataclass`. + +.. + +.. date: 2023-04-09-06-59-36 +.. gh-issue: 103092 +.. nonce: vskbro +.. section: Library + +Isolate :mod:`!_collections` (apply :pep:`687`). Patch by Erlend E. Aasland. + +.. + +.. date: 2023-04-08-01-33-12 +.. gh-issue: 103357 +.. nonce: vjin28 +.. section: Library + +Added support for :class:`logging.Formatter` ``defaults`` parameter to +:func:`logging.config.dictConfig` and :func:`logging.config.fileConfig`. +Patch by Bar Harel. + +.. + +.. date: 2023-04-08-00-48-40 +.. gh-issue: 103092 +.. nonce: 5EFts0 +.. section: Library + +Adapt the :mod:`winreg` extension module to :pep:`687`. + +.. + +.. date: 2023-04-07-15-15-40 +.. gh-issue: 74690 +.. nonce: un84hh +.. section: Library + +The performance of :func:`isinstance` checks against +:func:`runtime-checkable protocols <typing.runtime_checkable>` 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. + +.. + +.. date: 2023-04-07-15-09-26 +.. gh-issue: 74690 +.. nonce: 0f886b +.. section: Library + +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" <whatsnew-typing-py312>` for more details. + +.. + +.. date: 2023-04-06-17-28-36 +.. gh-issue: 103256 +.. nonce: 1syxfs +.. section: Library + +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')``. + +.. + +.. date: 2023-04-06-16-55-51 +.. gh-issue: 102778 +.. nonce: BWeAmE +.. section: Library + +Support ``sys.last_exc`` in :mod:`idlelib`. + +.. + +.. date: 2023-04-06-04-35-59 +.. gh-issue: 103285 +.. nonce: rCZ9-G +.. section: Library + +Improve performance of :func:`ast.get_source_segment`. + +.. + +.. date: 2023-04-05-01-28-53 +.. gh-issue: 103225 +.. nonce: QD3JVU +.. section: Library + +Fix a bug in :mod:`pdb` when displaying line numbers of module-level source +code. + +.. + +.. date: 2023-04-04-21-44-25 +.. gh-issue: 103092 +.. nonce: Dz0_Xn +.. section: Library + +Adapt the :mod:`msvcrt` extension module to :pep:`687`. + +.. + +.. date: 2023-04-04-21-27-51 +.. gh-issue: 103092 +.. nonce: 7s7Bzf +.. section: Library + +Adapt the :mod:`winsound` extension module to :pep:`687`. + +.. + +.. date: 2023-04-04-12-43-38 +.. gh-issue: 93910 +.. nonce: jurMzv +.. section: Library + +Remove deprecation of enum ``memmber.member`` access. + +.. + +.. date: 2023-04-03-23-44-34 +.. gh-issue: 102978 +.. nonce: gy9eVk +.. section: Library + +Fixes :func:`unittest.mock.patch` not enforcing function signatures for +methods decorated with ``@classmethod`` or ``@staticmethod`` when patch is +called with ``autospec=True``. + +.. + +.. date: 2023-04-03-23-43-12 +.. gh-issue: 103092 +.. nonce: 3xqk4y +.. section: Library + +Isolate :mod:`!_socket` (apply :pep:`687`). Patch by Erlend E. Aasland. + +.. + +.. date: 2023-04-03-22-02-35 +.. gh-issue: 100479 +.. nonce: kNBjQm +.. section: Library + +Add :meth:`pathlib.PurePath.with_segments`, which creates a path object from +arguments. This method is called whenever a derivative path is created, such +as from :attr:`pathlib.PurePath.parent`. Subclasses may override this method +to share information between path objects. + +.. + +.. date: 2023-04-03-21-08-53 +.. gh-issue: 103220 +.. nonce: OW_Bj5 +.. section: Library + +Fix issue where :func:`os.path.join` added a slash when joining onto an +incomplete UNC drive with a trailing slash on Windows. + +.. + +.. date: 2023-04-02-23-05-22 +.. gh-issue: 103204 +.. nonce: bbDmu0 +.. section: Library + +Fixes :mod:`http.server` accepting HTTP requests with HTTP version numbers +preceded by '+', or '-', or with digit-separating '_' characters. The +length of the version numbers is also constrained. + +.. + +.. date: 2023-04-02-22-04-26 +.. gh-issue: 75586 +.. nonce: 526iJm +.. section: Library + +Fix various Windows-specific issues with ``shutil.which``. + +.. + +.. date: 2023-04-02-17-51-08 +.. gh-issue: 103193 +.. nonce: xrZbM1 +.. section: Library + +Improve performance of :func:`inspect.getattr_static`. Patch by Alex +Waygood. + +.. + +.. date: 2023-04-01-23-01-31 +.. gh-issue: 103176 +.. nonce: FBsdxa +.. section: Library + +:func:`sys._current_exceptions` now returns a mapping from thread-id to an +exception instance, rather than to a ``(typ, exc, tb)`` tuple. + +.. + +.. date: 2023-03-31-01-13-00 +.. gh-issue: 103143 +.. nonce: 6eMluy +.. section: Library + +Polish the help messages and docstrings of :mod:`pdb`. + +.. + +.. date: 2023-03-28-09-13-31 +.. gh-issue: 103015 +.. nonce: ETTfNf +.. section: Library + +Add *entrypoint* keyword-only parameter to +:meth:`sqlite3.Connection.load_extension`, for overriding the SQLite +extension entry point. Patch by Erlend E. Aasland. + +.. + +.. date: 2023-03-24-20-49-48 +.. gh-issue: 103000 +.. nonce: 6eVNZI +.. section: Library + +Improve performance of :func:`dataclasses.astuple` and +:func:`dataclasses.asdict` in cases where the contents are common Python +types. + +.. + +.. date: 2023-03-23-15-24-38 +.. gh-issue: 102953 +.. nonce: YR4KaK +.. section: Library + +The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, +have a new a *filter* argument that allows limiting tar features than may be +surprising or dangerous, such as creating files outside the destination +directory. See :ref:`tarfile-extraction-filter` for details. + +.. + +.. date: 2023-03-15-12-18-07 +.. gh-issue: 97696 +.. nonce: DtnpIC +.. section: Library + +Implemented an eager task factory in asyncio. When used as a task factory on +an event loop, it performs eager execution of coroutines. Coroutines that +are able to complete synchronously (e.g. return or raise without blocking) +are returned immediately as a finished task, and the task is never scheduled +to the event loop. If the coroutine blocks, the (pending) task is scheduled +and returned. + +.. + +.. date: 2023-03-15-00-37-43 +.. gh-issue: 81079 +.. nonce: heTAod +.. section: Library + +Add *case_sensitive* keyword-only argument to :meth:`pathlib.Path.glob` and +:meth:`~pathlib.Path.rglob`. + +.. + +.. date: 2023-03-14-11-20-19 +.. gh-issue: 101819 +.. nonce: 0-h0it +.. section: Library + +Isolate the :mod:`io` extension module by applying :pep:`687`. Patch by +Kumar Aditya, Victor Stinner, and Erlend E. Aasland. + +.. + +.. date: 2023-03-08-02-45-46 +.. gh-issue: 91896 +.. nonce: kgON_a +.. section: Library + +Deprecate :class:`collections.abc.ByteString` + +.. + +.. date: 2023-03-06-18-49-57 +.. gh-issue: 101362 +.. nonce: eSSy6L +.. section: Library + +Speed up :class:`pathlib.Path` construction by omitting the path anchor from +the internal list of path parts. + +.. + +.. date: 2023-02-21-14-57-34 +.. gh-issue: 102114 +.. nonce: uUDQzb +.. section: Library + +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. + +.. + +.. date: 2023-02-19-12-37-08 +.. gh-issue: 62432 +.. nonce: GnBFIB +.. section: Library + +The :mod:`unittest` runner will now exit with status code 5 if no tests were +run. It is common for test runner misconfiguration to fail to find any +tests, this should be an error. + +.. + +.. date: 2023-02-17-21-14-40 +.. gh-issue: 78079 +.. nonce: z3Szr6 +.. section: Library + +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. + +.. + +.. date: 2023-02-11-21-18-10 +.. gh-issue: 85984 +.. nonce: nvzOD0 +.. section: Library + +Add :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` to :mod:`tty` and +modernize, the behavior of :func:`tty.setraw` and :func:`tty.setcbreak` to +use POSIX.1-2017 Chapter 11 "General Terminal Interface" flag masks by +default. + +.. + +.. date: 2023-02-11-15-01-32 +.. gh-issue: 101688 +.. nonce: kwXmfM +.. section: Library + +Implement :func:`types.get_original_bases` to provide further introspection +for types. + +.. + +.. date: 2023-02-09-22-24-34 +.. gh-issue: 101640 +.. nonce: oFuEpB +.. section: Library + +:class:`argparse.ArgumentParser` now catches errors when writing messages, +such as when :data:`sys.stderr` is ``None``. Patch by Oleg Iarygin. + +.. + +.. date: 2023-02-06-16-45-18 +.. gh-issue: 83861 +.. nonce: mMbIU3 +.. section: Library + +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. + +.. + +.. date: 2023-01-22-14-53-12 +.. gh-issue: 89550 +.. nonce: c1U23f +.. section: Library + +Decrease execution time of some :mod:`gzip` file writes by 15% by adding +more appropriate buffering. + +.. + +.. date: 2023-01-14-17-54-56 +.. gh-issue: 95299 +.. nonce: vUhpKz +.. section: Library + +Remove the bundled setuptools wheel from ``ensurepip``, and stop installing +setuptools in environments created by ``venv``. + +.. + +.. date: 2022-11-10-16-26-47 +.. gh-issue: 99353 +.. nonce: DQFjnt +.. section: Library + +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*``. + +.. + +.. date: 2022-10-21-17-20-57 +.. gh-issue: 98040 +.. nonce: 3btbmA +.. section: Library + +Remove the long-deprecated ``imp`` module. + +.. + +.. date: 2022-10-21-16-23-31 +.. gh-issue: 97850 +.. nonce: N46coo +.. section: Library + +Deprecate :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` in +favor of :func:`importlib.util.find_spec`. + +.. + +.. date: 2022-10-20-14-03-58 +.. gh-issue: 94473 +.. nonce: pzGX73 +.. section: Library + +Flatten arguments in :meth:`tkinter.Canvas.coords`. It now accepts not only +``x1, y1, x2, y2, ...`` and ``[x1, y1, x2, y2, ...]``, but also ``(x1, y1), +(x2, y2), ...`` and ``[(x1, y1), (x2, y2), ...]``. + +.. + +.. date: 2022-10-09-14-47-42 +.. gh-issue: 98040 +.. nonce: IN3qab +.. section: Library + +Remove more deprecated importlib APIs: ``find_loader()``, ``find_module()``, +``importlib.abc.Finder``, ``pkgutil.ImpImporter``, ``pkgutil.ImpLoader``. + +.. + +.. date: 2022-09-07-09-32-07 +.. gh-issue: 96522 +.. nonce: t73oqp +.. section: Library + +Fix potential deadlock in pty.spawn() + +.. + +.. date: 2022-09-03-09-24-02 +.. gh-issue: 96534 +.. nonce: EU4Oxv +.. section: Library + +Support divert(4) added in FreeBSD 14. + +.. + +.. date: 2022-08-27-21-41-41 +.. gh-issue: 87474 +.. nonce: 9X-kxt +.. section: Library + +Fix potential file descriptor leaks in :class:`subprocess.Popen`. + +.. + +.. date: 2022-07-16-17-15-29 +.. gh-issue: 94906 +.. nonce: C4G8DG +.. section: Library + +Support multiple steps in :func:`math.nextafter`. Patch by Shantanu Jain and +Matthias Gorgens. + +.. + +.. date: 2022-07-06-11-10-37 +.. gh-issue: 51574 +.. nonce: sveUeD +.. section: Library + +Make :func:`tempfile.mkdtemp` return absolute paths when its *dir* parameter +is relative. + +.. + +.. date: 2022-07-03-23-13-28 +.. gh-issue: 94518 +.. nonce: 511Tbh +.. section: Library + +Convert private :meth:`_posixsubprocess.fork_exec` to use Argument Clinic. + +.. + +.. date: 2022-05-02-16-21-05 +.. gh-issue: 92184 +.. nonce: hneGVW +.. section: Library + +When creating zip files using :mod:`zipfile`, ``os.altsep``, if not +``None``, will always be treated as a path separator even when it is not +``/``. Patch by Carey Metcalfe. + +.. + +.. bpo: 46797 +.. date: 2022-02-19-14-19-34 +.. nonce: 6BXZX4 +.. section: Library + +Deprecation warnings are now emitted for :class:`!ast.Num`, +:class:`!ast.Bytes`, :class:`!ast.Str`, :class:`!ast.NameConstant` and +:class:`!ast.Ellipsis`. These have been documented as deprecated since +Python 3.8, and will be removed in Python 3.14. + +.. + +.. bpo: 44844 +.. date: 2021-12-03-23-00-56 +.. nonce: tvg2VY +.. section: Library + +Enables :mod:`webbrowser` to detect and launch Microsoft Edge browser. + +.. + +.. bpo: 45606 +.. date: 2021-11-19-23-37-18 +.. nonce: UW5XE1 +.. section: Library + +Fixed the bug in :meth:`pathlib.Path.glob` -- previously a dangling symlink +would not be found by this method when the pattern is an exact match, but +would be found when the pattern contains a wildcard or the recursive +wildcard (``**``). With this change, a dangling symlink will be found in +both cases. + +.. + +.. bpo: 23041 +.. date: 2021-11-07-15-31-25 +.. nonce: 564i32 +.. section: Library + +Add :data:`~csv.QUOTE_STRINGS` and :data:`~csv.QUOTE_NOTNULL` to the suite +of :mod:`csv` module quoting styles. + +.. + +.. bpo: 24964 +.. date: 2021-05-16-14-28-30 +.. nonce: Oa5Ie_ +.. section: Library + +Added :meth:`http.client.HTTPConnection.get_proxy_response_headers` that +provides access to the HTTP headers on a proxy server response to the +``CONNECT`` request. + +.. + +.. bpo: 17258 +.. date: 2020-05-25-12-42-36 +.. nonce: lf2554 +.. section: Library + +:mod:`multiprocessing` now supports stronger HMAC algorithms for +inter-process connection authentication rather than only HMAC-MD5. + +.. + +.. bpo: 39744 +.. date: 2020-02-25-00-43-22 +.. nonce: hgK689 +.. section: Library + +Make :func:`asyncio.subprocess.Process.communicate` close the subprocess's +stdin even when called with ``input=None``. + +.. + +.. bpo: 22708 +.. date: 2018-07-16-14-10-29 +.. nonce: 592iRR +.. section: Library + +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. + +.. + +.. date: 2023-05-14-12-11-28 +.. gh-issue: 67056 +.. nonce: nVC2Rf +.. section: Documentation + +Document that the effect of registering or unregistering an :mod:`atexit` +cleanup function from within a registered cleanup function is undefined. + +.. + +.. date: 2023-04-26-23-55-31 +.. gh-issue: 103629 +.. nonce: -0reqn +.. section: Documentation + +Mention the new way of typing ``**kwargs`` with ``Unpack`` and ``TypedDict`` +introduced in :pep:`692`. + +.. + +.. date: 2023-04-25-22-58-08 +.. gh-issue: 48241 +.. nonce: l1Gxxh +.. section: Documentation + +Clarifying documentation about the url parameter to urllib.request.urlopen +and urllib.request.Requst needing to be encoded properly. + +.. + +.. date: 2023-03-10-04-59-35 +.. gh-issue: 86094 +.. nonce: zOYdy8 +.. section: Documentation + +Add support for Unicode Path Extra Field in ZipFile. Patch by Yeojin Kim and +Andrea Giudiceandrea + +.. + +.. date: 2023-03-07-23-30-29 +.. gh-issue: 99202 +.. nonce: hhiAJF +.. section: Documentation + +Fix extension type from documentation for compiling in C++20 mode + +.. + +.. date: 2023-05-15-02-22-44 +.. gh-issue: 104494 +.. nonce: Bkrbfn +.. section: Tests + +Update ``test_pack_configure_in`` and ``test_place_configure_in`` for +changes to error message formatting in Tk 8.7. + +.. + +.. date: 2023-05-14-03-00-00 +.. gh-issue: 104461 +.. nonce: Rmex11 +.. section: Tests + +Run test_configure_screen on X11 only, since the ``DISPLAY`` environment +variable and ``-screen`` option for toplevels are not useful on Tk for Win32 +or Aqua. + +.. + +.. date: 2023-04-25-12-19-37 +.. gh-issue: 86275 +.. nonce: -RoLIt +.. section: Tests + +Added property-based tests to the :mod:`zoneinfo` tests, along with stubs +for the ``hypothesis`` interface. (Patch by Paul Ganssle) + +.. + +.. date: 2023-04-08-00-50-23 +.. gh-issue: 103329 +.. nonce: M38tqF +.. section: Tests + +Regression tests for the behaviour of ``unittest.mock.PropertyMock`` were +added. + +.. + +.. date: 2023-03-17-22-00-47 +.. gh-issue: 102795 +.. nonce: z21EoC +.. section: Tests + +fix use of poll in test_epoll's test_control_and_wait + +.. + +.. date: 2022-11-06-18-42-38 +.. gh-issue: 75729 +.. nonce: uGYJrv +.. section: Tests + +Fix the :func:`os.spawn* <os.spawnl>` tests failing on Windows when the +working directory or interpreter path contains spaces. + +.. + +.. date: 2023-05-20-16-09-59 +.. gh-issue: 101282 +.. nonce: FvRARb +.. section: Build + +BOLT optimization is now applied to the libpython shared library if building +a shared library. BOLT instrumentation and application settings can now be +influenced via the ``BOLT_INSTRUMENT_FLAGS`` and ``BOLT_APPLY_FLAGS`` +configure variables. + +.. + +.. date: 2023-05-15-09-34-08 +.. gh-issue: 99017 +.. nonce: nToOQu +.. section: Build + +``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. + +.. + +.. date: 2023-05-14-19-00-19 +.. gh-issue: 104490 +.. nonce: 1tA4AF +.. section: Build + +Define ``.PHONY`` / virtual make targets consistently and properly. + +.. + +.. date: 2023-05-04-10-56-14 +.. gh-issue: 104106 +.. nonce: -W9BJS +.. section: Build + +Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Dong-hee Na. + +.. + +.. date: 2023-04-14-10-24-37 +.. gh-issue: 103532 +.. nonce: H1djkd +.. section: Build + +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. + +.. + +.. date: 2023-02-11-05-31-05 +.. gh-issue: 99069 +.. nonce: X4LDvY +.. section: Build + +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. + +.. + +.. date: 2022-12-18-07-24-44 +.. gh-issue: 100220 +.. nonce: BgSV7C +.. section: Build + +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. + +.. + +.. date: 2022-06-20-15-15-11 +.. gh-issue: 90656 +.. nonce: kFBbKe +.. section: Build + +Add platform triplets for 64-bit LoongArch: + +* loongarch64-linux-gnusf +* loongarch64-linux-gnuf32 +* loongarch64-linux-gnu + +Patch by Zhang Na. + +.. + +.. date: 2023-05-18-22-46-03 +.. gh-issue: 104623 +.. nonce: HJZhm1 +.. section: Windows + +Update Windows installer to use SQLite 3.42.0. + +.. + +.. date: 2023-04-24-15-51-11 +.. gh-issue: 82814 +.. nonce: GI3UkZ +.. section: Windows + +Fix a potential ``[Errno 13] Permission denied`` when using +:func:`shutil.copystat` within Windows Subsystem for Linux (WSL) on a +mounted filesystem by adding ``errno.EACCES`` to the list of ignored errors +within the internal implementation. + +.. + +.. date: 2023-04-12-10-49-21 +.. gh-issue: 103088 +.. nonce: Yjj-qJ +.. section: Windows + +Fix virtual environment :file:`activate` script having incorrect line +endings for Cygwin. + +.. + +.. date: 2023-04-11-09-22-22 +.. gh-issue: 103088 +.. nonce: 6AJEuR +.. section: Windows + +Fixes venvs not working in bash on Windows across different disks + +.. + +.. date: 2023-03-24-11-25-28 +.. gh-issue: 102997 +.. nonce: dredy2 +.. section: Windows + +Update Windows installer to use SQLite 3.41.2. + +.. + +.. date: 2023-03-18-21-38-00 +.. gh-issue: 88013 +.. nonce: Z3loxC +.. section: Windows + +Fixed a bug where :exc:`TypeError` was raised when calling +:func:`ntpath.realpath` with a bytes parameter in some cases. + +.. + +.. date: 2023-05-21-23-54-52 +.. gh-issue: 99834 +.. nonce: 6ANPts +.. section: macOS + +Update macOS installer to Tcl/Tk 8.6.13. + +.. + +.. date: 2023-05-18-22-31-49 +.. gh-issue: 104623 +.. nonce: 6h7Xfx +.. section: macOS + +Update macOS installer to SQLite 3.42.0. + +.. + +.. date: 2023-05-18-08-52-04 +.. gh-issue: 103545 +.. nonce: pi5k2N +.. section: macOS + +Add ``os.PRIO_DARWIN_THREAD``, ``os.PRIO_DARWIN_PROCESS``, +``os.PRIO_DARWIN_BG`` and ``os.PRIO_DARWIN_NONUI``. These can be used with +``os.setpriority`` to run the process at a lower priority and make use of +the efficiency cores on Apple Silicon systems. + +.. + +.. date: 2023-05-04-21-47-59 +.. gh-issue: 104180 +.. nonce: lEJCwd +.. section: macOS + +Support reading SOCKS proxy configuration from macOS System Configuration. +Patch by Sam Schott. + +.. + +.. date: 2023-04-24-18-37-48 +.. gh-issue: 60436 +.. nonce: in-IyF +.. section: macOS + +update curses textbox to additionally handle backspace using the +``curses.ascii.DEL`` key press. + +.. + +.. 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-03-24-11-20-47 +.. gh-issue: 102997 +.. nonce: ZgQkbq +.. section: macOS + +Update macOS installer to SQLite 3.41.2. + +.. + +.. date: 2023-05-17-17-32-21 +.. gh-issue: 104499 +.. nonce: hNeqV4 +.. section: IDLE + +Fix completions for Tk Aqua 8.7 (currently blank). + +.. + +.. date: 2023-05-17-15-11-11 +.. gh-issue: 104496 +.. nonce: wjav-y +.. section: IDLE + +About prints both tcl and tk versions if different (expected someday). + +.. + +.. date: 2023-04-30-20-01-18 +.. gh-issue: 88496 +.. nonce: y65vUb +.. section: IDLE + +Fix IDLE test hang on macOS. + +.. + +.. date: 2023-05-11-15-12-11 +.. gh-issue: 104389 +.. nonce: EiOhB3 +.. section: Tools/Demos + +Argument Clinic C converters now accept the ``unused`` keyword, for wrapping +a parameter with :c:macro:`Py_UNUSED`. Patch by Erlend E. Aasland. + +.. + +.. date: 2023-05-18-20-53-05 +.. gh-issue: 101291 +.. nonce: ZBh9aR +.. section: C API + +Added unstable C API for extracting the value of "compact" integers: +:c:func:`PyUnstable_Long_IsCompact` and +:c:func:`PyUnstable_Long_CompactValue`. + +.. + +.. date: 2023-05-02-21-05-54 +.. gh-issue: 104109 +.. nonce: 0tnDZV +.. section: C API + +We've added ``Py_NewInterpreterFromConfig()`` and ``PyInterpreterConfig`` to +the public C-API (but not the stable ABI; not yet at least). The new +function may be used to create a new interpreter with various features +configured. The function was added to support PEP 684 (per-interpreter +GIL). + +.. + +.. date: 2023-04-28-18-04-38 +.. gh-issue: 103968 +.. nonce: EnVvOx +.. section: C API + +:c:func:`PyType_FromSpec` and its variants now allow creating classes whose +metaclass overrides :c:member:`~PyTypeObject.tp_new`. The ``tp_new`` is +ignored. This behavior is deprecated and will be disallowed in 3.14+. The +new :c:func:`PyType_FromMetaclass` already disallows it. + +.. + +.. date: 2023-04-24-10-31-59 +.. gh-issue: 103743 +.. nonce: 2xYA1K +.. section: C API + +Add :c:func:`PyUnstable_Object_GC_NewWithExtraData` function that can be +used to allocate additional memory after an object for data not managed by +Python. + +.. + +.. date: 2023-04-14-23-05-52 +.. gh-issue: 103295 +.. nonce: GRHY1Z +.. section: C API + +Introduced :c:func:`PyUnstable_WritePerfMapEntry`, +:c:func:`PyUnstable_PerfMapState_Init` and +:c:func:`PyUnstable_PerfMapState_Fini`. These allow extension modules (JIT +compilers in particular) to write to perf-map files in a thread safe manner. +The :doc:`../howto/perf_profiling` also uses these APIs to write entries in +the perf-map file. + +.. + +.. date: 2023-04-13-16-54-00 +.. gh-issue: 103509 +.. nonce: A26Qu8 +.. section: C API + +Added C API for extending types whose instance memory layout is opaque: +:c:member:`PyType_Spec.basicsize` can now be zero or negative, +:c:func:`PyObject_GetTypeData` can be used to get subclass-specific data, +and :c:macro:`Py_TPFLAGS_ITEMS_AT_END` can be used to safely extend +variable-size objects. See :pep:`697` for details. + +.. + +.. date: 2023-03-28-12-31-51 +.. gh-issue: 103091 +.. nonce: CzZyaZ +.. section: C API + +Add a new C-API function to eagerly assign a version tag to a PyTypeObject: +``PyUnstable_Type_AssignVersionTag()``. + +.. + +.. date: 2023-02-09-23-09-29 +.. gh-issue: 101408 +.. nonce: _paFIF +.. section: C API + +:c:func:`PyObject_GC_Resize` should calculate preheader size if needed. +Patch by Dong-hee Na. + +.. + +.. date: 2022-10-29-10-13-20 +.. gh-issue: 98836 +.. nonce: Cy5h_z +.. section: C API + +Add support of more formatting options (left aligning, octals, uppercase +hexadecimals, :c:expr:`intmax_t`, :c:expr:`ptrdiff_t`, :c:expr:`wchar_t` C +strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and +:c:func:`PyUnicode_FromFormatV`. + +.. + +.. date: 2022-09-15-15-21-34 +.. gh-issue: 96803 +.. nonce: ynBKIS +.. section: C API + +Add unstable C-API functions to get the code object, lasti and line number +from the internal ``_PyInterpreterFrame`` in the limited API. The functions +are: + +* ``PyCodeObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` +* ``int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` +* ``int PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` diff --git a/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst b/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst deleted file mode 100644 index dfe71a555207..000000000000 --- a/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst +++ /dev/null @@ -1,7 +0,0 @@ -Add platform triplets for 64-bit LoongArch: - -* loongarch64-linux-gnusf -* loongarch64-linux-gnuf32 -* loongarch64-linux-gnu - -Patch by Zhang Na. 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 deleted file mode 100644 index 7135317cd06f..000000000000 --- a/Misc/NEWS.d/next/Build/2022-12-18-07-24-44.gh-issue-100220.BgSV7C.rst +++ /dev/null @@ -1,4 +0,0 @@ -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. 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 deleted file mode 100644 index ae9b4d59ca8c..000000000000 --- a/Misc/NEWS.d/next/Build/2023-02-11-05-31-05.gh-issue-99069.X4LDvY.rst +++ /dev/null @@ -1 +0,0 @@ -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. 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 deleted file mode 100644 index 255c9833282c..000000000000 --- a/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst +++ /dev/null @@ -1,4 +0,0 @@ -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. diff --git a/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst b/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst deleted file mode 100644 index 900e5bd61d60..000000000000 --- a/Misc/NEWS.d/next/Build/2023-05-04-10-56-14.gh-issue-104106.-W9BJS.rst +++ /dev/null @@ -1 +0,0 @@ -Add gcc fallback of mkfifoat/mknodat for macOS. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst b/Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst deleted file mode 100644 index 1315b5cb3c19..000000000000 --- a/Misc/NEWS.d/next/Build/2023-05-14-19-00-19.gh-issue-104490.1tA4AF.rst +++ /dev/null @@ -1 +0,0 @@ -Define ``.PHONY`` / virtual make targets consistently and properly. diff --git a/Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst b/Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst deleted file mode 100644 index a3517ac0204b..000000000000 --- a/Misc/NEWS.d/next/Build/2023-05-15-09-34-08.gh-issue-99017.nToOQu.rst +++ /dev/null @@ -1 +0,0 @@ -``PYTHON_FOR_REGEN`` now require Python 3.10 or newer. diff --git a/Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst b/Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst deleted file mode 100644 index cc70d47c6c16..000000000000 --- a/Misc/NEWS.d/next/Build/2023-05-20-16-09-59.gh-issue-101282.FvRARb.rst +++ /dev/null @@ -1,4 +0,0 @@ -BOLT optimization is now applied to the libpython shared library if building -a shared library. BOLT instrumentation and application settings can now be -influenced via the ``BOLT_INSTRUMENT_FLAGS`` and ``BOLT_APPLY_FLAGS`` -configure variables. diff --git a/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst b/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst deleted file mode 100644 index 6fc56d2249f5..000000000000 --- a/Misc/NEWS.d/next/C API/2022-09-15-15-21-34.gh-issue-96803.ynBKIS.rst +++ /dev/null @@ -1,6 +0,0 @@ -Add unstable C-API functions to get the code object, lasti and line number from -the internal ``_PyInterpreterFrame`` in the limited API. The functions are: - -* ``PyCodeObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame)`` -* ``int PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame)`` -* ``int PyUnstable_InterpreterFrame_GetLine(struct _PyInterpreterFrame *frame)`` diff --git a/Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst b/Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst deleted file mode 100644 index e3730eb3f89e..000000000000 --- a/Misc/NEWS.d/next/C API/2022-10-29-10-13-20.gh-issue-98836.Cy5h_z.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add support of more formatting options (left aligning, octals, uppercase -hexadecimals, :c:expr:`intmax_t`, :c:expr:`ptrdiff_t`, :c:expr:`wchar_t` C -strings, variable width and precision) in :c:func:`PyUnicode_FromFormat` and -:c:func:`PyUnicode_FromFormatV`. 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 deleted file mode 100644 index 172d66163d42..000000000000 --- a/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst +++ /dev/null @@ -1,2 +0,0 @@ -:c:func:`PyObject_GC_Resize` should calculate preheader size if needed. -Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst b/Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst deleted file mode 100644 index 28c77b6816af..000000000000 --- a/Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst +++ /dev/null @@ -1 +0,0 @@ -Add a new C-API function to eagerly assign a version tag to a PyTypeObject: ``PyUnstable_Type_AssignVersionTag()``. diff --git a/Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst b/Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst deleted file mode 100644 index af630c3aafa9..000000000000 --- a/Misc/NEWS.d/next/C API/2023-04-13-16-54-00.gh-issue-103509.A26Qu8.rst +++ /dev/null @@ -1,5 +0,0 @@ -Added C API for extending types whose instance memory layout is opaque: -:c:member:`PyType_Spec.basicsize` can now be zero or negative, -:c:func:`PyObject_GetTypeData` can be used to get subclass-specific data, -and :c:macro:`Py_TPFLAGS_ITEMS_AT_END` can be used to safely extend -variable-size objects. See :pep:`697` for details. diff --git a/Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst b/Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst deleted file mode 100644 index 88222239858b..000000000000 --- a/Misc/NEWS.d/next/C API/2023-04-14-23-05-52.gh-issue-103295.GRHY1Z.rst +++ /dev/null @@ -1,5 +0,0 @@ -Introduced :c:func:`PyUnstable_WritePerfMapEntry`, :c:func:`PyUnstable_PerfMapState_Init` and -:c:func:`PyUnstable_PerfMapState_Fini`. These allow extension modules (JIT compilers in -particular) to write to perf-map files in a thread safe manner. The -:doc:`../howto/perf_profiling` also uses these APIs to write -entries in the perf-map file. diff --git a/Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst b/Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst deleted file mode 100644 index d074350ed3eb..000000000000 --- a/Misc/NEWS.d/next/C API/2023-04-24-10-31-59.gh-issue-103743.2xYA1K.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :c:func:`PyUnstable_Object_GC_NewWithExtraData` function that can be used to -allocate additional memory after an object for data not managed by Python. diff --git a/Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst b/Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst deleted file mode 100644 index 5e4270f82afd..000000000000 --- a/Misc/NEWS.d/next/C API/2023-04-28-18-04-38.gh-issue-103968.EnVvOx.rst +++ /dev/null @@ -1,4 +0,0 @@ -:c:func:`PyType_FromSpec` and its variants now allow creating classes whose -metaclass overrides :c:member:`~PyTypeObject.tp_new`. The ``tp_new`` is -ignored. This behavior is deprecated and will be disallowed in 3.14+. The -new :c:func:`PyType_FromMetaclass` already disallows it. diff --git a/Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst b/Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst deleted file mode 100644 index 2ffc0fa81c01..000000000000 --- a/Misc/NEWS.d/next/C API/2023-05-02-21-05-54.gh-issue-104109.0tnDZV.rst +++ /dev/null @@ -1,5 +0,0 @@ -We've added ``Py_NewInterpreterFromConfig()`` and ``PyInterpreterConfig`` to -the public C-API (but not the stable ABI; not yet at least). The new -function may be used to create a new interpreter with various features -configured. The function was added to support PEP 684 (per-interpreter -GIL). diff --git a/Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst b/Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst deleted file mode 100644 index 465af3b209a0..000000000000 --- a/Misc/NEWS.d/next/C API/2023-05-18-20-53-05.gh-issue-101291.ZBh9aR.rst +++ /dev/null @@ -1,3 +0,0 @@ -Added unstable C API for extracting the value of "compact" integers: -:c:func:`PyUnstable_Long_IsCompact` and -:c:func:`PyUnstable_Long_CompactValue`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-12-01-12-58-31.bpo-31821.1FNmwk.rst b/Misc/NEWS.d/next/Core and Builtins/2019-12-01-12-58-31.bpo-31821.1FNmwk.rst deleted file mode 100644 index 13c054fdd682..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2019-12-01-12-58-31.bpo-31821.1FNmwk.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`!pause_reading` to work when called from :func:`!connection_made` in :mod:`asyncio`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst b/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst deleted file mode 100644 index d65e0f3db9d6..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst +++ /dev/null @@ -1,2 +0,0 @@ -``len()`` for 0-dimensional :class:`memoryview`` objects (such as ``memoryview(ctypes.c_uint8(42))``) now raises a :exc:`TypeError`. -Previously this returned ``1``, which was not consistent with ``mem_0d[0]`` raising an :exc:`IndexError``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-32-11.gh-issue-98003.xWE0Yu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-32-11.gh-issue-98003.xWE0Yu.rst deleted file mode 100644 index f9e71bc1344b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-10-06-23-32-11.gh-issue-98003.xWE0Yu.rst +++ /dev/null @@ -1,3 +0,0 @@ -Complex function calls are now faster and consume no C stack -space. - diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst deleted file mode 100644 index 80076831badf..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst +++ /dev/null @@ -1,2 +0,0 @@ -Bypass instance attribute access of ``__name__`` in ``repr`` of -:class:`weakref.ref`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst deleted file mode 100644 index 2eec05cb3ace..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst +++ /dev/null @@ -1,2 +0,0 @@ -:pep:`709`: inline list, dict and set comprehensions to improve performance -and reduce bytecode size. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst deleted file mode 100644 index e03113ba05cd..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-07-17-37-00.gh-issue-102500.RUSQhz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Make the buffer protocol accessible in Python code using the new -``__buffer__`` and ``__release_buffer__`` magic methods. See :pep:`688` for -details. Patch by Jelle Zijlstra. 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 deleted file mode 100644 index 761d45b0a3a8..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-25-23-24-38.gh-issue-88691.2SWBd1.rst +++ /dev/null @@ -1 +0,0 @@ -Reduce the number of inline :opcode:`CACHE` entries for :opcode:`CALL`. 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 deleted file mode 100644 index 631ef4c78904..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst +++ /dev/null @@ -1 +0,0 @@ -Implement :pep:`669` Low Impact Monitoring for CPython. 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 deleted file mode 100644 index 46951486e4f9..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-01-00-46-31.gh-issue-102700.493NB4.rst +++ /dev/null @@ -1 +0,0 @@ -Allow built-in modules to be submodules. This allows submodules to be statically linked into a CPython binary. 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 deleted file mode 100644 index c4d8ce75b35a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst +++ /dev/null @@ -1,3 +0,0 @@ -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/Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst deleted file mode 100644 index 347c91d973e5..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst +++ /dev/null @@ -1,3 +0,0 @@ -We've replaced our use of ``_PyRuntime.tstate_current`` with a thread-local -variable. This is a fairly low-level implementation detail, and there -should be no change in behavior. 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 deleted file mode 100644 index 38b107f3be17..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-08-17-13-07.gh-issue-103242.ysI1b3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Migrate :meth:`~ssl.SSLContext.set_ecdh_curve` method not to use deprecated -OpenSSL APIs. Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst deleted file mode 100644 index 793f02c2afdc..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-04-30-02.gh-issue-103333.gKOetS.rst +++ /dev/null @@ -1 +0,0 @@ -:exc:`AttributeError` now retains the ``name`` attribute when pickled and unpickled. 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 deleted file mode 100644 index 85c8ecf7de8d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst +++ /dev/null @@ -1,3 +0,0 @@ -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/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst deleted file mode 100644 index 819a2359bf6f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-19-55-24.gh-issue-82012.FlcJAh.rst +++ /dev/null @@ -1,5 +0,0 @@ -The bitwise inversion operator (``~``) on bool is deprecated. -It returns the bitwise inversion of the underlying ``int`` representation such that -``bool(~True) == True``, which can be confusing. Use ``not`` for logical negation -of bools. In the rare case that you really need the bitwise inversion of the underlying ``int``, -convert to int explicitly ``~int(x)``. 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 deleted file mode 100644 index e7daa104e571..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst +++ /dev/null @@ -1,3 +0,0 @@ -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/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst deleted file mode 100644 index 9d75de1565a1..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add :opcode:`LOAD_SUPER_ATTR` (and a specialization for ``super().method()``) to -speed up ``super().method()`` and ``super().attr``. This makes -``super().method()`` roughly 2.3x faster and brings it within 20% of the -performance of a simple method call. Patch by Vladimir Matveev and Carl Meyer. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst deleted file mode 100644 index 929650968173..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst +++ /dev/null @@ -1 +0,0 @@ -Clarify :exc:`SyntaxWarning` with literal ``is`` comparison by specifying which literal is problematic, since comparisons using ``is`` with e.g. None and bool literals are idiomatic. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst deleted file mode 100644 index 730c6cd40d72..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst +++ /dev/null @@ -1 +0,0 @@ -Fix bug in line numbers of instructions emitted for :keyword:`except* <except_star>`. 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 deleted file mode 100644 index 5b1bcc4a680f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst +++ /dev/null @@ -1 +0,0 @@ -Clarify the error message raised when the called part of a class pattern isn't actually a class. 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 deleted file mode 100644 index 35eceb83816b..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst +++ /dev/null @@ -1 +0,0 @@ -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/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst deleted file mode 100644 index 5434660e9d6f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst +++ /dev/null @@ -1 +0,0 @@ -Change the perf map format to remove the '0x' prefix from the addresses diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst deleted file mode 100644 index af733a8207a2..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst +++ /dev/null @@ -1 +0,0 @@ -Do not wrap a single exception raised from a ``try-except*`` construct in an :exc:`ExceptionGroup`. 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 deleted file mode 100644 index 15cb6c64adba..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst +++ /dev/null @@ -1 +0,0 @@ -Change the error range for invalid bytes literals. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-24-14-38-16.gh-issue-103793.kqoH6Q.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-24-14-38-16.gh-issue-103793.kqoH6Q.rst deleted file mode 100644 index c48348798e71..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-24-14-38-16.gh-issue-103793.kqoH6Q.rst +++ /dev/null @@ -1,3 +0,0 @@ -Optimized asyncio Task creation by deferring expensive string formatting -(task name generation) from Task creation to the first time ``get_name`` is -called. This makes asyncio benchmarks up to 5% faster. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst deleted file mode 100644 index 6f07d72fafdf..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst +++ /dev/null @@ -1 +0,0 @@ -Adds three minor linting fixes to the wasm module caught that were caught by ruff. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst deleted file mode 100644 index cb8d25650126..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-08-43-11.gh-issue-103763.ZLBZk1.rst +++ /dev/null @@ -1,23 +0,0 @@ -Implement :pep:`695`, adding syntactic support for generic classes, generic -functions, and type aliases. - -A new ``type X = ...`` syntax is added for type aliases, which resolves at -runtime to an instance of the new class ``typing.TypeAliasType``. -The value is lazily evaluated and is accessible through the ``.__value__`` -attribute. This is implemented as a new AST node ``ast.TypeAlias``. - -New syntax (``class X[T]: ...``, ``def func[T](): ...``) is added for defining -generic functions and classes. This is implemented as a new -``type_params`` attribute on the AST nodes for classes and functions. -This node holds instances of the new AST classes ``ast.TypeVar``, -``ast.ParamSpec``, and ``ast.TypeVarTuple``. - -``typing.TypeVar``, ``typing.ParamSpec``, ``typing.ParamSpecArgs``, -``typing.ParamSpecKwargs``, ``typing.TypeVarTuple``, and -``typing.Generic`` are now implemented in C rather than Python. - -There are new bytecode instructions ``LOAD_LOCALS``, -``LOAD_CLASSDICT_OR_GLOBAL``, and ``LOAD_CLASSDICT_OR_DEREF`` -to support correct resolution of names in class namespaces. - -Patch by Eric Traut, Larry Hastings, and Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst deleted file mode 100644 index e8434854cde6..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-25-20-56-01.gh-issue-103845.V7NYFn.rst +++ /dev/null @@ -1 +0,0 @@ -Remove both line and instruction instrumentation before adding new ones for monitoring, to avoid newly added instrumentation being removed immediately. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst deleted file mode 100644 index c12a6b9cb841..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-15-14-23.gh-issue-103899.1pqKPF.rst +++ /dev/null @@ -1,3 +0,0 @@ -Provide a helpful hint in the :exc:`TypeError` message when accidentally -calling a :term:`module` object that has a callable attribute of the same -name (such as :func:`dis.dis` or :class:`datetime.datetime`). diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst deleted file mode 100644 index cb2aaffed9ff..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-16-26-35.gh-issue-103907.kiONZQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Don't modify the refcounts of known immortal objects (:const:`True`, -:const:`False`, and :const:`None`) in the main interpreter loop. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst deleted file mode 100644 index 6fed304c9132..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-04-26-17-56-18.gh-issue-103895.ESB6tn.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve handling of edge cases in showing ``Exception.__notes__``. Ensures -that the messages always end with a newline and that string/bytes are not -exploded over multiple lines. Patch by Carey Metcalfe. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.rst deleted file mode 100644 index 997bef226e71..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-08-08-05.gh-issue-102213.nfH-4C.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-05-01-12-03-52.gh-issue-104018.PFxGS4.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst deleted file mode 100644 index f3cadaee0e32..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-12-03-52.gh-issue-104018.PFxGS4.rst +++ /dev/null @@ -1 +0,0 @@ -Disallow the "z" format specifier in %-format of bytes objects. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst deleted file mode 100644 index 9c35ea88499d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-10-38.gh-issue-104028.dxfh13.rst +++ /dev/null @@ -1,2 +0,0 @@ -Reduce object creation while calling callback function from gc. -Patch by Dong-hee Na. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst deleted file mode 100644 index 97e0c01689cb..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-14-48-29.gh-issue-104066.pzoUZQ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve the performance of :func:`hasattr` for module objects with a missing -attribute. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst deleted file mode 100644 index 6f24529bac3e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-01-21-05-47.gh-issue-104078.vRaBsU.rst +++ /dev/null @@ -1 +0,0 @@ -Improve the performance of :c:func:`PyObject_HasAttrString` diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst deleted file mode 100644 index 6a19ae84057f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-02-18-29-49.gh-issue-104142._5Et6I.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue where :class:`list` or :class:`tuple` repetition could fail to -respect :pep:`683`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst deleted file mode 100644 index dad843636493..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-03-17-46-47.gh-issue-104108.GOxAYt.rst +++ /dev/null @@ -1,6 +0,0 @@ -Multi-phase init extension modules may now indicate whether or not they -actually support multiple interpreters. By default such modules are -expected to support use in multiple interpreters. In the uncommon case that -one does not, it may use the new ``Py_mod_multiple_interpreters`` module def -slot. A value of ``0`` means the module does not support them. ``1`` means -it does. The default is ``1``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst deleted file mode 100644 index 42e26cb27b6e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst +++ /dev/null @@ -1,6 +0,0 @@ -The GIL is now (optionally) per-interpreter. This is the fundamental change -for PEP 684. This is all made possible by virtue of the isolated state of -each interpreter in the process. The behavior of the main interpreter -remains unchanged. Likewise, interpreters created using -``Py_NewInterpreter()`` are not affected. To get an interpreter with its -own GIL, call ``Py_NewInterpreterFromConfig()``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst deleted file mode 100644 index afd267508461..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-13-18-56.gh-issue-99113.hT1ajK.rst +++ /dev/null @@ -1,11 +0,0 @@ -Multi-phase init extension modules may now indicate that they support -running in subinterpreters that have their own GIL. This is done by using -``Py_MOD_PER_INTERPRETER_GIL_SUPPORTED`` as the value for the -``Py_mod_multiple_interpreters`` module def slot. Otherwise the module, by -default, cannot be imported in such subinterpreters. (This does not affect -the main interpreter or subinterpreters that do not have their own GIL.) In -addition to the isolation that multi-phase init already normally requires, -support for per-interpreter GIL involves one additional constraint: -thread-safety. If the module has external (linked) dependencies and those -libraries have any state that isn't thread-safe then the module must do the -additional work to add thread-safety. This should be an uncommon case. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst deleted file mode 100644 index 342467cfcd4e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-08-10-34-55.gh-issue-104263.ctHWI8.rst +++ /dev/null @@ -1,6 +0,0 @@ -Fix ``float("nan")`` to produce a quiet NaN on platforms (like MIPS) where -the meaning of the signalling / quiet bit is inverted from its usual -meaning. Also introduce a new macro ``Py_INFINITY`` matching C99's -``INFINITY``, and refactor internals to rely on C99's ``NAN`` and -``INFINITY`` macros instead of hard-coding bit patterns for infinities and -NaNs. Thanks Sebastian Berg. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst deleted file mode 100644 index 40eee64dfa71..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-10-20-52-29.gh-issue-103082.y3LG5Q.rst +++ /dev/null @@ -1,5 +0,0 @@ -Change behavior of ``sys.monitoring.events.LINE`` events in -``sys.monitoring``: Line events now occur when a new line is reached -dynamically, instead of using a static approximation, as before. This makes -the behavior very similar to that of "line" events in ``sys.settrace``. This -should ease porting of tools from 3.11 to 3.12. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst deleted file mode 100644 index 06ec5d7b0f0c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-11-15-56-07.gh-issue-104405.tXV5fn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix an issue where some :term:`bytecode` instructions could ignore -:pep:`523` when "inlining" calls. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst deleted file mode 100644 index 5cb77bff792c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-12-13-30-04.gh-issue-102818.rnv1mH.rst +++ /dev/null @@ -1,5 +0,0 @@ -Do not add a frame to the traceback in the ``sys.setprofile`` and -``sys.settrace`` trampoline functions. This ensures that frames are not -duplicated if an exception is raised in the callback function, and ensures -that frames are not omitted if a C callback is used and that does not add the -frame. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst deleted file mode 100644 index 07c09a3a84a6..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-14-18-56-54.gh-issue-104482.yaQsv8.rst +++ /dev/null @@ -1 +0,0 @@ -Fix three error handling bugs in ast.c's validation of pattern matching statements. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst deleted file mode 100644 index 25bad8aa6e3e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-16-19-17-48.gh-issue-104572.eBZQYS.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve syntax error message for invalid constructs in :pep:`695` contexts -and in annotations when ``from __future__ import annotations`` is active. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst deleted file mode 100644 index 447291a619dd..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-18-13-00-21.gh-issue-104615.h_rtw2.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix wrong ordering of assignments in code like ``a, a = x, y``. Contributed by -Carl Meyer. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst deleted file mode 100644 index ff831c9f935d..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-05-20-23-08-48.gh-issue-102856.Knv9WT.rst +++ /dev/null @@ -1 +0,0 @@ -Implement PEP 701 changes in the :mod:`tokenize` module. Patch by Marta G?mez Mac?as and Pablo Galindo Salgado 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 deleted file mode 100644 index 1569e815ee50..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-03-07-23-30-29.gh-issue-99202.hhiAJF.rst +++ /dev/null @@ -1 +0,0 @@ -Fix extension type from documentation for compiling in C++20 mode 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 deleted file mode 100644 index 39461f3f84c9..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-03-10-04-59-35.gh-issue-86094.zOYdy8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add support for Unicode Path Extra Field in ZipFile. Patch by Yeojin Kim -and Andrea Giudiceandrea diff --git a/Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst b/Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst deleted file mode 100644 index 619505cf6ee5..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-04-25-22-58-08.gh-issue-48241.l1Gxxh.rst +++ /dev/null @@ -1 +0,0 @@ -Clarifying documentation about the url parameter to urllib.request.urlopen and urllib.request.Requst needing to be encoded properly. diff --git a/Misc/NEWS.d/next/Documentation/2023-04-26-23-55-31.gh-issue-103629.-0reqn.rst b/Misc/NEWS.d/next/Documentation/2023-04-26-23-55-31.gh-issue-103629.-0reqn.rst deleted file mode 100644 index 6dc0a1cb5a3e..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-04-26-23-55-31.gh-issue-103629.-0reqn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Mention the new way of typing ``**kwargs`` with ``Unpack`` and ``TypedDict`` -introduced in :pep:`692`. diff --git a/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst b/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst deleted file mode 100644 index 2c6ef1781072..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-05-14-12-11-28.gh-issue-67056.nVC2Rf.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document that the effect of registering or unregistering an :mod:`atexit` -cleanup function from within a registered cleanup function is undefined. diff --git a/Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst b/Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst deleted file mode 100644 index 4f390d189d23..000000000000 --- a/Misc/NEWS.d/next/IDLE/2023-04-30-20-01-18.gh-issue-88496.y65vUb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix IDLE test hang on macOS. diff --git a/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst b/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst deleted file mode 100644 index 18d83150e94f..000000000000 --- a/Misc/NEWS.d/next/IDLE/2023-05-17-15-11-11.gh-issue-104496.wjav-y.rst +++ /dev/null @@ -1 +0,0 @@ -About prints both tcl and tk versions if different (expected someday). diff --git a/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst b/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst deleted file mode 100644 index 20cbd9ab9e57..000000000000 --- a/Misc/NEWS.d/next/IDLE/2023-05-17-17-32-21.gh-issue-104499.hNeqV4.rst +++ /dev/null @@ -1 +0,0 @@ -Fix completions for Tk Aqua 8.7 (currently blank). 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 deleted file mode 100644 index 00bcf38bbcdf..000000000000 --- a/Misc/NEWS.d/next/Library/2018-07-16-14-10-29.bpo-22708.592iRR.rst +++ /dev/null @@ -1,3 +0,0 @@ -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. diff --git a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst b/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst deleted file mode 100644 index 6e690f996569..000000000000 --- a/Misc/NEWS.d/next/Library/2020-02-25-00-43-22.bpo-39744.hgK689.rst +++ /dev/null @@ -1 +0,0 @@ -Make :func:`asyncio.subprocess.Process.communicate` close the subprocess's stdin even when called with ``input=None``. diff --git a/Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst b/Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst deleted file mode 100644 index 18ebd6e140cf..000000000000 --- a/Misc/NEWS.d/next/Library/2020-05-25-12-42-36.bpo-17258.lf2554.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`multiprocessing` now supports stronger HMAC algorithms for inter-process -connection authentication rather than only HMAC-MD5. diff --git a/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst b/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst deleted file mode 100644 index 0904b162e635..000000000000 --- a/Misc/NEWS.d/next/Library/2021-05-16-14-28-30.bpo-24964.Oa5Ie_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Added :meth:`http.client.HTTPConnection.get_proxy_response_headers` that -provides access to the HTTP headers on a proxy server response to the -``CONNECT`` request. 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 deleted file mode 100644 index 53c32d397b20..000000000000 --- a/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :data:`~csv.QUOTE_STRINGS` and :data:`~csv.QUOTE_NOTNULL` to the suite -of :mod:`csv` module quoting styles. diff --git a/Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst b/Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst deleted file mode 100644 index 531f47292200..000000000000 --- a/Misc/NEWS.d/next/Library/2021-11-19-23-37-18.bpo-45606.UW5XE1.rst +++ /dev/null @@ -1,5 +0,0 @@ -Fixed the bug in :meth:`pathlib.Path.glob` -- previously a dangling symlink -would not be found by this method when the pattern is an exact match, but -would be found when the pattern contains a wildcard or the recursive -wildcard (``**``). With this change, a dangling symlink will be found in -both cases. 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 deleted file mode 100644 index f0c91236dfdf..000000000000 --- a/Misc/NEWS.d/next/Library/2021-12-03-23-00-56.bpo-44844.tvg2VY.rst +++ /dev/null @@ -1 +0,0 @@ -Enables :mod:`webbrowser` to detect and launch Microsoft Edge browser. diff --git a/Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst b/Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst deleted file mode 100644 index 6539efbc9d0e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-02-19-14-19-34.bpo-46797.6BXZX4.rst +++ /dev/null @@ -1,4 +0,0 @@ -Deprecation warnings are now emitted for :class:`!ast.Num`, -:class:`!ast.Bytes`, :class:`!ast.Str`, :class:`!ast.NameConstant` and -:class:`!ast.Ellipsis`. These have been documented as deprecated since Python -3.8, and will be removed in Python 3.14. diff --git a/Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst b/Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst deleted file mode 100644 index 65dbdc9f6037..000000000000 --- a/Misc/NEWS.d/next/Library/2022-05-02-16-21-05.gh-issue-92184.hneGVW.rst +++ /dev/null @@ -1,3 +0,0 @@ -When creating zip files using :mod:`zipfile`, ``os.altsep``, if not ``None``, -will always be treated as a path separator even when it is not ``/``. -Patch by Carey Metcalfe. diff --git a/Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst b/Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst deleted file mode 100644 index 7719b74b8e5e..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst +++ /dev/null @@ -1 +0,0 @@ -Convert private :meth:`_posixsubprocess.fork_exec` to use Argument Clinic. diff --git a/Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst b/Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst deleted file mode 100644 index 50a3d6a46291..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst +++ /dev/null @@ -1,2 +0,0 @@ -Make :func:`tempfile.mkdtemp` return absolute paths when its *dir* -parameter is relative. diff --git a/Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst b/Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst deleted file mode 100644 index 663343371d1b..000000000000 --- a/Misc/NEWS.d/next/Library/2022-07-16-17-15-29.gh-issue-94906.C4G8DG.rst +++ /dev/null @@ -1 +0,0 @@ -Support multiple steps in :func:`math.nextafter`. Patch by Shantanu Jain and Matthias Gorgens. diff --git a/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst b/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst deleted file mode 100644 index eeb5308680e8..000000000000 --- a/Misc/NEWS.d/next/Library/2022-08-27-21-41-41.gh-issue-87474.9X-kxt.rst +++ /dev/null @@ -1 +0,0 @@ -Fix potential file descriptor leaks in :class:`subprocess.Popen`. diff --git a/Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst b/Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst deleted file mode 100644 index 0497d9eb6916..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-03-09-24-02.gh-issue-96534.EU4Oxv.rst +++ /dev/null @@ -1 +0,0 @@ -Support divert(4) added in FreeBSD 14. diff --git a/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst b/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst deleted file mode 100644 index 12ed52f97129..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-07-09-32-07.gh-issue-96522.t73oqp.rst +++ /dev/null @@ -1 +0,0 @@ -Fix potential deadlock in pty.spawn() diff --git a/Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst b/Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst deleted file mode 100644 index ac1854068441..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-09-14-47-42.gh-issue-98040.IN3qab.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove more deprecated importlib APIs: ``find_loader()``, ``find_module()``, -``importlib.abc.Finder``, ``pkgutil.ImpImporter``, ``pkgutil.ImpLoader``. diff --git a/Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst b/Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst deleted file mode 100644 index f70722a6f0f6..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-20-14-03-58.gh-issue-94473.pzGX73.rst +++ /dev/null @@ -1,3 +0,0 @@ -Flatten arguments in :meth:`tkinter.Canvas.coords`. It now accepts not only -``x1, y1, x2, y2, ...`` and ``[x1, y1, x2, y2, ...]``, but also ``(x1, y1), -(x2, y2), ...`` and ``[(x1, y1), (x2, y2), ...]``. diff --git a/Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst b/Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst deleted file mode 100644 index e3297d164fff..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-21-16-23-31.gh-issue-97850.N46coo.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecate :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` -in favor of :func:`importlib.util.find_spec`. diff --git a/Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst b/Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst deleted file mode 100644 index f67bffcb0ddc..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-21-17-20-57.gh-issue-98040.3btbmA.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the long-deprecated ``imp`` module. 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 deleted file mode 100644 index 1ad42d5c9aa5..000000000000 --- a/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst +++ /dev/null @@ -1,3 +0,0 @@ -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*``. 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 deleted file mode 100644 index 29c30848e09a..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst +++ /dev/null @@ -1 +0,0 @@ -Remove the bundled setuptools wheel from ``ensurepip``, and stop installing setuptools in environments created by ``venv``. diff --git a/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst b/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst deleted file mode 100644 index 556db0eae00c..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst +++ /dev/null @@ -1,2 +0,0 @@ -Decrease execution time of some :mod:`gzip` file writes by 15% by -adding more appropriate buffering. 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 deleted file mode 100644 index e85e7a4ff2e7..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst +++ /dev/null @@ -1,4 +0,0 @@ -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/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst b/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst deleted file mode 100644 index 917cf0f97b9e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-09-22-24-34.gh-issue-101640.oFuEpB.rst +++ /dev/null @@ -1 +0,0 @@ -:class:`argparse.ArgumentParser` now catches errors when writing messages, such as when :data:`sys.stderr` is ``None``. Patch by Oleg Iarygin. 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 deleted file mode 100644 index 6df694639314..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implement :func:`types.get_original_bases` to provide further introspection -for types. diff --git a/Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst b/Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst deleted file mode 100644 index 246530472165..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-11-21-18-10.gh-issue-85984.nvzOD0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add :func:`tty.cfmakeraw` and :func:`tty.cfmakecbreak` to :mod:`tty` and -modernize, the behavior of :func:`tty.setraw` and :func:`tty.setcbreak` to use -POSIX.1-2017 Chapter 11 "General Terminal Interface" flag masks by default. 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 deleted file mode 100644 index bbb9ac3e3f8f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst +++ /dev/null @@ -1,3 +0,0 @@ -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. diff --git a/Misc/NEWS.d/next/Library/2023-02-19-12-37-08.gh-issue-62432.GnBFIB.rst b/Misc/NEWS.d/next/Library/2023-02-19-12-37-08.gh-issue-62432.GnBFIB.rst deleted file mode 100644 index a8d66ea48c32..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-19-12-37-08.gh-issue-62432.GnBFIB.rst +++ /dev/null @@ -1,3 +0,0 @@ -The :mod:`unittest` runner will now exit with status code 5 if no tests -were run. It is common for test runner misconfiguration to fail to find -any tests, this should be an error. 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 deleted file mode 100644 index 4140c9a96cd2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst +++ /dev/null @@ -1 +0,0 @@ -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. 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 deleted file mode 100644 index 87617a503c0d..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst +++ /dev/null @@ -1,2 +0,0 @@ -Speed up :class:`pathlib.Path` construction by omitting the path anchor from -the internal list of path parts. diff --git a/Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst b/Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst deleted file mode 100644 index b5282d3d6129..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-08-02-45-46.gh-issue-91896.kgON_a.rst +++ /dev/null @@ -1 +0,0 @@ -Deprecate :class:`collections.abc.ByteString` diff --git a/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst b/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst deleted file mode 100644 index 4a73bbf32b37..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-14-11-20-19.gh-issue-101819.0-h0it.rst +++ /dev/null @@ -1,2 +0,0 @@ -Isolate the :mod:`io` extension module by applying :pep:`687`. Patch by -Kumar Aditya, Victor Stinner, and Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst b/Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst deleted file mode 100644 index ef5690533985..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-15-00-37-43.gh-issue-81079.heTAod.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add *case_sensitive* keyword-only argument to :meth:`pathlib.Path.glob` and -:meth:`~pathlib.Path.rglob`. diff --git a/Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst b/Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst deleted file mode 100644 index 0b3854d74eb9..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-15-12-18-07.gh-issue-97696.DtnpIC.rst +++ /dev/null @@ -1,6 +0,0 @@ -Implemented an eager task factory in asyncio. -When used as a task factory on an event loop, it performs eager execution of -coroutines. Coroutines that are able to complete synchronously (e.g. return or -raise without blocking) are returned immediately as a finished task, and the -task is never scheduled to the event loop. If the coroutine blocks, the -(pending) task is scheduled and returned. diff --git a/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst deleted file mode 100644 index 48a105a4a17b..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst +++ /dev/null @@ -1,4 +0,0 @@ -The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, -have a new a *filter* argument that allows limiting tar features than may be -surprising or dangerous, such as creating files outside the destination -directory. See :ref:`tarfile-extraction-filter` for details. 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 deleted file mode 100644 index 15f16d9eb4c1..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :func:`dataclasses.astuple` and -:func:`dataclasses.asdict` in cases where the contents are common Python types. diff --git a/Misc/NEWS.d/next/Library/2023-03-28-09-13-31.gh-issue-103015.ETTfNf.rst b/Misc/NEWS.d/next/Library/2023-03-28-09-13-31.gh-issue-103015.ETTfNf.rst deleted file mode 100644 index dcac1a28ca58..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-28-09-13-31.gh-issue-103015.ETTfNf.rst +++ /dev/null @@ -1,3 +0,0 @@ -Add *entrypoint* keyword-only parameter to -:meth:`sqlite3.Connection.load_extension`, for overriding the SQLite -extension entry point. Patch by Erlend E. Aasland. 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 deleted file mode 100644 index 32bd62d27c7c..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst +++ /dev/null @@ -1 +0,0 @@ -Polish the help messages and docstrings of :mod:`pdb`. 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 deleted file mode 100644 index b89f9bae5954..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst +++ /dev/null @@ -1,2 +0,0 @@ -: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/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 deleted file mode 100644 index f0b76a605a56..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-02-17-51-08.gh-issue-103193.xrZbM1.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :func:`inspect.getattr_static`. Patch by Alex -Waygood. 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 deleted file mode 100644 index 8ec568ec4e47..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-02-22-04-26.gh-issue-75586.526iJm.rst +++ /dev/null @@ -1 +0,0 @@ -Fix various Windows-specific issues with ``shutil.which``. diff --git a/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst b/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst deleted file mode 100644 index f8b3aa5151b6..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-02-23-05-22.gh-issue-103204.bbDmu0.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixes :mod:`http.server` accepting HTTP requests with HTTP version numbers -preceded by '+', or '-', or with digit-separating '_' characters. The length -of the version numbers is also constrained. 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 deleted file mode 100644 index 9cf26c26873b..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issue where :func:`os.path.join` added a slash when joining onto an -incomplete UNC drive with a trailing slash on Windows. diff --git a/Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst b/Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst deleted file mode 100644 index 58db90480d2f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-03-22-02-35.gh-issue-100479.kNBjQm.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add :meth:`pathlib.PurePath.with_segments`, which creates a path object from -arguments. This method is called whenever a derivative path is created, such -as from :attr:`pathlib.PurePath.parent`. Subclasses may override this method -to share information between path objects. 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 deleted file mode 100644 index e7586a223c14..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst +++ /dev/null @@ -1 +0,0 @@ -Isolate :mod:`!_socket` (apply :pep:`687`). Patch by Erlend E. Aasland. 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 deleted file mode 100644 index df63af10a385..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixes :func:`unittest.mock.patch` not enforcing function signatures for methods -decorated with ``@classmethod`` or ``@staticmethod`` when patch is called with -``autospec=True``. 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 deleted file mode 100644 index 783aefae0770..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-04-12-43-38.gh-issue-93910.jurMzv.rst +++ /dev/null @@ -1 +0,0 @@ -Remove deprecation of enum ``memmber.member`` access. 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 deleted file mode 100644 index 39c62ffbe8c6..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst +++ /dev/null @@ -1 +0,0 @@ -Adapt the :mod:`winsound` extension module to :pep:`687`. 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 deleted file mode 100644 index 7bd191e3c22b..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst +++ /dev/null @@ -1 +0,0 @@ -Adapt the :mod:`msvcrt` extension module to :pep:`687`. 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 deleted file mode 100644 index 5d1a063acdeb..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-05-01-28-53.gh-issue-103225.QD3JVU.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug in :mod:`pdb` when displaying line numbers of module-level source code. diff --git a/Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst b/Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst deleted file mode 100644 index 62b4364c2b16..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst +++ /dev/null @@ -1 +0,0 @@ -Improve performance of :func:`ast.get_source_segment`. 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 deleted file mode 100644 index 64ae5b5b6d56..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst +++ /dev/null @@ -1 +0,0 @@ -Support ``sys.last_exc`` in :mod:`idlelib`. 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 deleted file mode 100644 index 894c046dcdf0..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-06-17-28-36.gh-issue-103256.1syxfs.rst +++ /dev/null @@ -1,6 +0,0 @@ -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/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 deleted file mode 100644 index 0a103ae11970..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-07-15-09-26.gh-issue-74690.0f886b.rst +++ /dev/null @@ -1,3 +0,0 @@ -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" <whatsnew-typing-py312>` 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 deleted file mode 100644 index 48f11aac692d..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-07-15-15-40.gh-issue-74690.un84hh.rst +++ /dev/null @@ -1,8 +0,0 @@ -The performance of :func:`isinstance` checks against -:func:`runtime-checkable protocols <typing.runtime_checkable>` 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. 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 deleted file mode 100644 index 0f2108fee763..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst +++ /dev/null @@ -1 +0,0 @@ -Adapt the :mod:`winreg` extension module to :pep:`687`. 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 deleted file mode 100644 index 83dce56ed0b7..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst +++ /dev/null @@ -1,3 +0,0 @@ -Added support for :class:`logging.Formatter` ``defaults`` parameter to -:func:`logging.config.dictConfig` and :func:`logging.config.fileConfig`. -Patch by Bar Harel. 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 deleted file mode 100644 index 6977c1489a29..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst +++ /dev/null @@ -1 +0,0 @@ -Isolate :mod:`!_collections` (apply :pep:`687`). Patch by Erlend E. Aasland. 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 deleted file mode 100644 index 0b2b47af1cba..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst +++ /dev/null @@ -1 +0,0 @@ -Fix a bug in doc string generation in :func:`dataclasses.dataclass`. 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 deleted file mode 100644 index 50758c89cc28..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst +++ /dev/null @@ -1,4 +0,0 @@ -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. diff --git a/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst b/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst deleted file mode 100644 index 01d84f024bd4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-12-13-04-16.gh-issue-103472.C6bOHv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid a potential :exc:`ResourceWarning` in :class:`http.client.HTTPConnection` -by closing the proxy / tunnel's CONNECT response explicitly. 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 deleted file mode 100644 index 4d69f6f6fff7..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst +++ /dev/null @@ -1 +0,0 @@ -Set default Flag boundary to ``STRICT`` and fix bitwise operations. diff --git a/Misc/NEWS.d/next/Library/2023-04-13-13-17-47.gh-issue-103489.ZSZgmu.rst b/Misc/NEWS.d/next/Library/2023-04-13-13-17-47.gh-issue-103489.ZSZgmu.rst deleted file mode 100644 index 264564d018ce..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-13-13-17-47.gh-issue-103489.ZSZgmu.rst +++ /dev/null @@ -1,4 +0,0 @@ -Add :meth:`~sqlite3.Connection.getconfig` and -:meth:`~sqlite3.Connection.setconfig` to :class:`~sqlite3.Connection` to -make configuration changes to a database connection. Patch by Erlend E. -Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst b/Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst deleted file mode 100644 index 1414cb07dd91..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-13-19-43-15.gh-issue-103525.uY4VYg.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix misleading exception message when mixed ``str`` and ``bytes`` arguments -are supplied to :class:`pathlib.PurePath` and :class:`~pathlib.Path`. diff --git a/Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst b/Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst deleted file mode 100644 index 1008ea076c71..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-14-06-32-54.gh-issue-103533.n_AfcS.rst +++ /dev/null @@ -1 +0,0 @@ -Update :mod:`cProfile` to use PEP 669 API diff --git a/Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst b/Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst deleted file mode 100644 index 32788307d6f3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-14-21-12-32.gh-issue-103538.M4FK_v.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove ``_tkinter`` module code guarded by definition of the ``TK_AQUA`` macro -which was only needed for Tk 8.4.7 or earlier and was never actually defined by -any build system or documented for manual use. diff --git a/Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst b/Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst deleted file mode 100644 index 238f28688674..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-14-21-16-05.gh-issue-103548.lagdpp.rst +++ /dev/null @@ -1,4 +0,0 @@ -Improve performance of :meth:`pathlib.Path.absolute` and -:meth:`~pathlib.Path.cwd` by joining paths only when necessary. Also improve -performance of :meth:`pathlib.PurePath.is_absolute` on Posix by skipping path -parsing and normalization. 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 deleted file mode 100644 index 2c9d67e2c4bf..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst +++ /dev/null @@ -1 +0,0 @@ -Update the bundled copy of pip to version 23.1.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 deleted file mode 100644 index fe2267b7b790..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst +++ /dev/null @@ -1,3 +0,0 @@ -Now creating :class:`inspect.Signature` objects with positional-only -parameter with a default followed by a positional-or-keyword parameter -without one is impossible. diff --git a/Misc/NEWS.d/next/Library/2023-04-16-18-29-04.gh-issue-103578.fly1wc.rst b/Misc/NEWS.d/next/Library/2023-04-16-18-29-04.gh-issue-103578.fly1wc.rst deleted file mode 100644 index 69986c2a15b3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-16-18-29-04.gh-issue-103578.fly1wc.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a bug where :mod:`pdb` crashes when reading source file with different encoding by replacing :func:`io.open` with :func:`io.open_code`. The new method would also call into the hook set by :func:`PyFile_SetOpenCodeHook`. 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 deleted file mode 100644 index 6d7c93ade9cd..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst +++ /dev/null @@ -1,12 +0,0 @@ -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``. 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 deleted file mode 100644 index 2fa27e60b58e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst +++ /dev/null @@ -1,2 +0,0 @@ -Attributes/methods are no longer shadowed by same-named enum members, -although they may be shadowed by enum.property's. diff --git a/Misc/NEWS.d/next/Library/2023-04-19-16-08-53.gh-issue-84976.HwbzlD.rst b/Misc/NEWS.d/next/Library/2023-04-19-16-08-53.gh-issue-84976.HwbzlD.rst deleted file mode 100644 index 8658627aeba4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-19-16-08-53.gh-issue-84976.HwbzlD.rst +++ /dev/null @@ -1,5 +0,0 @@ -Create a new ``Lib/_pydatetime.py`` file that defines the Python version of -the ``datetime`` module, and make ``datetime`` import the contents of the -new library only if the C implementation is missing. Currently, the full -Python implementation is defined and then deleted if the C implementation is -not available, slowing down ``import datetime`` unnecessarily. diff --git a/Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst b/Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst deleted file mode 100644 index b3b5085250f0..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst +++ /dev/null @@ -1 +0,0 @@ -Added Enum for months and days in the calendar module. diff --git a/Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst b/Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst deleted file mode 100644 index bd5317744ff1..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst +++ /dev/null @@ -1,2 +0,0 @@ -:mod:`socketserver` gains ``ForkingUnixStreamServer`` and -``ForkingUnixDatagramServer`` classes. Patch by Jay Berry. diff --git a/Misc/NEWS.d/next/Library/2023-04-22-11-20-27.gh-issue-89415.YHk760.rst b/Misc/NEWS.d/next/Library/2023-04-22-11-20-27.gh-issue-89415.YHk760.rst deleted file mode 100644 index a5b99a2f1360..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-22-11-20-27.gh-issue-89415.YHk760.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :mod:`socket` constants for source-specific multicast. -Patch by Reese Hyde. diff --git a/Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst b/Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst deleted file mode 100644 index d4a02d829419..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-22-12-30-10.gh-issue-92248.NcVTKR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecate ``type``, ``choices``, and ``metavar`` parameters of -``argparse.BooleanOptionalAction``. diff --git a/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst b/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst deleted file mode 100644 index 52c68bfc9cee..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-22-21-34-13.gh-issue-103693.SBtuLQ.rst +++ /dev/null @@ -1 +0,0 @@ -Add convenience variable feature to :mod:`pdb` 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 deleted file mode 100644 index 60547a25a109..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add ``__orig_bases__`` to non-generic TypedDicts, call-based TypedDicts, and -call-based NamedTuples. Other TypedDicts and NamedTuples already had the attribute. 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 deleted file mode 100644 index 6adb71f76772..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst +++ /dev/null @@ -1,3 +0,0 @@ -: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. diff --git a/Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst b/Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst deleted file mode 100644 index 31df04790721..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst +++ /dev/null @@ -1 +0,0 @@ -Prepare :meth:`tkinter.Menu.index` for Tk 8.7 so that it does not raise ``TclError: expected integer but got ""`` when it should return ``None``. diff --git a/Misc/NEWS.d/next/Library/2023-04-24-16-00-28.gh-issue-90750.da0Xi8.rst b/Misc/NEWS.d/next/Library/2023-04-24-16-00-28.gh-issue-90750.da0Xi8.rst deleted file mode 100644 index 99e10f140f50..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-24-16-00-28.gh-issue-90750.da0Xi8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Use :meth:`datetime.datetime.fromisocalendar` in the implementation of -:meth:`datetime.datetime.strptime`, which should now accept only valid ISO -dates. (Patch by Paul Ganssle) diff --git a/Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst b/Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst deleted file mode 100644 index f00384cde970..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst +++ /dev/null @@ -1,3 +0,0 @@ -:class:`contextlib.suppress` now supports suppressing exceptions raised as -part of an :exc:`ExceptionGroup`. If other exceptions exist on the group, they -are re-raised in a group that does not contain the suppressed exceptions. diff --git a/Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst b/Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst deleted file mode 100644 index 1d40a8fbcd3f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-25-16-31-00.gh-issue-103839.tpyLhI.rst +++ /dev/null @@ -1,2 +0,0 @@ -Avoid compilation error due to tommath.h not being found when building -Tkinter against Tcl 8.7 built with bundled libtommath. diff --git a/Misc/NEWS.d/next/Library/2023-04-25-17-03-18.gh-issue-103857.Mr2Cak.rst b/Misc/NEWS.d/next/Library/2023-04-25-17-03-18.gh-issue-103857.Mr2Cak.rst deleted file mode 100644 index 3bd370dabf4e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-25-17-03-18.gh-issue-103857.Mr2Cak.rst +++ /dev/null @@ -1,2 +0,0 @@ -Deprecated :meth:`datetime.datetime.utcnow` and -:meth:`datetime.datetime.utcfromtimestamp`. (Patch by Paul Ganssle) diff --git a/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst b/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst deleted file mode 100644 index cc1c444449fe..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-25-19-58-13.gh-issue-103861.JeozgD.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix ``zipfile.Zipfile`` creating invalid zip files when ``force_zip64`` was -used to add files to them. Patch by Carey Metcalfe. diff --git a/Misc/NEWS.d/next/Library/2023-04-25-22-06-00.gh-issue-74940.TOacQ9.rst b/Misc/NEWS.d/next/Library/2023-04-25-22-06-00.gh-issue-74940.TOacQ9.rst deleted file mode 100644 index c37d795f3eb3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-25-22-06-00.gh-issue-74940.TOacQ9.rst +++ /dev/null @@ -1,2 +0,0 @@ -The C.UTF-8 locale is no longer converted to en_US.UTF-8, enabling the use -of UTF-8 encoding on systems which have no locales installed. diff --git a/Misc/NEWS.d/next/Library/2023-04-25-22-59-06.gh-issue-99944.pst8iT.rst b/Misc/NEWS.d/next/Library/2023-04-25-22-59-06.gh-issue-99944.pst8iT.rst deleted file mode 100644 index 80238a65e32a..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-25-22-59-06.gh-issue-99944.pst8iT.rst +++ /dev/null @@ -1 +0,0 @@ -Make :mod:`dis` display the value of oparg of :opcode:`KW_NAMES`. diff --git a/Misc/NEWS.d/next/Library/2023-04-26-09-38-47.gh-issue-103872.8LBsDz.rst b/Misc/NEWS.d/next/Library/2023-04-26-09-38-47.gh-issue-103872.8LBsDz.rst deleted file mode 100644 index b840f9f5769f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-26-09-38-47.gh-issue-103872.8LBsDz.rst +++ /dev/null @@ -1 +0,0 @@ -Update the bundled copy of pip to version 23.1.2. diff --git a/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst b/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst deleted file mode 100644 index 81e5904aa6cc..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add checks to ensure that ``[`` bracketed ``]`` hosts found by -:func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format. diff --git a/Misc/NEWS.d/next/Library/2023-04-26-15-14-36.gh-issue-103583.iCMDFt.rst b/Misc/NEWS.d/next/Library/2023-04-26-15-14-36.gh-issue-103583.iCMDFt.rst deleted file mode 100644 index 8c92ee408316..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-26-15-14-36.gh-issue-103583.iCMDFt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Isolate :mod:`!_multibytecodec` and codecs extension modules. Patches by -Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-04-26-18-12-13.gh-issue-103636.-KvCgO.rst b/Misc/NEWS.d/next/Library/2023-04-26-18-12-13.gh-issue-103636.-KvCgO.rst deleted file mode 100644 index a05a6f5cbcdb..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-26-18-12-13.gh-issue-103636.-KvCgO.rst +++ /dev/null @@ -1 +0,0 @@ -Module-level attributes ``January`` and ``February`` are deprecated from :mod:`calendar`. diff --git a/Misc/NEWS.d/next/Library/2023-04-27-00-05-32.gh-issue-102628.X230E-.rst b/Misc/NEWS.d/next/Library/2023-04-27-00-05-32.gh-issue-102628.X230E-.rst deleted file mode 100644 index eaaca5b41ba5..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-27-00-05-32.gh-issue-102628.X230E-.rst +++ /dev/null @@ -1,2 +0,0 @@ -Substitute CTRL-D with CTRL-Z in :mod:`sqlite3` CLI banner when running on -Windows. diff --git a/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst b/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst deleted file mode 100644 index 9022d55c48cb..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-27-00-45-41.gh-issue-100370.MgZ3KY.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix potential :exc:`OverflowError` in :meth:`sqlite3.Connection.blobopen` -for 32-bit builds. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst b/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst deleted file mode 100644 index bf29b64793b9..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed garbled output of :meth:`~unittest.TestCase.assertEqual` when an input lacks final newline. diff --git a/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst b/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst deleted file mode 100644 index 71b2d87249c4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-27-20-03-08.gh-issue-103935.Uaf2M0.rst +++ /dev/null @@ -1 +0,0 @@ -Use :func:`io.open_code` for files to be executed instead of raw :func:`open` diff --git a/Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst b/Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst deleted file mode 100644 index f14c9533f3af..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-28-18-04-23.gh-issue-88773.xXCNJw.rst +++ /dev/null @@ -1 +0,0 @@ -Added :func:`turtle.teleport` to the :mod:`turtle` module to move a turtle to a new point without tracing a line, visible or invisible. Patch by Liam Gersten. diff --git a/Misc/NEWS.d/next/Library/2023-04-28-19-08-50.gh-issue-103977.msF70A.rst b/Misc/NEWS.d/next/Library/2023-04-28-19-08-50.gh-issue-103977.msF70A.rst deleted file mode 100644 index ff4005774a95..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-28-19-08-50.gh-issue-103977.msF70A.rst +++ /dev/null @@ -1 +0,0 @@ -Improve import time of :mod:`platform` module. diff --git a/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst b/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst deleted file mode 100644 index 48c6d149a8ed..000000000000 --- a/Misc/NEWS.d/next/Library/2023-04-29-18-23-16.gh-issue-103987.sRgALL.rst +++ /dev/null @@ -1,2 +0,0 @@ -In :mod:`mmap`, fix several bugs that could lead to access to memory-mapped files after -they have been invalidated. diff --git a/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst b/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst deleted file mode 100644 index 8c8e3d6ba5fb..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-01-16-43-28.gh-issue-104035.MrJBw8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Do not ignore user-defined ``__getstate__`` and ``__setstate__`` methods for -slotted frozen dataclasses. diff --git a/Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst b/Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst deleted file mode 100644 index cb06ad5d22e8..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-01-17-58-28.gh-issue-103963.XWlHx7.rst +++ /dev/null @@ -1 +0,0 @@ -Make :mod:`dis` display the names of the args for :opcode:`CALL_INTRINSIC_*`. diff --git a/Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst b/Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst deleted file mode 100644 index 7971ab66359c..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-01-19-10-05.gh-issue-103629.81bpZz.rst +++ /dev/null @@ -1 +0,0 @@ -Update the ``repr`` of :class:`typing.Unpack` according to :pep:`692`. diff --git a/Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst b/Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst deleted file mode 100644 index 3daf9cc09380..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-02-04-49-45.gh-issue-103822.m0QdAO.rst +++ /dev/null @@ -1 +0,0 @@ -Update the return type of ``weekday`` to the newly added Day attribute diff --git a/Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst b/Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst deleted file mode 100644 index 7101de908a50..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-02-20-43-03.gh-issue-104102.vgSdEJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :meth:`pathlib.Path.glob` when evaluating patterns -that contain ``'../'`` segments. diff --git a/Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst b/Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst deleted file mode 100644 index 935a0e2a2bff..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-02-21-05-30.gh-issue-104104.9tjplT.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :meth:`pathlib.Path.glob` by using -:data:`re.IGNORECASE` to implement case-insensitive matching. diff --git a/Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst b/Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst deleted file mode 100644 index e705fea8326e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-03-03-14-33.gh-issue-104114.RG26RD.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix issue where :meth:`pathlib.Path.glob` returns paths using the case of -non-wildcard segments for corresponding path segments, rather than the real -filesystem case. diff --git a/Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst b/Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst deleted file mode 100644 index b975d48ed338..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-03-16-50-24.gh-issue-104144.yNkjL8.rst +++ /dev/null @@ -1,3 +0,0 @@ -Optimize :func:`asyncio.gather` when using :func:`asyncio.eager_task_factory` -to complete eagerly if all fututres completed eagerly. -Avoid scheduling done callbacks for futures that complete eagerly. diff --git a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst deleted file mode 100644 index ced3b7cea049..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`. -Skip scheduling a done callback if a TaskGroup task completes eagerly. diff --git a/Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst b/Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst deleted file mode 100644 index 1fd9588bebd5..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-03-19-22-24.gh-issue-90208.tI00da.rst +++ /dev/null @@ -1,4 +0,0 @@ -Fixed issue where :meth:`pathlib.Path.glob` returned incomplete results when -it encountered a :exc:`PermissionError`. This method now suppresses all -:exc:`OSError` exceptions, except those raised from calling -:meth:`~pathlib.Path.is_dir` on the top-level path. diff --git a/Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst b/Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst deleted file mode 100644 index 54b019019286..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-05-18-52-22.gh-issue-65772.w5P5Wv.rst +++ /dev/null @@ -1 +0,0 @@ -Remove unneeded comments and code in turtle.py. diff --git a/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst b/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst deleted file mode 100644 index 01f8b948d2cb..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst +++ /dev/null @@ -1,3 +0,0 @@ -Improve performance of :meth:`pathlib.Path.glob` when expanding recursive -wildcards ("``**``") by merging adjacent wildcards and de-duplicating -results only when necessary. diff --git a/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst deleted file mode 100644 index 9c582844bf90..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst +++ /dev/null @@ -1,4 +0,0 @@ -Prevent possible crash by disallowing instantiation of the -:class:`!_csv.Reader` and :class:`!_csv.Writer` types. -The regression was introduced in 3.10.0a4 with PR 23224 (:issue:`14935`). -Patch by Radislav Chugunov. diff --git a/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst b/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst deleted file mode 100644 index 7b677656bea3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-08-15-39-00.gh-issue-87695.f6iO7v.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issue where :meth:`pathlib.Path.glob` raised :exc:`OSError` when it -encountered a symlink to an overly long path. diff --git a/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst b/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst deleted file mode 100644 index 3743d569995f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst +++ /dev/null @@ -1,3 +0,0 @@ -Users may now use ``importlib.util.allowing_all_extensions()`` (a context -manager) to temporarily disable the strict compatibility checks for -importing extension modules in subinterpreters. diff --git a/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst deleted file mode 100644 index 03775845450c..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`socket.getnameinfo` now releases the GIL while contacting the DNS server diff --git a/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst b/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst deleted file mode 100644 index 145e75f6dea6..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst +++ /dev/null @@ -1,3 +0,0 @@ -Teach :func:`urllib.parse.unsplit` to retain the ``"//"`` when assembling -``itms-services://?action=generate-bugs`` style `Apple Platform Deployment -<https://support.apple.com/en-gb/guide/deployment/depce7cefc4d/web>`_ URLs. diff --git a/Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst b/Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst deleted file mode 100644 index a44ad765e624..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-09-18-46-24.gh-issue-104301.gNnbId.rst +++ /dev/null @@ -1 +0,0 @@ -Allow leading whitespace in disambiguated statements in :mod:`pdb`. diff --git a/Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst b/Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst deleted file mode 100644 index f84ec5c8b3ca..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-10-19-33-36.gh-issue-103000.j0KSfD.rst +++ /dev/null @@ -1,2 +0,0 @@ -Improve performance of :func:`dataclasses.asdict` for the common case where -*dict_factory* is ``dict``. Patch by David C Ellis. diff --git a/Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst b/Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst deleted file mode 100644 index 3b06964dc8d2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-11-01-07-42.gh-issue-102613.uMsokt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix issue where :meth:`pathlib.Path.glob` raised :exc:`RecursionError` when -walking deep directory trees. diff --git a/Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst b/Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst deleted file mode 100644 index b441b2acd19f..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-11-07-50-00.gh-issue-104392.YSllzt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove undocumented and unused ``_paramspec_tvars`` attribute from some -classes in :mod:`typing`. diff --git a/Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst b/Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst deleted file mode 100644 index 5e8bf967bfdc..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-11-21-32-18.gh-issue-101520.l9MjRE.rst +++ /dev/null @@ -1,2 +0,0 @@ -Move the core functionality of the ``tracemalloc`` module in the ``Python/`` -folder, leaving just the module wrapper in ``Modules/``. diff --git a/Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst b/Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst deleted file mode 100644 index 6e8162d9ecc2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-12-19-29-28.gh-issue-103857.0IzSxr.rst +++ /dev/null @@ -1 +0,0 @@ -Update datetime deprecations' stracktrace to point to the calling line diff --git a/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst b/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst deleted file mode 100644 index b0f5d78f7e61..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-16-10-07-16.gh-issue-104536.hFWD8f.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a race condition in the internal :mod:`multiprocessing.process` cleanup -logic that could manifest as an unintended ``AttributeError`` when calling -``process.close()``. diff --git a/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst b/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst deleted file mode 100644 index 554c425e6a78..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-16-11-02-44.gh-issue-75367.qLWR35.rst +++ /dev/null @@ -1 +0,0 @@ -Fix data descriptor detection in :func:`inspect.getattr_static`. diff --git a/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst b/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst deleted file mode 100644 index 6d42078c35dd..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-17-03-14-07.gh-issue-104484.y6KxL6.rst +++ /dev/null @@ -1 +0,0 @@ -Added *case_sensitive* argument to :meth:`pathlib.PurePath.match` diff --git a/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst b/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst deleted file mode 100644 index c228f503aab4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst +++ /dev/null @@ -1 +0,0 @@ -Refactored the ``_posixsubprocess`` internals to avoid Python C API usage between fork and exec when marking ``pass_fds=`` file descriptors inheritable. diff --git a/Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst b/Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst deleted file mode 100644 index 2992346484c5..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-17-16-58-23.gh-issue-104555.5rb5oM.rst +++ /dev/null @@ -1,7 +0,0 @@ -Fix issue where an :func:`issubclass` check comparing a class ``X`` against a -:func:`runtime-checkable protocol <typing.runtime_checkable>` ``Y`` with -non-callable members would not cause :exc:`TypeError` to be raised if an -:func:`isinstance` call had previously been made comparing an instance of ``X`` -to ``Y``. This issue was present in edge cases on Python 3.11, but became more -prominent in 3.12 due to some unrelated changes that were made to -runtime-checkable protocols. Patch by Alex Waygood. diff --git a/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst b/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst deleted file mode 100644 index 5b03622df6a2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-17-20-03-01.gh-issue-104340.kp_XmX.rst +++ /dev/null @@ -1 +0,0 @@ -When an ``asyncio`` pipe protocol loses its connection due to an error, and the caller doesn't await ``wait_closed()`` on the corresponding ``StreamWriter``, don't log a warning about an exception that was never retrieved. After all, according to the ``StreamWriter.close()`` docs, the ``wait_closed()`` call is optional ("not mandatory"). diff --git a/Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst b/Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst deleted file mode 100644 index 64f81e140d96..000000000000 --- a/Misc/NEWS.d/next/Library/2023-05-17-21-01-48.gh-issue-104600.E6CK35.rst +++ /dev/null @@ -1,2 +0,0 @@ -:func:`functools.update_wrapper` now sets the ``__type_params__`` attribute -(added by :pep:`695`). diff --git a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst b/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst deleted file mode 100644 index e57ac4ed3ac5..000000000000 --- a/Misc/NEWS.d/next/Security/2023-03-07-20-59-17.gh-issue-102153.14CLSZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -:func:`urllib.parse.urlsplit` now strips leading C0 control and space -characters following the specification for URLs defined by WHATWG in -response to CVE-2023-24329. Patch by Illia Volochii. diff --git a/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst b/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst deleted file mode 100644 index f259acf75383..000000000000 --- a/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst +++ /dev/null @@ -1,2 +0,0 @@ -Upgrade built-in :mod:`hashlib` SHA3 implementation to a verified implementation -from the ``HACL*`` project. Used when OpenSSL is not present or lacks SHA3. diff --git a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst b/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst deleted file mode 100644 index 969deb26bfeb..000000000000 --- a/Misc/NEWS.d/next/Security/2023-05-01-15-03-25.gh-issue-104049.b01Y3g.rst +++ /dev/null @@ -1,2 +0,0 @@ -Do not expose the local on-disk location in directory indexes -produced by :class:`http.client.SimpleHTTPRequestHandler`. diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst deleted file mode 100644 index b7002e81b6b6..000000000000 --- a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a security in flaw in :func:`uu.decode` that could allow for -directory traversal based on the input if no ``out_file`` was specified. 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 deleted file mode 100644 index 8baecdfc3188..000000000000 --- a/Misc/NEWS.d/next/Tests/2022-11-06-18-42-38.gh-issue-75729.uGYJrv.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix the :func:`os.spawn* <os.spawnl>` tests failing on Windows -when the working directory or interpreter path contains spaces. diff --git a/Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst b/Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst deleted file mode 100644 index fe2afff91ece..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-03-17-22-00-47.gh-issue-102795.z21EoC.rst +++ /dev/null @@ -1 +0,0 @@ -fix use of poll in test_epoll's test_control_and_wait 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 deleted file mode 100644 index 79448ed72804..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-04-08-00-50-23.gh-issue-103329.M38tqF.rst +++ /dev/null @@ -1 +0,0 @@ -Regression tests for the behaviour of ``unittest.mock.PropertyMock`` were added. diff --git a/Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst b/Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst deleted file mode 100644 index 37ab74ffc441..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-04-25-12-19-37.gh-issue-86275.-RoLIt.rst +++ /dev/null @@ -1,2 +0,0 @@ -Added property-based tests to the :mod:`zoneinfo` tests, along with stubs -for the ``hypothesis`` interface. (Patch by Paul Ganssle) diff --git a/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst b/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst deleted file mode 100644 index ae69f623e945..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-05-14-03-00-00.gh-issue-104461.Rmex11.rst +++ /dev/null @@ -1,3 +0,0 @@ -Run test_configure_screen on X11 only, since the ``DISPLAY`` -environment variable and ``-screen`` option for toplevels -are not useful on Tk for Win32 or Aqua. diff --git a/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst b/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst deleted file mode 100644 index a320c48428b5..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-05-15-02-22-44.gh-issue-104494.Bkrbfn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update ``test_pack_configure_in`` and ``test_place_configure_in`` -for changes to error message formatting in Tk 8.7. diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst b/Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst deleted file mode 100644 index 854e1cca967c..000000000000 --- a/Misc/NEWS.d/next/Tools-Demos/2023-05-11-15-12-11.gh-issue-104389.EiOhB3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Argument Clinic C converters now accept the ``unused`` keyword, for wrapping -a parameter with :c:macro:`Py_UNUSED`. Patch by Erlend E. Aasland. 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 deleted file mode 100644 index 4ca3185ea1f6..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-03-18-21-38-00.gh-issue-88013.Z3loxC.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed a bug where :exc:`TypeError` was raised when calling -:func:`ntpath.realpath` with a bytes parameter in some cases. diff --git a/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst b/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst deleted file mode 100644 index c8f7259aecba..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-03-24-11-25-28.gh-issue-102997.dredy2.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to use SQLite 3.41.2. 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 deleted file mode 100644 index f9f5343f4210..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes venvs not working in bash on Windows across different disks 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 deleted file mode 100644 index 1fee99da2403..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst +++ /dev/null @@ -1 +0,0 @@ -Fix virtual environment :file:`activate` script having incorrect line endings for Cygwin. diff --git a/Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst b/Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst deleted file mode 100644 index 5bd005ffacb8..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix a potential ``[Errno 13] Permission denied`` when using :func:`shutil.copystat` -within Windows Subsystem for Linux (WSL) on a mounted filesystem by adding -``errno.EACCES`` to the list of ignored errors within the internal implementation. diff --git a/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst b/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst deleted file mode 100644 index 3ffe8261e5a1..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-05-18-22-46-03.gh-issue-104623.HJZhm1.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to use SQLite 3.42.0. diff --git a/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst b/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst deleted file mode 100644 index d0b390a896b7..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-03-24-11-20-47.gh-issue-102997.ZgQkbq.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to SQLite 3.41.2. 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/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst b/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst deleted file mode 100644 index f274d3b898f1..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-04-24-18-37-48.gh-issue-60436.in-IyF.rst +++ /dev/null @@ -1 +0,0 @@ -update curses textbox to additionally handle backspace using the ``curses.ascii.DEL`` key press. diff --git a/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst b/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst deleted file mode 100644 index b6b18dcfd813..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Support reading SOCKS proxy configuration from macOS System Configuration. -Patch by Sam Schott. diff --git a/Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst b/Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst deleted file mode 100644 index c40f9460508d..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-05-18-08-52-04.gh-issue-103545.pi5k2N.rst +++ /dev/null @@ -1 +0,0 @@ -Add ``os.PRIO_DARWIN_THREAD``, ``os.PRIO_DARWIN_PROCESS``, ``os.PRIO_DARWIN_BG`` and ``os.PRIO_DARWIN_NONUI``. These can be used with ``os.setpriority`` to run the process at a lower priority and make use of the efficiency cores on Apple Silicon systems. diff --git a/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst b/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst deleted file mode 100644 index ffb124631c21..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-05-18-22-31-49.gh-issue-104623.6h7Xfx.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to SQLite 3.42.0. diff --git a/Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst b/Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst deleted file mode 100644 index aeb64d25b09a..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-05-21-23-54-52.gh-issue-99834.6ANPts.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to Tcl/Tk 8.6.13. diff --git a/README.rst b/README.rst index 06c4f0a1fa39..596a62108cf1 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 alpha 7 +This is Python version 3.12.0 beta 1 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From webhook-mailer at python.org Mon May 22 15:34:42 2023 From: webhook-mailer at python.org (brandtbucher) Date: Mon, 22 May 2023 19:34:42 -0000 Subject: [Python-checkins] GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104674) Message-ID: <mailman.540.1684784082.13550.python-checkins@python.org> https://github.com/python/cpython/commit/357bed0bcd3c5d7c4a8caad451754a9a172aca3e commit: 357bed0bcd3c5d7c4a8caad451754a9a172aca3e branch: main author: Brandt Bucher <brandtbucher at microsoft.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-22T19:34:34Z summary: GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104674) files: A Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst M Doc/c-api/veryhigh.rst M Doc/whatsnew/3.12.rst M Parser/myreadline.c diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 513856d8a48d..000a2d3d8790 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -167,6 +167,10 @@ the same library that the Python runtime is using. event loops, as done in the :file:`Modules/_tkinter.c` in the Python source code. + .. versionchanged:: 3.12 + This function is only called from the + :ref:`main interpreter <sub-interpreter-support>`. + .. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) @@ -187,6 +191,10 @@ the same library that the Python runtime is using. :c:func:`PyMem_RawRealloc`, instead of being allocated by :c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`. + .. versionchanged:: 3.12 + This function is only called from the + :ref:`main interpreter <sub-interpreter-support>`. + .. c:function:: PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) This is a simplified interface to :c:func:`PyRun_StringFlags` below, leaving diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index efbd2ca3de12..4ff90664bb79 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1476,6 +1476,15 @@ Porting to Python 3.12 Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12) already disallows creating classes whose metaclass overrides ``tp_new``. +* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no + longer called in :ref:`subinterpreters <sub-interpreter-support>`. This is + because clients generally rely on process-wide global state (since these + callbacks have no way of recovering extension module state). + + This also avoids situations where extensions may find themselves running in a + subinterpreter that they don't support (or haven't yet been loaded in). See + :gh:`104668` for more info. + Deprecated ---------- diff --git a/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst new file mode 100644 index 000000000000..7b882afd7f81 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst @@ -0,0 +1,5 @@ +Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer` +in subinterpreters, since it's generally difficult to avoid using global +state in their registered callbacks. This also avoids situations where +extensions may find themselves running in a subinterpreter they don't +support (or haven't yet been loaded in). diff --git a/Parser/myreadline.c b/Parser/myreadline.c index 3f0e29f051a4..7074aba74b72 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -45,7 +45,10 @@ my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp) #endif while (1) { - if (PyOS_InputHook != NULL) { + if (PyOS_InputHook != NULL && + // GH-104668: See PyOS_ReadlineFunctionPointer's comment below... + _Py_IsMainInterpreter(tstate->interp)) + { (void)(PyOS_InputHook)(); } @@ -131,7 +134,10 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn) wbuf = wbuf_local; wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1; while (1) { - if (PyOS_InputHook != NULL) { + if (PyOS_InputHook != NULL && + // GH-104668: See PyOS_ReadlineFunctionPointer's comment below... + _Py_IsMainInterpreter(tstate->interp)) + { (void)(PyOS_InputHook)(); } if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) { @@ -389,11 +395,23 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) * a tty. This can happen, for example if python is run like * this: python -i < test1.py */ - if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout))) - rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt); - else - rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, - prompt); + if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) || + // GH-104668: Don't call global callbacks like PyOS_InputHook or + // PyOS_ReadlineFunctionPointer from subinterpreters, since it seems + // like there's no good way for users (like readline and tkinter) to + // avoid using global state to manage them. Plus, we generally don't + // want to cause trouble for libraries that don't know/care about + // subinterpreter support. If libraries really need better APIs that + // work per-interpreter and have ways to access module state, we can + // certainly add them later (but for now we'll cross our fingers and + // hope that nobody actually cares): + !_Py_IsMainInterpreter(tstate->interp)) + { + rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt); + } + else { + rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt); + } Py_END_ALLOW_THREADS PyThread_release_lock(_PyOS_ReadlineLock); From webhook-mailer at python.org Mon May 22 16:05:34 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 22 May 2023 20:05:34 -0000 Subject: [Python-checkins] Fix whatsnew for 3.13. (GH-104756) Message-ID: <mailman.541.1684785935.13550.python-checkins@python.org> https://github.com/python/cpython/commit/42974c46bc9b1f282d35cf786b45f604b4df1bda commit: 42974c46bc9b1f282d35cf786b45f604b4df1bda branch: main author: Ned Deily <nad at python.org> committer: ned-deily <nad at python.org> date: 2023-05-22T16:05:27-04:00 summary: Fix whatsnew for 3.13. (GH-104756) files: A Doc/whatsnew/3.13.rst D Doc/whatsnew/3.13 M Doc/whatsnew/index.rst diff --git a/Doc/whatsnew/3.13 b/Doc/whatsnew/3.13.rst similarity index 100% rename from Doc/whatsnew/3.13 rename to Doc/whatsnew/3.13.rst diff --git a/Doc/whatsnew/index.rst b/Doc/whatsnew/index.rst index bfee225791ee..b9c196026532 100644 --- a/Doc/whatsnew/index.rst +++ b/Doc/whatsnew/index.rst @@ -11,6 +11,7 @@ anyone wishing to stay up-to-date after a new release. .. toctree:: :maxdepth: 2 + 3.13.rst 3.12.rst 3.11.rst 3.10.rst From webhook-mailer at python.org Mon May 22 17:50:33 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 21:50:33 -0000 Subject: [Python-checkins] Regenerate configure after the Python version bump (#104757) Message-ID: <mailman.0.1684792233.17421.python-checkins@python.org> https://github.com/python/cpython/commit/bc285c667c909b0690f659be3cbd96bb837d790a commit: bc285c667c909b0690f659be3cbd96bb837d790a branch: main author: T. Wouters <thomas at python.org> committer: Yhg1s <thomas at python.org> date: 2023-05-22T23:50:26+02:00 summary: Regenerate configure after the Python version bump (#104757) Regenerate configure after the Python version bump. files: M configure diff --git a/configure b/configure index 2b863be108be..bcf2a5c7c7f7 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for python 3.12. +# Generated by GNU Autoconf 2.69 for python 3.13. # # Report bugs to <https://github.com/python/cpython/issues/>. # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='python' PACKAGE_TARNAME='python' -PACKAGE_VERSION='3.12' -PACKAGE_STRING='python 3.12' +PACKAGE_VERSION='3.13' +PACKAGE_STRING='python 3.13' PACKAGE_BUGREPORT='https://github.com/python/cpython/issues/' PACKAGE_URL='' @@ -1690,7 +1690,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures python 3.12 to adapt to many kinds of systems. +\`configure' configures python 3.13 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1756,7 +1756,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of python 3.12:";; + short | recursive ) echo "Configuration of python 3.13:";; esac cat <<\_ACEOF @@ -1800,9 +1800,9 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-build-python=python3.12 + --with-build-python=python3.13 path to build python binary for cross compiling - (default: _bootstrap_python or python3.12) + (default: _bootstrap_python or python3.13) --with-pkg-config=[yes|no|check] use pkg-config to detect build options (default is check) @@ -2041,7 +2041,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -python configure 3.12 +python configure 3.13 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2750,7 +2750,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by python $as_me 3.12, which was +It was created by python $as_me 3.13, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3366,7 +3366,7 @@ fi -for ac_prog in python$PACKAGE_VERSION python3.12 python3.11 python3.10 python3 python +for ac_prog in python$PACKAGE_VERSION python3.13 python3.12 python3.11 python3.10 python3 python do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -3436,7 +3436,7 @@ rm confdefs.h mv confdefs.h.new confdefs.h -VERSION=3.12 +VERSION=3.13 # Version number of Python's own shared library file. @@ -28971,7 +28971,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by python $as_me 3.12, which was +This file was extended by python $as_me 3.13, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -29033,7 +29033,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -python config.status 3.12 +python config.status 3.13 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" From webhook-mailer at python.org Mon May 22 18:20:16 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 22:20:16 -0000 Subject: [Python-checkins] Update Windows library names for the Python version bump (#104755) Message-ID: <mailman.1.1684794017.17421.python-checkins@python.org> https://github.com/python/cpython/commit/4ded2c5e9c92cecb759c306470b4d18c99b391bf commit: 4ded2c5e9c92cecb759c306470b4d18c99b391bf branch: main author: Kirill Podoprigora <kirill.bast9 at mail.ru> committer: Yhg1s <thomas at python.org> date: 2023-05-23T00:20:06+02:00 summary: Update Windows library names for the Python version bump (#104755) files: M PC/pyconfig.h diff --git a/PC/pyconfig.h b/PC/pyconfig.h index 3415efe2dea1..f9250d6faccb 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -308,11 +308,11 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ file in their Makefile (other compilers are generally taken care of by distutils.) */ # if defined(_DEBUG) -# pragma comment(lib,"python312_d.lib") +# pragma comment(lib,"python313_d.lib") # elif defined(Py_LIMITED_API) # pragma comment(lib,"python3.lib") # else -# pragma comment(lib,"python312.lib") +# pragma comment(lib,"python313.lib") # endif /* _DEBUG */ # endif /* _MSC_VER */ # endif /* Py_BUILD_CORE */ From webhook-mailer at python.org Mon May 22 19:03:30 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 23:03:30 -0000 Subject: [Python-checkins] gh-102304: Temporarily Bump Py_LIMITED_API for 2 New Functions (#104766) Message-ID: <mailman.2.1684796611.17421.python-checkins@python.org> https://github.com/python/cpython/commit/421cbf39fba94c4031c87d3c3e9bb8a8a4ca54a8 commit: 421cbf39fba94c4031c87d3c3e9bb8a8a4ca54a8 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: Yhg1s <thomas at python.org> date: 2023-05-23T01:03:17+02:00 summary: gh-102304: Temporarily Bump Py_LIMITED_API for 2 New Functions (#104766) Quick and dirty. files: M Include/object.h diff --git a/Include/object.h b/Include/object.h index 81aeb2d8bd5a..c4fe2f83ef62 100644 --- a/Include/object.h +++ b/Include/object.h @@ -590,7 +590,7 @@ you can count such references to the type object.) extern Py_ssize_t _Py_RefTotal; # define _Py_INC_REFTOTAL() _Py_RefTotal++ # define _Py_DEC_REFTOTAL() _Py_RefTotal-- -# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000 +# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030D0000 PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); # define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() From webhook-mailer at python.org Mon May 22 19:16:35 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 23:16:35 -0000 Subject: [Python-checkins] Add the 3.12 branch to the github workflows. (#104768) Message-ID: <mailman.3.1684797396.17421.python-checkins@python.org> https://github.com/python/cpython/commit/4194d8f2c40f478eb0fc9b6fa9b913baaff229da commit: 4194d8f2c40f478eb0fc9b6fa9b913baaff229da branch: main author: T. Wouters <thomas at python.org> committer: Yhg1s <thomas at python.org> date: 2023-05-23T01:16:28+02:00 summary: Add the 3.12 branch to the github workflows. (#104768) files: M .github/workflows/build.yml M .github/workflows/doc.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41abddffa5d6..b9797192dba0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: push: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' @@ -16,6 +17,7 @@ on: pull_request: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 3f7550cc7294..ec900ce68a1d 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -5,6 +5,7 @@ on: #push: # branches: # - 'main' + # - '3.12' # - '3.11' # - '3.10' # - '3.9' @@ -15,6 +16,7 @@ on: pull_request: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' From webhook-mailer at python.org Mon May 22 19:17:13 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 23:17:13 -0000 Subject: [Python-checkins] gh-104764: Skip failing tests in test_enum that started failing. (#104765) Message-ID: <mailman.4.1684797434.17421.python-checkins@python.org> https://github.com/python/cpython/commit/586aca3fc647c626c39e995d07d8bd7dd13e2d52 commit: 586aca3fc647c626c39e995d07d8bd7dd13e2d52 branch: main author: T. Wouters <thomas at python.org> committer: Yhg1s <thomas at python.org> date: 2023-05-23T01:17:06+02:00 summary: gh-104764: Skip failing tests in test_enum that started failing. (#104765) Skip failing tests in test_enum that started failing when the version was bumped to 3.13. files: M Lib/test/test_enum.py diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index fb7a016c9007..350554bfd2cc 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1090,7 +1090,7 @@ class Inner(Enum): ) @unittest.skipIf( - python_version < (3, 13), + python_version < (3, 14), 'inner classes are still members', ) def test_nested_classes_in_enum_are_not_members(self): @@ -4261,8 +4261,8 @@ class Color(Enum): self.assertEqual(Color.green.value, 3) @unittest.skipIf( - python_version < (3, 13), - 'mixed types with auto() will raise in 3.13', + python_version < (3, 14), + 'mixed types with auto() will raise in the future', ) def test_auto_garbage_fail(self): with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'): @@ -4271,8 +4271,8 @@ class Color(Enum): blue = auto() @unittest.skipIf( - python_version < (3, 13), - 'mixed types with auto() will raise in 3.13', + python_version < (3, 14), + 'mixed types with auto() will raise in the future', ) def test_auto_garbage_corrected_fail(self): with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'): @@ -4303,8 +4303,8 @@ def _generate_next_value_(name, start, count, last): self.assertEqual(Color.blue.value, 'blue') @unittest.skipIf( - python_version < (3, 13), - 'auto() will return highest value + 1 in 3.13', + python_version < (3, 14), + 'auto() will return highest value + 1 in the future', ) def test_auto_with_aliases(self): class Color(Enum): From webhook-mailer at python.org Mon May 22 19:20:12 2023 From: webhook-mailer at python.org (Yhg1s) Date: Mon, 22 May 2023 23:20:12 -0000 Subject: [Python-checkins] [3.12] Add the 3.12 branch to the github workflows. (GH-104768) (#104769) Message-ID: <mailman.5.1684797613.17421.python-checkins@python.org> https://github.com/python/cpython/commit/97f85479131ad34daa3bc50e33c471fb2fe6c056 commit: 97f85479131ad34daa3bc50e33c471fb2fe6c056 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Yhg1s <thomas at python.org> date: 2023-05-23T01:20:05+02:00 summary: [3.12] Add the 3.12 branch to the github workflows. (GH-104768) (#104769) Add the 3.12 branch to the github workflows. (GH-104768) (cherry picked from commit 4194d8f2c40f478eb0fc9b6fa9b913baaff229da) Co-authored-by: T. Wouters <thomas at python.org> files: M .github/workflows/build.yml M .github/workflows/doc.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 41abddffa5d6..b9797192dba0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: push: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' @@ -16,6 +17,7 @@ on: pull_request: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 3f7550cc7294..ec900ce68a1d 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -5,6 +5,7 @@ on: #push: # branches: # - 'main' + # - '3.12' # - '3.11' # - '3.10' # - '3.9' @@ -15,6 +16,7 @@ on: pull_request: branches: - 'main' + - '3.12' - '3.11' - '3.10' - '3.9' From webhook-mailer at python.org Mon May 22 19:27:18 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 22 May 2023 23:27:18 -0000 Subject: [Python-checkins] Add codeowners for the tokenizer module (#104753) Message-ID: <mailman.6.1684798039.17421.python-checkins@python.org> https://github.com/python/cpython/commit/988c1f68ce7f99f43322722c4a4f8f85b40bbcd8 commit: 988c1f68ce7f99f43322722c4a4f8f85b40bbcd8 branch: main author: Pablo Galindo Salgado <Pablogsal at gmail.com> committer: pablogsal <Pablogsal at gmail.com> date: 2023-05-23T00:27:10+01:00 summary: Add codeowners for the tokenizer module (#104753) files: M .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 32ba5355a585..d218f029a990 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -97,6 +97,8 @@ Include/pytime.h @pganssle @abalkin /Tools/peg_generator/ @pablogsal @lysnikolaou /Lib/test/test_peg_generator/ @pablogsal @lysnikolaou /Grammar/python.gram @pablogsal @lysnikolaou +/Lib/tokenize.py @pablogsal @lysnikolaou +/Lib/test/test_tokenize.py @pablogsal @lysnikolaou # AST Python/ast.c @isidentical From webhook-mailer at python.org Mon May 22 20:06:48 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 23 May 2023 00:06:48 -0000 Subject: [Python-checkins] gh-99108: Release the GIL around hashlib built-in computation (#104675) Message-ID: <mailman.7.1684800409.17421.python-checkins@python.org> https://github.com/python/cpython/commit/2e5d8a90aa633ff0bebc9b2b8e21eea389937b19 commit: 2e5d8a90aa633ff0bebc9b2b8e21eea389937b19 branch: main author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-23T00:06:41Z summary: gh-99108: Release the GIL around hashlib built-in computation (#104675) This matches the GIL releasing behavior of our existing `_hashopenssl` module, extending it to the HACL* built-ins. Includes adding comments to better describe the ENTER/LEAVE macros purpose and explain the lock strategy in both existing and new code. files: A Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst M Modules/_hashopenssl.c M Modules/hashlib.h M Modules/md5module.c M Modules/sha1module.c M Modules/sha2module.c M Modules/sha3module.c diff --git a/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst new file mode 100644 index 000000000000..b595f1893609 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst @@ -0,0 +1,3 @@ +We now release the GIL around built-in :mod:`hashlib` computations of +reasonable size for the SHA families and MD5 hash functions, matching +what our OpenSSL backed hash computations already does. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 99d0b7281913..4b425f414751 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -227,12 +227,16 @@ get_hashlib_state(PyObject *module) typedef struct { PyObject_HEAD EVP_MD_CTX *ctx; /* OpenSSL message digest context */ + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. PyThread_type_lock lock; /* OpenSSL context lock */ } EVPobject; typedef struct { PyObject_HEAD HMAC_CTX *ctx; /* OpenSSL hmac context */ + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. PyThread_type_lock lock; /* HMAC context lock */ } HMACobject; @@ -896,6 +900,8 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj, if (view.buf && view.len) { if (view.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ Py_BEGIN_ALLOW_THREADS result = EVP_hash(self, view.buf, view.len); Py_END_ALLOW_THREADS diff --git a/Modules/hashlib.h b/Modules/hashlib.h index 56ae7a5e50bf..a8bad9dd87a9 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -37,6 +37,13 @@ * LEAVE_HASHLIB block or explicitly acquire and release the lock inside * a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for * an operation. + * + * These only drop the GIL if the lock acquisition itself is likely to + * block. Thus the non-blocking acquire gating the GIL release for a + * blocking lock acquisition. The intent of these macros is to surround + * the assumed always "fast" operations that you aren't releasing the + * GIL around. Otherwise use code similar to what you see in hash + * function update() methods. */ #include "pythread.h" @@ -53,7 +60,7 @@ PyThread_release_lock((obj)->lock); \ } -/* TODO(gps): We should probably make this a module or EVPobject attribute +/* TODO(gpshead): We should make this a module or class attribute * to allow the user to optimize based on the platform they're using. */ #define HASHLIB_GIL_MINSIZE 2048 diff --git a/Modules/md5module.c b/Modules/md5module.c index 86605771d964..2122f8b18baf 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -49,7 +49,9 @@ typedef long long MD5_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD - + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_MD5_state *hash_state; } MD5object; @@ -72,6 +74,7 @@ static MD5object * newMD5object(MD5State * st) { MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); + md5->lock = NULL; PyObject_GC_Track(md5); return md5; } @@ -88,6 +91,9 @@ static void MD5_dealloc(MD5object *ptr) { Hacl_Streaming_MD5_legacy_free(ptr->hash_state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -115,7 +121,9 @@ MD5Type_copy_impl(MD5object *self, PyTypeObject *cls) if ((newobj = newMD5object(st))==NULL) return NULL; + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_MD5_legacy_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -130,7 +138,9 @@ MD5Type_digest_impl(MD5object *self) /*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/ { unsigned char digest[MD5_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE); } @@ -145,7 +155,9 @@ MD5Type_hexdigest_impl(MD5object *self) /*[clinic end generated code: output=17badced1f3ac932 input=b60b19de644798dd]*/ { unsigned char digest[MD5_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char*)digest, MD5_DIGESTSIZE); } @@ -177,7 +189,18 @@ MD5Type_update(MD5object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -279,7 +302,15 @@ _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update(new->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update(new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update(new->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha1module.c b/Modules/sha1module.c index bdb76c56f1a6..c66269b5f5cd 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -48,7 +48,9 @@ typedef long long SHA1_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD - + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA1_state *hash_state; } SHA1object; @@ -71,6 +73,7 @@ static SHA1object * newSHA1object(SHA1State *st) { SHA1object *sha = (SHA1object *)PyObject_GC_New(SHA1object, st->sha1_type); + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -88,6 +91,9 @@ static void SHA1_dealloc(SHA1object *ptr) { Hacl_Streaming_SHA1_legacy_free(ptr->hash_state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -115,7 +121,9 @@ SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls) if ((newobj = newSHA1object(st)) == NULL) return NULL; + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_SHA1_legacy_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -130,7 +138,9 @@ SHA1Type_digest_impl(SHA1object *self) /*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/ { unsigned char digest[SHA1_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE); } @@ -145,7 +155,9 @@ SHA1Type_hexdigest_impl(SHA1object *self) /*[clinic end generated code: output=4161fd71e68c6659 input=97691055c0c74ab0]*/ { unsigned char digest[SHA1_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, SHA1_DIGESTSIZE); } @@ -177,7 +189,18 @@ SHA1Type_update(SHA1object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -279,7 +302,15 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update(new->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update(new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update(new->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 37d9b5c538fd..6c7c3917198d 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -52,12 +52,18 @@ class SHA512Type "SHA512object *" "&PyType_Type" typedef struct { PyObject_HEAD int digestsize; + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA2_state_sha2_256 *state; } SHA256object; typedef struct { PyObject_HEAD int digestsize; + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA2_state_sha2_512 *state; } SHA512object; @@ -100,6 +106,7 @@ newSHA224object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -112,6 +119,7 @@ newSHA256object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -124,6 +132,7 @@ newSHA384object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -136,6 +145,7 @@ newSHA512object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -153,6 +163,9 @@ static void SHA256_dealloc(SHA256object *ptr) { Hacl_Streaming_SHA2_free_256(ptr->state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -163,6 +176,9 @@ static void SHA512_dealloc(SHA512object *ptr) { Hacl_Streaming_SHA2_free_512(ptr->state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -229,7 +245,9 @@ SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls) } } + ENTER_HASHLIB(self); SHA256copy(self, newobj); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -259,7 +277,9 @@ SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls) } } + ENTER_HASHLIB(self); SHA512copy(self, newobj); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -275,9 +295,11 @@ SHA256Type_digest_impl(SHA256object *self) { uint8_t digest[SHA256_DIGESTSIZE]; assert(self->digestsize <= SHA256_DIGESTSIZE); + ENTER_HASHLIB(self); // HACL* performs copies under the hood so that self->state remains valid // after this call. Hacl_Streaming_SHA2_finish_256(self->state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -293,9 +315,11 @@ SHA512Type_digest_impl(SHA512object *self) { uint8_t digest[SHA512_DIGESTSIZE]; assert(self->digestsize <= SHA512_DIGESTSIZE); + ENTER_HASHLIB(self); // HACL* performs copies under the hood so that self->state remains valid // after this call. Hacl_Streaming_SHA2_finish_512(self->state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -311,7 +335,9 @@ SHA256Type_hexdigest_impl(SHA256object *self) { uint8_t digest[SHA256_DIGESTSIZE]; assert(self->digestsize <= SHA256_DIGESTSIZE); + ENTER_HASHLIB(self); Hacl_Streaming_SHA2_finish_256(self->state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, self->digestsize); } @@ -327,7 +353,9 @@ SHA512Type_hexdigest_impl(SHA512object *self) { uint8_t digest[SHA512_DIGESTSIZE]; assert(self->digestsize <= SHA512_DIGESTSIZE); + ENTER_HASHLIB(self); Hacl_Streaming_SHA2_finish_512(self->state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, self->digestsize); } @@ -348,7 +376,18 @@ SHA256Type_update(SHA256object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update_256(self->state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update_256(self->state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update_256(self->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -371,7 +410,18 @@ SHA512Type_update(SHA512object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update_512(self->state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update_512(self->state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update_512(self->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -560,7 +610,15 @@ _sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_256(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_256(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_256(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -606,7 +664,15 @@ _sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_256(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_256(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_256(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -651,7 +717,15 @@ _sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_512(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_512(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_512(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -696,7 +770,15 @@ _sha2_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_512(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_512(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_512(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha3module.c b/Modules/sha3module.c index f05187498a19..558d2005cff6 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -60,6 +60,9 @@ class _sha3.shake_256 "SHA3object *" "&SHAKE256type" typedef struct { PyObject_HEAD + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_Keccak_state *hash_state; } SHA3object; @@ -73,6 +76,7 @@ newSHA3object(PyTypeObject *type) if (newobj == NULL) { return NULL; } + newobj->lock = NULL; return newobj; } @@ -133,7 +137,15 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) if (data) { GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error); - sha3_update(self->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + sha3_update(self->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + sha3_update(self->hash_state, buf.buf, buf.len); + } } PyBuffer_Release(&buf); @@ -157,6 +169,9 @@ static void SHA3_dealloc(SHA3object *self) { Hacl_Streaming_Keccak_free(self->hash_state); + if (self->lock != NULL) { + PyThread_free_lock(self->lock); + } PyTypeObject *tp = Py_TYPE(self); PyObject_Free(self); Py_DECREF(tp); @@ -181,7 +196,9 @@ _sha3_sha3_224_copy_impl(SHA3object *self) if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) { return NULL; } + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_Keccak_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -199,7 +216,9 @@ _sha3_sha3_224_digest_impl(SHA3object *self) unsigned char digest[SHA3_MAX_DIGESTSIZE]; // This function errors out if the algorithm is Shake. Here, we know this // not to be the case, and therefore do not perform error checking. + ENTER_HASHLIB(self); Hacl_Streaming_Keccak_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -216,7 +235,9 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self) /*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/ { unsigned char digest[SHA3_MAX_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_Keccak_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -237,7 +258,18 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data) { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - sha3_update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + sha3_update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + sha3_update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; } From webhook-mailer at python.org Mon May 22 21:59:47 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 23 May 2023 01:59:47 -0000 Subject: [Python-checkins] gh-104764: [Enum] fix 3.13-specific tests (GH-104779) Message-ID: <mailman.8.1684807189.17421.python-checkins@python.org> https://github.com/python/cpython/commit/5ecd8c85f934e13a5ff98db6539d89e0c7c03f2d commit: 5ecd8c85f934e13a5ff98db6539d89e0c7c03f2d branch: main author: Ethan Furman <ethan at stoneleaf.us> committer: ethanfurman <ethan at stoneleaf.us> date: 2023-05-22T18:59:40-07:00 summary: gh-104764: [Enum] fix 3.13-specific tests (GH-104779) files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 6e497f7ef6a7..b50fe50d8258 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -388,16 +388,8 @@ def __setitem__(self, key, value): Single underscore (sunder) names are reserved. """ - if _is_internal_class(self._cls_name, value): - import warnings - warnings.warn( - "In 3.13 classes created inside an enum will not become a member. " - "Use the `member` decorator to keep the current behavior.", - DeprecationWarning, - stacklevel=2, - ) if _is_private(self._cls_name, key): - # also do nothing, name will be a normal attribute + # do nothing, name will be a normal attribute pass elif _is_sunder(key): if key not in ( @@ -440,10 +432,9 @@ def __setitem__(self, key, value): value = value.value elif _is_descriptor(value): pass - # TODO: uncomment next three lines in 3.13 - # elif _is_internal_class(self._cls_name, value): - # # do nothing, name will be a normal attribute - # pass + elif _is_internal_class(self._cls_name, value): + # do nothing, name will be a normal attribute + pass else: if key in self: # enum overwriting a descriptor? @@ -1169,28 +1160,13 @@ def _generate_next_value_(name, start, count, last_values): if not last_values: return start try: - last = last_values[-1] - last_values.sort() - if last == last_values[-1]: - # no difference between old and new methods - return last + 1 - else: - # trigger old method (with warning) - raise TypeError + last_value = sorted(last_values).pop() except TypeError: - import warnings - warnings.warn( - "In 3.13 the default `auto()`/`_generate_next_value_` will require all values to be sortable and support adding +1\n" - "and the value returned will be the largest value in the enum incremented by 1", - DeprecationWarning, - stacklevel=3, - ) - for v in last_values: - try: - return v + 1 - except TypeError: - pass - return start + raise TypeError('unable to sort non-numeric values') from None + try: + return last_value + 1 + except TypeError: + raise TypeError('unable to increment %r' % (last_value, )) from None @classmethod def _missing_(cls, value): diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 350554bfd2cc..fe701025b70f 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1090,7 +1090,7 @@ class Inner(Enum): ) @unittest.skipIf( - python_version < (3, 14), + python_version < (3, 13), 'inner classes are still members', ) def test_nested_classes_in_enum_are_not_members(self): @@ -4261,21 +4261,21 @@ class Color(Enum): self.assertEqual(Color.green.value, 3) @unittest.skipIf( - python_version < (3, 14), - 'mixed types with auto() will raise in the future', + python_version < (3, 13), + 'mixed types with auto() will raise in 3.13', ) def test_auto_garbage_fail(self): - with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'): + with self.assertRaisesRegex(TypeError, "unable to increment 'red'"): class Color(Enum): red = 'red' blue = auto() @unittest.skipIf( - python_version < (3, 14), - 'mixed types with auto() will raise in the future', + python_version < (3, 13), + 'mixed types with auto() will raise in 3.13', ) def test_auto_garbage_corrected_fail(self): - with self.assertRaisesRegex(TypeError, 'will require all values to be sortable'): + with self.assertRaisesRegex(TypeError, 'unable to sort non-numeric values'): class Color(Enum): red = 'red' blue = 2 @@ -4303,8 +4303,8 @@ def _generate_next_value_(name, start, count, last): self.assertEqual(Color.blue.value, 'blue') @unittest.skipIf( - python_version < (3, 14), - 'auto() will return highest value + 1 in the future', + python_version < (3, 13), + 'auto() will return highest value + 1 in 3.13', ) def test_auto_with_aliases(self): class Color(Enum): From webhook-mailer at python.org Tue May 23 03:09:10 2023 From: webhook-mailer at python.org (vstinner) Date: Tue, 23 May 2023 07:09:10 -0000 Subject: [Python-checkins] gh-104773: PEP 594: Remove the telnetlib module (#104778) Message-ID: <mailman.9.1684825751.17421.python-checkins@python.org> https://github.com/python/cpython/commit/9dc476be2dcfc9bcf53bcb83f4b8d555682d0600 commit: 9dc476be2dcfc9bcf53bcb83f4b8d555682d0600 branch: main author: Victor Stinner <vstinner at python.org> committer: vstinner <vstinner at python.org> date: 2023-05-23T07:09:02Z summary: gh-104773: PEP 594: Remove the telnetlib module (#104778) files: A Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst D Doc/library/telnetlib.rst D Lib/telnetlib.py D Lib/test/test_telnetlib.py M Doc/library/superseded.rst M Doc/tools/.nitignore M Doc/whatsnew/2.6.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.13.rst M Doc/whatsnew/3.6.rst M Misc/NEWS.d/3.9.0a1.rst M Python/stdlib_module_names.h M Tools/wasm/wasm_assets.py diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index aaf66ea121d3..e4a473f71284 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -27,6 +27,5 @@ backwards compatibility. They have been superseded by other modules. sndhdr.rst spwd.rst sunau.rst - telnetlib.rst uu.rst xdrlib.rst diff --git a/Doc/library/telnetlib.rst b/Doc/library/telnetlib.rst deleted file mode 100644 index 5a993dc42a5a..000000000000 --- a/Doc/library/telnetlib.rst +++ /dev/null @@ -1,262 +0,0 @@ -:mod:`telnetlib` --- Telnet client -================================== - -.. module:: telnetlib - :synopsis: Telnet client class. - :deprecated: - -.. sectionauthor:: Skip Montanaro <skip at pobox.com> - -**Source code:** :source:`Lib/telnetlib.py` - -.. index:: single: protocol; Telnet - -.. deprecated-removed:: 3.11 3.13 - The :mod:`telnetlib` module is deprecated - (see :pep:`PEP 594 <594#telnetlib>` for details and alternatives). - --------------- - -The :mod:`telnetlib` module provides a :class:`Telnet` class that implements the -Telnet protocol. See :rfc:`854` for details about the protocol. In addition, it -provides symbolic constants for the protocol characters (see below), and for the -telnet options. The symbolic names of the telnet options follow the definitions -in ``arpa/telnet.h``, with the leading ``TELOPT_`` removed. For symbolic names -of options which are traditionally not included in ``arpa/telnet.h``, see the -module source itself. - -The symbolic constants for the telnet commands are: IAC, DONT, DO, WONT, WILL, -SE (Subnegotiation End), NOP (No Operation), DM (Data Mark), BRK (Break), IP -(Interrupt process), AO (Abort output), AYT (Are You There), EC (Erase -Character), EL (Erase Line), GA (Go Ahead), SB (Subnegotiation Begin). - -.. include:: ../includes/wasm-notavail.rst - -.. class:: Telnet(host=None, port=0[, timeout]) - - :class:`Telnet` represents a connection to a Telnet server. The instance is - initially not connected by default; the :meth:`~Telnet.open` method must be used to - establish a connection. Alternatively, the host name and optional port - number can be passed to the constructor too, in which case the connection to - the server will be established before the constructor returns. The optional - *timeout* parameter specifies a timeout in seconds for blocking operations - like the connection attempt (if not specified, the global default timeout - setting will be used). - - Do not reopen an already connected instance. - - This class has many :meth:`read_\*` methods. Note that some of them raise - :exc:`EOFError` when the end of the connection is read, because they can return - an empty string for other reasons. See the individual descriptions below. - - A :class:`Telnet` object is a context manager and can be used in a - :keyword:`with` statement. When the :keyword:`!with` block ends, the - :meth:`close` method is called:: - - >>> from telnetlib import Telnet - >>> with Telnet('localhost', 23) as tn: - ... tn.interact() - ... - - .. versionchanged:: 3.6 Context manager support added - - -.. seealso:: - - :rfc:`854` - Telnet Protocol Specification - Definition of the Telnet protocol. - - -.. _telnet-objects: - -Telnet Objects --------------- - -:class:`Telnet` instances have the following methods: - - -.. method:: Telnet.read_until(expected, timeout=None) - - Read until a given byte string, *expected*, is encountered or until *timeout* - seconds have passed. - - When no match is found, return whatever is available instead, possibly empty - bytes. Raise :exc:`EOFError` if the connection is closed and no cooked data - is available. - - -.. method:: Telnet.read_all() - - Read all data until EOF as bytes; block until connection closed. - - -.. method:: Telnet.read_some() - - Read at least one byte of cooked data unless EOF is hit. Return ``b''`` if - EOF is hit. Block if no data is immediately available. - - -.. method:: Telnet.read_very_eager() - - Read everything that can be without blocking in I/O (eager). - - Raise :exc:`EOFError` if connection closed and no cooked data available. - Return ``b''`` if no cooked data available otherwise. Do not block unless in - the midst of an IAC sequence. - - -.. method:: Telnet.read_eager() - - Read readily available data. - - Raise :exc:`EOFError` if connection closed and no cooked data available. - Return ``b''`` if no cooked data available otherwise. Do not block unless in - the midst of an IAC sequence. - - -.. method:: Telnet.read_lazy() - - Process and return data already in the queues (lazy). - - Raise :exc:`EOFError` if connection closed and no data available. Return - ``b''`` if no cooked data available otherwise. Do not block unless in the - midst of an IAC sequence. - - -.. method:: Telnet.read_very_lazy() - - Return any data available in the cooked queue (very lazy). - - Raise :exc:`EOFError` if connection closed and no data available. Return - ``b''`` if no cooked data available otherwise. This method never blocks. - - -.. method:: Telnet.read_sb_data() - - Return the data collected between a SB/SE pair (suboption begin/end). The - callback should access these data when it was invoked with a ``SE`` command. - This method never blocks. - - -.. method:: Telnet.open(host, port=0[, timeout]) - - Connect to a host. The optional second argument is the port number, which - defaults to the standard Telnet port (23). The optional *timeout* parameter - specifies a timeout in seconds for blocking operations like the connection - attempt (if not specified, the global default timeout setting will be used). - - Do not try to reopen an already connected instance. - - .. audit-event:: telnetlib.Telnet.open self,host,port telnetlib.Telnet.open - - -.. method:: Telnet.msg(msg, *args) - - Print a debug message when the debug level is ``>`` 0. If extra arguments are - present, they are substituted in the message using the standard string - formatting operator. - - -.. method:: Telnet.set_debuglevel(debuglevel) - - Set the debug level. The higher the value of *debuglevel*, the more debug - output you get (on ``sys.stdout``). - - -.. method:: Telnet.close() - - Close the connection. - - -.. method:: Telnet.get_socket() - - Return the socket object used internally. - - -.. method:: Telnet.fileno() - - Return the file descriptor of the socket object used internally. - - -.. method:: Telnet.write(buffer) - - Write a byte string to the socket, doubling any IAC characters. This can - block if the connection is blocked. May raise :exc:`OSError` if the - connection is closed. - - .. audit-event:: telnetlib.Telnet.write self,buffer telnetlib.Telnet.write - - .. versionchanged:: 3.3 - This method used to raise :exc:`socket.error`, which is now an alias - of :exc:`OSError`. - - -.. method:: Telnet.interact() - - Interaction function, emulates a very dumb Telnet client. - - -.. method:: Telnet.mt_interact() - - Multithreaded version of :meth:`interact`. - - -.. method:: Telnet.expect(list, timeout=None) - - Read until one from a list of a regular expressions matches. - - The first argument is a list of regular expressions, either compiled - (:ref:`regex objects <re-objects>`) or uncompiled (byte strings). The - optional second argument is a timeout, in seconds; the default is to block - indefinitely. - - Return a tuple of three items: the index in the list of the first regular - expression that matches; the match object returned; and the bytes read up - till and including the match. - - If end of file is found and no bytes were read, raise :exc:`EOFError`. - Otherwise, when nothing matches, return ``(-1, None, data)`` where *data* is - the bytes received so far (may be empty bytes if a timeout happened). - - If a regular expression ends with a greedy match (such as ``.*``) or if more - than one expression can match the same input, the results are - non-deterministic, and may depend on the I/O timing. - - -.. method:: Telnet.set_option_negotiation_callback(callback) - - Each time a telnet option is read on the input flow, this *callback* (if set) is - called with the following parameters: callback(telnet socket, command - (DO/DONT/WILL/WONT), option). No other action is done afterwards by telnetlib. - - -.. _telnet-example: - -Telnet Example --------------- - -.. sectionauthor:: Peter Funk <pf at artcom-gmbh.de> - - -A simple example illustrating typical use:: - - import getpass - import telnetlib - - HOST = "localhost" - user = input("Enter your remote account: ") - password = getpass.getpass() - - tn = telnetlib.Telnet(HOST) - - tn.read_until(b"login: ") - tn.write(user.encode('ascii') + b"\n") - if password: - tn.read_until(b"Password: ") - tn.write(password.encode('ascii') + b"\n") - - tn.write(b"ls\n") - tn.write(b"exit\n") - - print(tn.read_all().decode('ascii')) - diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 1d3503bf06f0..554e31ff51dd 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -215,7 +215,6 @@ 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 diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 84bb651e68ee..7236e1cad7c8 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -2465,7 +2465,7 @@ changes, or look through the Subversion logs for all the details. (All changes contributed by Lars Gust?bel). * An optional ``timeout`` parameter was added to the - :class:`telnetlib.Telnet` class constructor, specifying a timeout + :class:`!telnetlib.Telnet` class constructor, specifying a timeout measured in seconds. (Added by Facundo Batista.) * The :class:`tempfile.NamedTemporaryFile` class usually deletes diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 7a479c6e56a9..1a4a9936aca6 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1731,7 +1731,7 @@ Modules slated for removal in Python 3.13: +---------------------+---------------------+---------------------+---------------------+---------------------+ - | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`telnetlib` | + | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`!telnetlib` | +---------------------+---------------------+---------------------+---------------------+---------------------+ | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`sndhdr` | :mod:`uu` | +---------------------+---------------------+---------------------+---------------------+---------------------+ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4ff90664bb79..5e07a4caeb9e 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -819,7 +819,7 @@ Modules (see :pep:`594`): * :mod:`sndhdr` * :mod:`spwd` * :mod:`sunau` -* :mod:`telnetlib` +* :mod:`!telnetlib` * :mod:`uu` * :mod:`xdrlib` diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index af331c46f1c0..8256f429183a 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -102,6 +102,10 @@ Deprecated Removed ======= +* :pep:`594`: Remove the :mod:`!telnetlib` module, deprecated in Python 3.11: + use the projects `telnetlib3 <https://pypi.org/project/telnetlib3/>`_ or + `Exscript <https://pypi.org/project/Exscript/>`_ instead. + (Contributed by Victor Stinner in :gh:`104773`.) Porting to Python 3.13 diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 3a681754e25d..1cd33dfb6042 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -1520,7 +1520,7 @@ rather than the version that is being emulated for the process telnetlib --------- -:class:`~telnetlib.Telnet` is now a context manager (contributed by +:class:`!telnetlib.Telnet` is now a context manager (contributed by St?phane Wirtel in :issue:`25485`). diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py deleted file mode 100644 index 62d636129853..000000000000 --- a/Lib/telnetlib.py +++ /dev/null @@ -1,679 +0,0 @@ -r"""TELNET client class. - -Based on RFC 854: TELNET Protocol Specification, by J. Postel and -J. Reynolds - -Example: - ->>> from telnetlib import Telnet ->>> tn = Telnet('www.python.org', 79) # connect to finger port ->>> tn.write(b'guido\r\n') ->>> print(tn.read_all()) -Login Name TTY Idle When Where -guido Guido van Rossum pts/2 <Dec 2 11:10> snag.cnri.reston.. - ->>> - -Note that read_all() won't read until eof -- it just reads some data --- but it guarantees to read at least one byte unless EOF is hit. - -It is possible to pass a Telnet object to a selector in order to wait until -more data is available. Note that in this case, read_eager() may return b'' -even if there was data on the socket, because the protocol negotiation may have -eaten the data. This is why EOFError is needed in some cases to distinguish -between "no data" and "connection closed" (since the socket also appears ready -for reading when it is closed). - -To do: -- option negotiation -- timeout should be intrinsic to the connection object instead of an - option on one of the read calls only - -""" - - -# Imported modules -import sys -import socket -import selectors -from time import monotonic as _time -import warnings - -warnings._deprecated(__name__, remove=(3, 13)) - -__all__ = ["Telnet"] - -# Tunable parameters -DEBUGLEVEL = 0 - -# Telnet protocol defaults -TELNET_PORT = 23 - -# Telnet protocol characters (don't change) -IAC = bytes([255]) # "Interpret As Command" -DONT = bytes([254]) -DO = bytes([253]) -WONT = bytes([252]) -WILL = bytes([251]) -theNULL = bytes([0]) - -SE = bytes([240]) # Subnegotiation End -NOP = bytes([241]) # No Operation -DM = bytes([242]) # Data Mark -BRK = bytes([243]) # Break -IP = bytes([244]) # Interrupt process -AO = bytes([245]) # Abort output -AYT = bytes([246]) # Are You There -EC = bytes([247]) # Erase Character -EL = bytes([248]) # Erase Line -GA = bytes([249]) # Go Ahead -SB = bytes([250]) # Subnegotiation Begin - - -# Telnet protocol options code (don't change) -# These ones all come from arpa/telnet.h -BINARY = bytes([0]) # 8-bit data path -ECHO = bytes([1]) # echo -RCP = bytes([2]) # prepare to reconnect -SGA = bytes([3]) # suppress go ahead -NAMS = bytes([4]) # approximate message size -STATUS = bytes([5]) # give status -TM = bytes([6]) # timing mark -RCTE = bytes([7]) # remote controlled transmission and echo -NAOL = bytes([8]) # negotiate about output line width -NAOP = bytes([9]) # negotiate about output page size -NAOCRD = bytes([10]) # negotiate about CR disposition -NAOHTS = bytes([11]) # negotiate about horizontal tabstops -NAOHTD = bytes([12]) # negotiate about horizontal tab disposition -NAOFFD = bytes([13]) # negotiate about formfeed disposition -NAOVTS = bytes([14]) # negotiate about vertical tab stops -NAOVTD = bytes([15]) # negotiate about vertical tab disposition -NAOLFD = bytes([16]) # negotiate about output LF disposition -XASCII = bytes([17]) # extended ascii character set -LOGOUT = bytes([18]) # force logout -BM = bytes([19]) # byte macro -DET = bytes([20]) # data entry terminal -SUPDUP = bytes([21]) # supdup protocol -SUPDUPOUTPUT = bytes([22]) # supdup output -SNDLOC = bytes([23]) # send location -TTYPE = bytes([24]) # terminal type -EOR = bytes([25]) # end or record -TUID = bytes([26]) # TACACS user identification -OUTMRK = bytes([27]) # output marking -TTYLOC = bytes([28]) # terminal location number -VT3270REGIME = bytes([29]) # 3270 regime -X3PAD = bytes([30]) # X.3 PAD -NAWS = bytes([31]) # window size -TSPEED = bytes([32]) # terminal speed -LFLOW = bytes([33]) # remote flow control -LINEMODE = bytes([34]) # Linemode option -XDISPLOC = bytes([35]) # X Display Location -OLD_ENVIRON = bytes([36]) # Old - Environment variables -AUTHENTICATION = bytes([37]) # Authenticate -ENCRYPT = bytes([38]) # Encryption option -NEW_ENVIRON = bytes([39]) # New - Environment variables -# the following ones come from -# http://www.iana.org/assignments/telnet-options -# Unfortunately, that document does not assign identifiers -# to all of them, so we are making them up -TN3270E = bytes([40]) # TN3270E -XAUTH = bytes([41]) # XAUTH -CHARSET = bytes([42]) # CHARSET -RSP = bytes([43]) # Telnet Remote Serial Port -COM_PORT_OPTION = bytes([44]) # Com Port Control Option -SUPPRESS_LOCAL_ECHO = bytes([45]) # Telnet Suppress Local Echo -TLS = bytes([46]) # Telnet Start TLS -KERMIT = bytes([47]) # KERMIT -SEND_URL = bytes([48]) # SEND-URL -FORWARD_X = bytes([49]) # FORWARD_X -PRAGMA_LOGON = bytes([138]) # TELOPT PRAGMA LOGON -SSPI_LOGON = bytes([139]) # TELOPT SSPI LOGON -PRAGMA_HEARTBEAT = bytes([140]) # TELOPT PRAGMA HEARTBEAT -EXOPL = bytes([255]) # Extended-Options-List -NOOPT = bytes([0]) - - -# poll/select have the advantage of not requiring any extra file descriptor, -# contrarily to epoll/kqueue (also, they require a single syscall). -if hasattr(selectors, 'PollSelector'): - _TelnetSelector = selectors.PollSelector -else: - _TelnetSelector = selectors.SelectSelector - - -class Telnet: - - """Telnet interface class. - - An instance of this class represents a connection to a telnet - server. The instance is initially not connected; the open() - method must be used to establish a connection. Alternatively, the - host name and optional port number can be passed to the - constructor, too. - - Don't try to reopen an already connected instance. - - This class has many read_*() methods. Note that some of them - raise EOFError when the end of the connection is read, because - they can return an empty string for other reasons. See the - individual doc strings. - - read_until(expected, [timeout]) - Read until the expected string has been seen, or a timeout is - hit (default is no timeout); may block. - - read_all() - Read all data until EOF; may block. - - read_some() - Read at least one byte or EOF; may block. - - read_very_eager() - Read all data available already queued or on the socket, - without blocking. - - read_eager() - Read either data already queued or some data available on the - socket, without blocking. - - read_lazy() - Read all data in the raw queue (processing it first), without - doing any socket I/O. - - read_very_lazy() - Reads all data in the cooked queue, without doing any socket - I/O. - - read_sb_data() - Reads available data between SB ... SE sequence. Don't block. - - set_option_negotiation_callback(callback) - Each time a telnet option is read on the input flow, this callback - (if set) is called with the following parameters : - callback(telnet socket, command, option) - option will be chr(0) when there is no option. - No other action is done afterwards by telnetlib. - - """ - - def __init__(self, host=None, port=0, - timeout=socket._GLOBAL_DEFAULT_TIMEOUT): - """Constructor. - - When called without arguments, create an unconnected instance. - With a hostname argument, it connects the instance; port number - and timeout are optional. - """ - self.debuglevel = DEBUGLEVEL - self.host = host - self.port = port - self.timeout = timeout - self.sock = None - self.rawq = b'' - self.irawq = 0 - self.cookedq = b'' - self.eof = 0 - self.iacseq = b'' # Buffer for IAC sequence. - self.sb = 0 # flag for SB and SE sequence. - self.sbdataq = b'' - self.option_callback = None - if host is not None: - self.open(host, port, timeout) - - def open(self, host, port=0, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): - """Connect to a host. - - The optional second argument is the port number, which - defaults to the standard telnet port (23). - - Don't try to reopen an already connected instance. - """ - self.eof = 0 - if not port: - port = TELNET_PORT - self.host = host - self.port = port - self.timeout = timeout - sys.audit("telnetlib.Telnet.open", self, host, port) - self.sock = socket.create_connection((host, port), timeout) - - def __del__(self): - """Destructor -- close the connection.""" - self.close() - - def msg(self, msg, *args): - """Print a debug message, when the debug level is > 0. - - If extra arguments are present, they are substituted in the - message using the standard string formatting operator. - - """ - if self.debuglevel > 0: - print('Telnet(%s,%s):' % (self.host, self.port), end=' ') - if args: - print(msg % args) - else: - print(msg) - - def set_debuglevel(self, debuglevel): - """Set the debug level. - - The higher it is, the more debug output you get (on sys.stdout). - - """ - self.debuglevel = debuglevel - - def close(self): - """Close the connection.""" - sock = self.sock - self.sock = None - self.eof = True - self.iacseq = b'' - self.sb = 0 - if sock: - sock.close() - - def get_socket(self): - """Return the socket object used internally.""" - return self.sock - - def fileno(self): - """Return the fileno() of the socket object used internally.""" - return self.sock.fileno() - - def write(self, buffer): - """Write a string to the socket, doubling any IAC characters. - - Can block if the connection is blocked. May raise - OSError if the connection is closed. - - """ - if IAC in buffer: - buffer = buffer.replace(IAC, IAC+IAC) - sys.audit("telnetlib.Telnet.write", self, buffer) - self.msg("send %r", buffer) - self.sock.sendall(buffer) - - def read_until(self, match, timeout=None): - """Read until a given string is encountered or until timeout. - - When no match is found, return whatever is available instead, - possibly the empty string. Raise EOFError if the connection - is closed and no cooked data is available. - - """ - n = len(match) - self.process_rawq() - i = self.cookedq.find(match) - if i >= 0: - i = i+n - buf = self.cookedq[:i] - self.cookedq = self.cookedq[i:] - return buf - if timeout is not None: - deadline = _time() + timeout - with _TelnetSelector() as selector: - selector.register(self, selectors.EVENT_READ) - while not self.eof: - if selector.select(timeout): - i = max(0, len(self.cookedq)-n) - self.fill_rawq() - self.process_rawq() - i = self.cookedq.find(match, i) - if i >= 0: - i = i+n - buf = self.cookedq[:i] - self.cookedq = self.cookedq[i:] - return buf - if timeout is not None: - timeout = deadline - _time() - if timeout < 0: - break - return self.read_very_lazy() - - def read_all(self): - """Read all data until EOF; block until connection closed.""" - self.process_rawq() - while not self.eof: - self.fill_rawq() - self.process_rawq() - buf = self.cookedq - self.cookedq = b'' - return buf - - def read_some(self): - """Read at least one byte of cooked data unless EOF is hit. - - Return b'' if EOF is hit. Block if no data is immediately - available. - - """ - self.process_rawq() - while not self.cookedq and not self.eof: - self.fill_rawq() - self.process_rawq() - buf = self.cookedq - self.cookedq = b'' - return buf - - def read_very_eager(self): - """Read everything that's possible without blocking in I/O (eager). - - Raise EOFError if connection closed and no cooked data - available. Return b'' if no cooked data available otherwise. - Don't block unless in the midst of an IAC sequence. - - """ - self.process_rawq() - while not self.eof and self.sock_avail(): - self.fill_rawq() - self.process_rawq() - return self.read_very_lazy() - - def read_eager(self): - """Read readily available data. - - Raise EOFError if connection closed and no cooked data - available. Return b'' if no cooked data available otherwise. - Don't block unless in the midst of an IAC sequence. - - """ - self.process_rawq() - while not self.cookedq and not self.eof and self.sock_avail(): - self.fill_rawq() - self.process_rawq() - return self.read_very_lazy() - - def read_lazy(self): - """Process and return data that's already in the queues (lazy). - - Raise EOFError if connection closed and no data available. - Return b'' if no cooked data available otherwise. Don't block - unless in the midst of an IAC sequence. - - """ - self.process_rawq() - return self.read_very_lazy() - - def read_very_lazy(self): - """Return any data available in the cooked queue (very lazy). - - Raise EOFError if connection closed and no data available. - Return b'' if no cooked data available otherwise. Don't block. - - """ - buf = self.cookedq - self.cookedq = b'' - if not buf and self.eof and not self.rawq: - raise EOFError('telnet connection closed') - return buf - - def read_sb_data(self): - """Return any data available in the SB ... SE queue. - - Return b'' if no SB ... SE available. Should only be called - after seeing a SB or SE command. When a new SB command is - found, old unread SB data will be discarded. Don't block. - - """ - buf = self.sbdataq - self.sbdataq = b'' - return buf - - def set_option_negotiation_callback(self, callback): - """Provide a callback function called after each receipt of a telnet option.""" - self.option_callback = callback - - def process_rawq(self): - """Transfer from raw queue to cooked queue. - - Set self.eof when connection is closed. Don't block unless in - the midst of an IAC sequence. - - """ - buf = [b'', b''] - try: - while self.rawq: - c = self.rawq_getchar() - if not self.iacseq: - if c == theNULL: - continue - if c == b"\021": - continue - if c != IAC: - buf[self.sb] = buf[self.sb] + c - continue - else: - self.iacseq += c - elif len(self.iacseq) == 1: - # 'IAC: IAC CMD [OPTION only for WILL/WONT/DO/DONT]' - if c in (DO, DONT, WILL, WONT): - self.iacseq += c - continue - - self.iacseq = b'' - if c == IAC: - buf[self.sb] = buf[self.sb] + c - else: - if c == SB: # SB ... SE start. - self.sb = 1 - self.sbdataq = b'' - elif c == SE: - self.sb = 0 - self.sbdataq = self.sbdataq + buf[1] - buf[1] = b'' - if self.option_callback: - # Callback is supposed to look into - # the sbdataq - self.option_callback(self.sock, c, NOOPT) - else: - # We can't offer automatic processing of - # suboptions. Alas, we should not get any - # unless we did a WILL/DO before. - self.msg('IAC %d not recognized' % ord(c)) - elif len(self.iacseq) == 2: - cmd = self.iacseq[1:2] - self.iacseq = b'' - opt = c - if cmd in (DO, DONT): - self.msg('IAC %s %d', - cmd == DO and 'DO' or 'DONT', ord(opt)) - if self.option_callback: - self.option_callback(self.sock, cmd, opt) - else: - self.sock.sendall(IAC + WONT + opt) - elif cmd in (WILL, WONT): - self.msg('IAC %s %d', - cmd == WILL and 'WILL' or 'WONT', ord(opt)) - if self.option_callback: - self.option_callback(self.sock, cmd, opt) - else: - self.sock.sendall(IAC + DONT + opt) - except EOFError: # raised by self.rawq_getchar() - self.iacseq = b'' # Reset on EOF - self.sb = 0 - self.cookedq = self.cookedq + buf[0] - self.sbdataq = self.sbdataq + buf[1] - - def rawq_getchar(self): - """Get next char from raw queue. - - Block if no data is immediately available. Raise EOFError - when connection is closed. - - """ - if not self.rawq: - self.fill_rawq() - if self.eof: - raise EOFError - c = self.rawq[self.irawq:self.irawq+1] - self.irawq = self.irawq + 1 - if self.irawq >= len(self.rawq): - self.rawq = b'' - self.irawq = 0 - return c - - def fill_rawq(self): - """Fill raw queue from exactly one recv() system call. - - Block if no data is immediately available. Set self.eof when - connection is closed. - - """ - if self.irawq >= len(self.rawq): - self.rawq = b'' - self.irawq = 0 - # The buffer size should be fairly small so as to avoid quadratic - # behavior in process_rawq() above - buf = self.sock.recv(50) - self.msg("recv %r", buf) - self.eof = (not buf) - self.rawq = self.rawq + buf - - def sock_avail(self): - """Test whether data is available on the socket.""" - with _TelnetSelector() as selector: - selector.register(self, selectors.EVENT_READ) - return bool(selector.select(0)) - - def interact(self): - """Interaction function, emulates a very dumb telnet client.""" - if sys.platform == "win32": - self.mt_interact() - return - with _TelnetSelector() as selector: - selector.register(self, selectors.EVENT_READ) - selector.register(sys.stdin, selectors.EVENT_READ) - - while True: - for key, events in selector.select(): - if key.fileobj is self: - try: - text = self.read_eager() - except EOFError: - print('*** Connection closed by remote host ***') - return - if text: - sys.stdout.write(text.decode('ascii')) - sys.stdout.flush() - elif key.fileobj is sys.stdin: - line = sys.stdin.readline().encode('ascii') - if not line: - return - self.write(line) - - def mt_interact(self): - """Multithreaded version of interact().""" - import _thread - _thread.start_new_thread(self.listener, ()) - while 1: - line = sys.stdin.readline() - if not line: - break - self.write(line.encode('ascii')) - - def listener(self): - """Helper for mt_interact() -- this executes in the other thread.""" - while 1: - try: - data = self.read_eager() - except EOFError: - print('*** Connection closed by remote host ***') - return - if data: - sys.stdout.write(data.decode('ascii')) - else: - sys.stdout.flush() - - def expect(self, list, timeout=None): - """Read until one from a list of a regular expressions matches. - - The first argument is a list of regular expressions, either - compiled (re.Pattern instances) or uncompiled (strings). - The optional second argument is a timeout, in seconds; default - is no timeout. - - Return a tuple of three items: the index in the list of the - first regular expression that matches; the re.Match object - returned; and the text read up till and including the match. - - If EOF is read and no text was read, raise EOFError. - Otherwise, when nothing matches, return (-1, None, text) where - text is the text received so far (may be the empty string if a - timeout happened). - - If a regular expression ends with a greedy match (e.g. '.*') - or if more than one expression can match the same input, the - results are undeterministic, and may depend on the I/O timing. - - """ - re = None - list = list[:] - indices = range(len(list)) - for i in indices: - if not hasattr(list[i], "search"): - if not re: import re - list[i] = re.compile(list[i]) - if timeout is not None: - deadline = _time() + timeout - with _TelnetSelector() as selector: - selector.register(self, selectors.EVENT_READ) - while not self.eof: - self.process_rawq() - for i in indices: - m = list[i].search(self.cookedq) - if m: - e = m.end() - text = self.cookedq[:e] - self.cookedq = self.cookedq[e:] - return (i, m, text) - if timeout is not None: - ready = selector.select(timeout) - timeout = deadline - _time() - if not ready: - if timeout < 0: - break - else: - continue - self.fill_rawq() - text = self.read_very_lazy() - if not text and self.eof: - raise EOFError - return (-1, None, text) - - def __enter__(self): - return self - - def __exit__(self, type, value, traceback): - self.close() - - -def test(): - """Test program for telnetlib. - - Usage: python telnetlib.py [-d] ... [host [port]] - - Default host is localhost; default port is 23. - - """ - debuglevel = 0 - while sys.argv[1:] and sys.argv[1] == '-d': - debuglevel = debuglevel+1 - del sys.argv[1] - host = 'localhost' - if sys.argv[1:]: - host = sys.argv[1] - port = 0 - if sys.argv[2:]: - portstr = sys.argv[2] - try: - port = int(portstr) - except ValueError: - port = socket.getservbyname(portstr, 'tcp') - with Telnet() as tn: - tn.set_debuglevel(debuglevel) - tn.open(host, port, timeout=0.5) - tn.interact() - -if __name__ == '__main__': - test() diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py deleted file mode 100644 index a9cade2ee466..000000000000 --- a/Lib/test/test_telnetlib.py +++ /dev/null @@ -1,405 +0,0 @@ -import socket -import selectors -import threading -import contextlib - -from test import support -from test.support import socket_helper, warnings_helper -import unittest - -support.requires_working_socket(module=True) - -telnetlib = warnings_helper.import_deprecated('telnetlib') - -HOST = socket_helper.HOST - -def server(evt, serv): - serv.listen() - evt.set() - try: - conn, addr = serv.accept() - conn.close() - except TimeoutError: - pass - finally: - serv.close() - -class GeneralTests(unittest.TestCase): - - def setUp(self): - self.evt = threading.Event() - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.settimeout(60) # Safety net. Look issue 11812 - self.port = socket_helper.bind_port(self.sock) - self.thread = threading.Thread(target=server, args=(self.evt,self.sock)) - self.thread.daemon = True - self.thread.start() - self.evt.wait() - - def tearDown(self): - self.thread.join() - del self.thread # Clear out any dangling Thread objects. - - def testBasic(self): - # connects - telnet = telnetlib.Telnet(HOST, self.port) - telnet.sock.close() - - def testContextManager(self): - with telnetlib.Telnet(HOST, self.port) as tn: - self.assertIsNotNone(tn.get_socket()) - self.assertIsNone(tn.get_socket()) - - def testTimeoutDefault(self): - self.assertTrue(socket.getdefaulttimeout() is None) - socket.setdefaulttimeout(30) - try: - telnet = telnetlib.Telnet(HOST, self.port) - finally: - socket.setdefaulttimeout(None) - self.assertEqual(telnet.sock.gettimeout(), 30) - telnet.sock.close() - - def testTimeoutNone(self): - # None, having other default - self.assertTrue(socket.getdefaulttimeout() is None) - socket.setdefaulttimeout(30) - try: - telnet = telnetlib.Telnet(HOST, self.port, timeout=None) - finally: - socket.setdefaulttimeout(None) - self.assertTrue(telnet.sock.gettimeout() is None) - telnet.sock.close() - - def testTimeoutValue(self): - telnet = telnetlib.Telnet(HOST, self.port, timeout=30) - self.assertEqual(telnet.sock.gettimeout(), 30) - telnet.sock.close() - - def testTimeoutOpen(self): - telnet = telnetlib.Telnet() - telnet.open(HOST, self.port, timeout=30) - self.assertEqual(telnet.sock.gettimeout(), 30) - telnet.sock.close() - - def testGetters(self): - # Test telnet getter methods - telnet = telnetlib.Telnet(HOST, self.port, timeout=30) - t_sock = telnet.sock - self.assertEqual(telnet.get_socket(), t_sock) - self.assertEqual(telnet.fileno(), t_sock.fileno()) - telnet.sock.close() - -class SocketStub(object): - ''' a socket proxy that re-defines sendall() ''' - def __init__(self, reads=()): - self.reads = list(reads) # Intentionally make a copy. - self.writes = [] - self.block = False - def sendall(self, data): - self.writes.append(data) - def recv(self, size): - out = b'' - while self.reads and len(out) < size: - out += self.reads.pop(0) - if len(out) > size: - self.reads.insert(0, out[size:]) - out = out[:size] - return out - -class TelnetAlike(telnetlib.Telnet): - def fileno(self): - raise NotImplementedError() - def close(self): pass - def sock_avail(self): - return (not self.sock.block) - def msg(self, msg, *args): - with support.captured_stdout() as out: - telnetlib.Telnet.msg(self, msg, *args) - self._messages += out.getvalue() - return - -class MockSelector(selectors.BaseSelector): - - def __init__(self): - self.keys = {} - - @property - def resolution(self): - return 1e-3 - - def register(self, fileobj, events, data=None): - key = selectors.SelectorKey(fileobj, 0, events, data) - self.keys[fileobj] = key - return key - - def unregister(self, fileobj): - return self.keys.pop(fileobj) - - def select(self, timeout=None): - block = False - for fileobj in self.keys: - if isinstance(fileobj, TelnetAlike): - block = fileobj.sock.block - break - if block: - return [] - else: - return [(key, key.events) for key in self.keys.values()] - - def get_map(self): - return self.keys - - - at contextlib.contextmanager -def test_socket(reads): - def new_conn(*ignored): - return SocketStub(reads) - try: - old_conn = socket.create_connection - socket.create_connection = new_conn - yield None - finally: - socket.create_connection = old_conn - return - -def test_telnet(reads=(), cls=TelnetAlike): - ''' return a telnetlib.Telnet object that uses a SocketStub with - reads queued up to be read ''' - for x in reads: - assert type(x) is bytes, x - with test_socket(reads): - telnet = cls('dummy', 0) - telnet._messages = '' # debuglevel output - return telnet - -class ExpectAndReadTestCase(unittest.TestCase): - def setUp(self): - self.old_selector = telnetlib._TelnetSelector - telnetlib._TelnetSelector = MockSelector - def tearDown(self): - telnetlib._TelnetSelector = self.old_selector - -class ReadTests(ExpectAndReadTestCase): - def test_read_until(self): - """ - read_until(expected, timeout=None) - test the blocking version of read_util - """ - want = [b'xxxmatchyyy'] - telnet = test_telnet(want) - data = telnet.read_until(b'match') - self.assertEqual(data, b'xxxmatch', msg=(telnet.cookedq, telnet.rawq, telnet.sock.reads)) - - reads = [b'x' * 50, b'match', b'y' * 50] - expect = b''.join(reads[:-1]) - telnet = test_telnet(reads) - data = telnet.read_until(b'match') - self.assertEqual(data, expect) - - - def test_read_all(self): - """ - read_all() - Read all data until EOF; may block. - """ - reads = [b'x' * 500, b'y' * 500, b'z' * 500] - expect = b''.join(reads) - telnet = test_telnet(reads) - data = telnet.read_all() - self.assertEqual(data, expect) - return - - def test_read_some(self): - """ - read_some() - Read at least one byte or EOF; may block. - """ - # test 'at least one byte' - telnet = test_telnet([b'x' * 500]) - data = telnet.read_some() - self.assertTrue(len(data) >= 1) - # test EOF - telnet = test_telnet() - data = telnet.read_some() - self.assertEqual(b'', data) - - def _read_eager(self, func_name): - """ - read_*_eager() - Read all data available already queued or on the socket, - without blocking. - """ - want = b'x' * 100 - telnet = test_telnet([want]) - func = getattr(telnet, func_name) - telnet.sock.block = True - self.assertEqual(b'', func()) - telnet.sock.block = False - data = b'' - while True: - try: - data += func() - except EOFError: - break - self.assertEqual(data, want) - - def test_read_eager(self): - # read_eager and read_very_eager make the same guarantees - # (they behave differently but we only test the guarantees) - self._read_eager('read_eager') - self._read_eager('read_very_eager') - # NB -- we need to test the IAC block which is mentioned in the - # docstring but not in the module docs - - def read_very_lazy(self): - want = b'x' * 100 - telnet = test_telnet([want]) - self.assertEqual(b'', telnet.read_very_lazy()) - while telnet.sock.reads: - telnet.fill_rawq() - data = telnet.read_very_lazy() - self.assertEqual(want, data) - self.assertRaises(EOFError, telnet.read_very_lazy) - - def test_read_lazy(self): - want = b'x' * 100 - telnet = test_telnet([want]) - self.assertEqual(b'', telnet.read_lazy()) - data = b'' - while True: - try: - read_data = telnet.read_lazy() - data += read_data - if not read_data: - telnet.fill_rawq() - except EOFError: - break - self.assertTrue(want.startswith(data)) - self.assertEqual(data, want) - -class nego_collector(object): - def __init__(self, sb_getter=None): - self.seen = b'' - self.sb_getter = sb_getter - self.sb_seen = b'' - - def do_nego(self, sock, cmd, opt): - self.seen += cmd + opt - if cmd == tl.SE and self.sb_getter: - sb_data = self.sb_getter() - self.sb_seen += sb_data - -tl = telnetlib - -class WriteTests(unittest.TestCase): - '''The only thing that write does is replace each tl.IAC for - tl.IAC+tl.IAC''' - - def test_write(self): - data_sample = [b'data sample without IAC', - b'data sample with' + tl.IAC + b' one IAC', - b'a few' + tl.IAC + tl.IAC + b' iacs' + tl.IAC, - tl.IAC, - b''] - for data in data_sample: - telnet = test_telnet() - telnet.write(data) - written = b''.join(telnet.sock.writes) - self.assertEqual(data.replace(tl.IAC,tl.IAC+tl.IAC), written) - -class OptionTests(unittest.TestCase): - # RFC 854 commands - cmds = [tl.AO, tl.AYT, tl.BRK, tl.EC, tl.EL, tl.GA, tl.IP, tl.NOP] - - def _test_command(self, data): - """ helper for testing IAC + cmd """ - telnet = test_telnet(data) - data_len = len(b''.join(data)) - nego = nego_collector() - telnet.set_option_negotiation_callback(nego.do_nego) - txt = telnet.read_all() - cmd = nego.seen - self.assertTrue(len(cmd) > 0) # we expect at least one command - self.assertIn(cmd[:1], self.cmds) - self.assertEqual(cmd[1:2], tl.NOOPT) - self.assertEqual(data_len, len(txt + cmd)) - nego.sb_getter = None # break the nego => telnet cycle - - def test_IAC_commands(self): - for cmd in self.cmds: - self._test_command([tl.IAC, cmd]) - self._test_command([b'x' * 100, tl.IAC, cmd, b'y'*100]) - self._test_command([b'x' * 10, tl.IAC, cmd, b'y'*10]) - # all at once - self._test_command([tl.IAC + cmd for (cmd) in self.cmds]) - - def test_SB_commands(self): - # RFC 855, subnegotiations portion - send = [tl.IAC + tl.SB + tl.IAC + tl.SE, - tl.IAC + tl.SB + tl.IAC + tl.IAC + tl.IAC + tl.SE, - tl.IAC + tl.SB + tl.IAC + tl.IAC + b'aa' + tl.IAC + tl.SE, - tl.IAC + tl.SB + b'bb' + tl.IAC + tl.IAC + tl.IAC + tl.SE, - tl.IAC + tl.SB + b'cc' + tl.IAC + tl.IAC + b'dd' + tl.IAC + tl.SE, - ] - telnet = test_telnet(send) - nego = nego_collector(telnet.read_sb_data) - telnet.set_option_negotiation_callback(nego.do_nego) - txt = telnet.read_all() - self.assertEqual(txt, b'') - want_sb_data = tl.IAC + tl.IAC + b'aabb' + tl.IAC + b'cc' + tl.IAC + b'dd' - self.assertEqual(nego.sb_seen, want_sb_data) - self.assertEqual(b'', telnet.read_sb_data()) - nego.sb_getter = None # break the nego => telnet cycle - - def test_debuglevel_reads(self): - # test all the various places that self.msg(...) is called - given_a_expect_b = [ - # Telnet.fill_rawq - (b'a', ": recv b''\n"), - # Telnet.process_rawq - (tl.IAC + bytes([88]), ": IAC 88 not recognized\n"), - (tl.IAC + tl.DO + bytes([1]), ": IAC DO 1\n"), - (tl.IAC + tl.DONT + bytes([1]), ": IAC DONT 1\n"), - (tl.IAC + tl.WILL + bytes([1]), ": IAC WILL 1\n"), - (tl.IAC + tl.WONT + bytes([1]), ": IAC WONT 1\n"), - ] - for a, b in given_a_expect_b: - telnet = test_telnet([a]) - telnet.set_debuglevel(1) - txt = telnet.read_all() - self.assertIn(b, telnet._messages) - return - - def test_debuglevel_write(self): - telnet = test_telnet() - telnet.set_debuglevel(1) - telnet.write(b'xxx') - expected = "send b'xxx'\n" - self.assertIn(expected, telnet._messages) - - def test_debug_accepts_str_port(self): - # Issue 10695 - with test_socket([]): - telnet = TelnetAlike('dummy', '0') - telnet._messages = '' - telnet.set_debuglevel(1) - telnet.msg('test') - self.assertRegex(telnet._messages, r'0.*test') - - -class ExpectTests(ExpectAndReadTestCase): - def test_expect(self): - """ - expect(expected, [timeout]) - Read until the expected string has been seen, or a timeout is - hit (default is no timeout); may block. - """ - want = [b'x' * 10, b'match', b'y' * 10] - telnet = test_telnet(want) - (_,_,data) = telnet.expect([b'match']) - self.assertEqual(data, b''.join(want[:-1])) - - -if __name__ == '__main__': - unittest.main() diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 0888a5c43087..7da438597318 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -99,7 +99,7 @@ after whitespace, e.g. '127.0.0.1 whatever'. Adds audit events for :mod:`ensurepip`, :mod:`ftplib`, :mod:`glob`, :mod:`imaplib`, :mod:`nntplib`, :mod:`pdb`, :mod:`poplib`, :mod:`shutil`, -:mod:`smtplib`, :mod:`sqlite3`, :mod:`subprocess`, :mod:`telnetlib`, +:mod:`smtplib`, :mod:`sqlite3`, :mod:`subprocess`, :mod:`!telnetlib`, :mod:`tempfile` and :mod:`webbrowser`, as well as :func:`os.listdir`, :func:`os.scandir` and :func:`breakpoint`. diff --git a/Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst b/Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst new file mode 100644 index 000000000000..0f3162ef509a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-02-20-13.gh-issue-104773.7K59zr.rst @@ -0,0 +1,2 @@ +:pep:`594`: Remove the :mod:`!telnetlib` module, deprecated in Python 3.11. +Patch by Victor Stinner. diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index ed4a0ac2dd32..4b0580557fb7 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -261,7 +261,6 @@ static const char* _Py_stdlib_module_names[] = { "syslog", "tabnanny", "tarfile", -"telnetlib", "tempfile", "termios", "textwrap", diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py index 1fc97fd5e70a..22bf9eabdcd6 100755 --- a/Tools/wasm/wasm_assets.py +++ b/Tools/wasm/wasm_assets.py @@ -78,7 +78,6 @@ "poplib.py", "smtplib.py", "socketserver.py", - "telnetlib.py", # keep urllib.parse for pydoc "urllib/error.py", "urllib/request.py", From webhook-mailer at python.org Tue May 23 04:11:17 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 23 May 2023 08:11:17 -0000 Subject: [Python-checkins] [3.11] gh-103726: Set up gcc-10 for ASAN (gh-103728) (#104794) Message-ID: <mailman.10.1684829478.17421.python-checkins@python.org> https://github.com/python/cpython/commit/ac12a6bf34e8fb55958f027444f58016aa9600ea commit: ac12a6bf34e8fb55958f027444f58016aa9600ea branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-23T08:10:44Z summary: [3.11] gh-103726: Set up gcc-10 for ASAN (gh-103728) (#104794) Set up gcc-10 for ASAN CI as the existing config's default 9.x does not play well with `vfork()`. <!-- Thanks for your contribution! Please read this comment in its entirety. It's quite important. GH- Pull Request title It should be in the following format: ``` gh-NNNNN: Summary of the changes made ``` Where: gh-NNNNN refers to the GitHub issue number. Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue. GH- Backport Pull Request title If this is a backport PR (PR made against branches other than `main`), please ensure that the PR title is in the following format: ``` [X.Y] <title from the original PR> (GH-NNNN) ``` Where: [X.Y] is the branch name, e.g. [3.6]. GH-NNNN refers to the PR number from `main`. --> <!-- gh-issue-number: gh-103726 --> * Issue: gh-103726 <!-- /gh-issue-number --> (cherry picked from commit 83305808000e03cbad31ac3e9ef65454fb409282) Co-authored-by: Dong-hee Na <donghee.na at python.org> files: M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 597797f73585..93dcb3f5f414 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -338,6 +338,10 @@ jobs: run: echo "::add-matcher::.github/problem-matchers/gcc.json" - name: Install Dependencies run: sudo ./.github/workflows/posix-deps-apt.sh + - name: Set up GCC-10 for ASAN + uses: egor-tensin/setup-gcc at v1 + with: + version: 10 - name: Configure OpenSSL env vars run: | echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV From webhook-mailer at python.org Tue May 23 04:56:31 2023 From: webhook-mailer at python.org (Yhg1s) Date: Tue, 23 May 2023 08:56:31 -0000 Subject: [Python-checkins] [3.12] gh-87891: Add ABI check to CI (#104793) Message-ID: <mailman.11.1684832193.17421.python-checkins@python.org> https://github.com/python/cpython/commit/b44beac5e101bb68898aa1bf4ccfc37f6f168050 commit: b44beac5e101bb68898aa1bf4ccfc37f6f168050 branch: 3.12 author: Petr Viktorin <encukou at gmail.com> committer: Yhg1s <thomas at python.org> date: 2023-05-23T10:56:14+02:00 summary: [3.12] gh-87891: Add ABI check to CI (#104793) Backport the workflow change and fix-ups: - GH-92442 (e89c01eac7731d7cb54d43252dbc3d3f3a040c53) - GH-94129 (0dadb2249a8bafa7c5877daa08c9452f2248958a) - GH-98556 (194588decc05fa12f04cd90c3b78cc081151b19e) Co-Authored-By: sterliakov <50529348+sterliakov at users.noreply.github.com> Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> Co-authored-by: Pablo Galindo Salgado <Pablogsal at gmail.com> files: A Doc/data/python3.12.abi M .github/workflows/build.yml M .gitignore diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9797192dba0..68bebb6bf61d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,6 +75,36 @@ jobs: echo "run_hypothesis=true" >> $GITHUB_OUTPUT fi + check_abi: + name: 'Check if the ABI has changed' + runs-on: ubuntu-22.04 + needs: check_source + if: needs.check_source.outputs.run_tests == 'true' + steps: + - uses: actions/checkout at v3 + - uses: actions/setup-python at v4 + - name: Install dependencies + run: | + sudo ./.github/workflows/posix-deps-apt.sh + sudo apt-get install -yq abigail-tools + - name: Build CPython + env: + CFLAGS: -g3 -O0 + run: | + # Build Python with the libpython dynamic library + ./configure --enable-shared + make -j4 + - name: Check for changes in the ABI + run: | + if ! make check-abidump; then + echo "Generated ABI file is not up to date." + echo "Please add the release manager of this branch as a reviewer of this PR." + echo "" + echo "To learn more about this check: https://devguide.python.org/setup/#regenerate-the-abi-dump" + echo "" + exit 1 + fi + check_generated_files: name: 'Check if generated files are up to date' runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index ef7642b09bc5..bde596a7a029 100644 --- a/.gitignore +++ b/.gitignore @@ -156,6 +156,3 @@ Python/frozen_modules/MANIFEST # Ignore ./python binary on Unix but still look into ./Python/ directory. /python !/Python/ - -# main branch only: ABI files are not checked/maintained -Doc/data/python*.abi diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi new file mode 100644 index 000000000000..79bf7ea6df82 --- /dev/null +++ b/Doc/data/python3.12.abi @@ -0,0 +1,26411 @@ +<abi-corpus version='2.0' path='libpython3.12.so' soname='libpython3.12.so.1.0'> + <elf-needed> + <dependency name='libm.so.6'/> + <dependency name='libc.so.6'/> + <dependency name='ld-linux-x86-64.so.2'/> + </elf-needed> + <elf-function-symbols> + <elf-symbol name='PyAIter_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_Parse' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_ParseTuple' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_ParseTupleAndKeywords' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_UnpackTuple' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_VaParse' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_VaParseTupleAndKeywords' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyArg_ValidateKeywordArguments' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyAsyncGen_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBool_FromLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_FillContiguousStrides' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_FillInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_FromContiguous' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_GetPointer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_IsContiguous' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_Release' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_SizeFromFormat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBuffer_ToContiguous' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_AsString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_Concat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_FromObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_FromStringAndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_Resize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_AsString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_AsStringAndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_Concat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_ConcatAndDel' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_DecodeEscape' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_FromFormat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_FromFormatV' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_FromObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_FromString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_FromStringAndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_Repr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_Call' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_GetFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_GetFunction' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_GetSelf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_NewEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCMethod_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCallIter_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCallable_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_GetContext' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_GetDestructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_GetName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_GetPointer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_Import' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_IsValid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_SetContext' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_SetDestructor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_SetName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_SetPointer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCell_Get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCell_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCell_Set' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyClassMethod_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_AddWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_Addr2Line' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_Addr2Location' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_ClearWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_GetCellvars' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_GetCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_GetFreevars' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_GetVarnames' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_NewEmpty' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_Optimize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_BackslashReplaceErrors' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_Decode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_Decoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_Encode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_Encoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_IgnoreErrors' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_IncrementalDecoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_IncrementalEncoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_KnownEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_LookupError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_NameReplaceErrors' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_Register' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_RegisterError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_ReplaceErrors' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_StreamReader' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_StreamWriter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_StrictErrors' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_Unregister' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCodec_XMLCharRefReplaceErrors' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCompile_OpcodeStackEffect' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCompile_OpcodeStackEffectWithJump' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyComplex_AsCComplex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyComplex_FromCComplex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyComplex_FromDoubles' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyComplex_ImagAsDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyComplex_RealAsDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_InitIsolatedConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_InitPythonConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_Read' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_SetArgv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_SetBytesArgv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_SetBytesString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_SetString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyConfig_SetWideStringList' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContextVar_Get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContextVar_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContextVar_Reset' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContextVar_Set' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContext_Copy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContext_CopyCurrent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContext_Enter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContext_Exit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContext_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCoro_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDescr_IsData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDescr_NewClassMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDescr_NewGetSet' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDescr_NewMember' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDescr_NewMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDescr_NewWrapper' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictProxy_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_AddWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_ClearWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Contains' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Copy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_DelItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_DelItemString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_GetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_GetItemString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_GetItemWithError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Items' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Keys' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Merge' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_MergeFromSeq2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Next' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_SetDefault' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_SetItemString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Unwatch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Update' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Values' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Watch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_BadArgument' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_BadInternalCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_CheckSignals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Display' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_DisplayException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_ExceptionMatches' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Fetch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Format' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_FormatV' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_GetExcInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_GetHandledException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_GetRaisedException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_GivenExceptionMatches' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_NewException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_NewExceptionWithDoc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_NoMemory' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_NormalizeException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Occurred' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Print' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_PrintEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_ProgramText' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_ProgramTextObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_RangedSyntaxLocationObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_ResourceWarning' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_Restore' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetExcInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetFromErrno' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetFromErrnoWithFilename' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetFromErrnoWithFilenameObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetFromErrnoWithFilenameObjects' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetHandledException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetImportError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetImportErrorSubclass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetInterrupt' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetInterruptEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetNone' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetRaisedException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SetString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SyntaxLocation' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SyntaxLocationEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_SyntaxLocationObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_WarnEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_WarnExplicit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_WarnExplicitFormat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_WarnExplicitObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_WarnFormat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyErr_WriteUnraisable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_AcquireLock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_AcquireThread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_CallFunction' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_CallMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_CallObjectWithKeywords' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_EvalCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_EvalCodeEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_EvalFrame' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_EvalFrameEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_GetBuiltins' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_GetFrame' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_GetFuncDesc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_GetFuncName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_GetGlobals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_GetLocals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_InitThreads' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_MergeCompilerFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_ReleaseLock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_ReleaseThread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_RestoreThread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_SaveThread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_SetProfile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_SetProfileAllThreads' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_SetTrace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_SetTraceAllThreads' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEval_ThreadsInitialized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExceptionClass_Name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_GetArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_GetCause' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_GetContext' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_GetTraceback' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_SetArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_SetCause' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_SetContext' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyException_SetTraceback' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_FromFd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_GetLine' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_NewStdPrinter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_OpenCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_OpenCodeObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_SetOpenCodeHook' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_WriteObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFile_WriteString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_AsDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_FromDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_FromString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_GetInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_GetMax' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_GetMin' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Pack2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Pack4' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Pack8' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Unpack2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Unpack4' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Unpack8' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_FastToLocals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_FastToLocalsWithError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetBack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetBuiltins' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetGenerator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetGlobals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetLasti' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetLineNumber' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetLocals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetVar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_GetVarString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_LocalsToFast' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrozenSet_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_AddWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_ClearWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetAnnotations' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetClosure' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetDefaults' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetGlobals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetKwDefaults' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_GetModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_NewWithQualName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_SetAnnotations' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_SetClosure' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_SetDefaults' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_SetKwDefaults' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_SetVectorcall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGC_Collect' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGC_Disable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGC_Enable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGC_IsEnabled' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGILState_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGILState_Ensure' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGILState_GetThisThreadState' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGILState_Release' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGen_GetCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGen_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGen_NewWithQualName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyHash_GetFuncDef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_AddModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_AddModuleObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_AppendInittab' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ExecCodeModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ExecCodeModuleEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ExecCodeModuleObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ExecCodeModuleWithPathnames' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ExtendInittab' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_GetImporter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_GetMagicNumber' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_GetMagicTag' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_GetModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_GetModuleDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_Import' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ImportFrozenModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ImportFrozenModuleObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ImportModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ImportModuleLevel' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ImportModuleLevelObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ImportModuleNoBlock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_ReloadModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyIndex_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__abc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__ast' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__codecs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__collections' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__functools' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__imp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__io' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__locale' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__operator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__signal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__sre' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__stat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__string' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__symtable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__thread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__tokenize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__tracemalloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__typing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit__weakref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_atexit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_errno' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_faulthandler' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_gc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_itertools' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_posix' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_pwd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInit_time' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInstanceMethod_Function' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInstanceMethod_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_Delete' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_Get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_GetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_GetID' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_Head' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_Main' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_Next' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInterpreterState_ThreadHead' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyIter_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyIter_Next' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyIter_Send' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_Append' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_AsTuple' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_GetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_GetSlice' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_Insert' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_Reverse' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_SetSlice' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_Sort' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsLongAndOverflow' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsLongLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsLongLongAndOverflow' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsSize_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsSsize_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsUnsignedLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsUnsignedLongLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsUnsignedLongLongMask' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsUnsignedLongMask' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_AsVoidPtr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromLongLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromSize_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromSsize_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromUnicodeObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromUnsignedLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromUnsignedLongLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_FromVoidPtr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_GetInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_GetItemString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_HasKey' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_HasKeyString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_Items' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_Keys' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_Length' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_SetItemString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMapping_Values' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_ReadLastObjectFromFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_ReadLongFromFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_ReadObjectFromFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_ReadObjectFromString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_ReadShortFromFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_WriteLongToFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_WriteObjectToFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMarshal_WriteObjectToString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_Calloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_Free' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_GetAllocator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_Malloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_RawCalloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_RawFree' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_RawMalloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_RawRealloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_Realloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_SetAllocator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMem_SetupDebugHooks' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMember_GetOne' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMember_SetOne' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMemoryView_FromBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMemoryView_FromMemory' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMemoryView_FromObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMemoryView_GetContiguous' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMethod_Function' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMethod_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMethod_Self' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModuleDef_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_AddFunctions' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_AddIntConstant' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_AddObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_AddObjectRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_AddStringConstant' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_AddType' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_Create2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_ExecDef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_FromDefAndSpec2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetDef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetFilename' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetFilenameObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetNameObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_GetState' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_NewObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_SetDocString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Absolute' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Add' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_And' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_AsSsize_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Divmod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Float' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_FloorDivide' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceAdd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceAnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceFloorDivide' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceLshift' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceMatrixMultiply' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceMultiply' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceOr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlacePower' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceRemainder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceRshift' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceSubtract' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceTrueDivide' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_InPlaceXor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Index' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Invert' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Long' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Lshift' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_MatrixMultiply' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Multiply' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Negative' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Or' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Positive' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Power' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Remainder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Rshift' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Subtract' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_ToBase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_TrueDivide' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyNumber_Xor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODict_DelItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODict_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODict_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_AfterFork' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_AfterFork_Child' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_AfterFork_Parent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_BeforeFork' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_FSPath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_InterruptOccurred' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_Readline' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_double_to_string' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_getsig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_mystricmp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_mystrnicmp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_setsig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_snprintf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_string_to_double' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_strtol' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_strtoul' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_vsnprintf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_ASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_AsCharBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_AsFileDescriptor' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_AsReadBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_AsWriteBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Bytes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Call' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallFinalizer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallFinalizerFromDealloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallFunction' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallFunctionObjArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallMethodObjArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallNoArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CallOneArg' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Calloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CheckBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CheckReadBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_ClearWeakRefs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_CopyData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_DelItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_DelItemString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Dir' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Format' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Free' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GC_Del' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GC_IsFinalized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GC_IsTracked' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GC_Track' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GC_UnTrack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GET_WEAKREFS_LISTPTR' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GenericGetAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GenericGetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GenericSetAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GenericSetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetAIter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetArenaAllocator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetAttrString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetItemData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetIter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_GetTypeData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_HasAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_HasAttrString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Hash' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_HashNotImplemented' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_IS_GC' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_InitVar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_IsInstance' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_IsSubclass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_IsTrue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Length' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_LengthHint' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Malloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Not' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Print' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Realloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Repr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_RichCompare' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_RichCompareBool' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_SelfIter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_SetArenaAllocator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_SetAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_SetAttrString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Str' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Type' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_Vectorcall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_VectorcallDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyObject_VectorcallMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyPickleBuffer_FromObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyPickleBuffer_GetBuffer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyPickleBuffer_Release' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyPreConfig_InitIsolatedConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyPreConfig_InitPythonConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_AnyFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_AnyFileEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_AnyFileExFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_AnyFileFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_File' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_FileEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_FileExFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_FileFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_InteractiveLoop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_InteractiveLoopFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_InteractiveOne' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_InteractiveOneFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_InteractiveOneObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_SimpleFile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_SimpleFileEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_SimpleFileExFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_SimpleString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_SimpleStringFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRun_StringFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySeqIter_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Check' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Concat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Contains' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Count' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_DelItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_DelSlice' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Fast' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_GetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_GetSlice' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_In' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_InPlaceConcat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_InPlaceRepeat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Index' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Length' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_List' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Repeat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_SetSlice' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySequence_Tuple' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Add' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Contains' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Discard' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Pop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySlice_AdjustIndices' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySlice_GetIndices' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySlice_GetIndicesEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySlice_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySlice_Unpack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyState_AddModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyState_FindModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyState_RemoveModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStaticMethod_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_Error' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_Exception' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_Exit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_IsError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_IsExit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_NoMemory' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStatus_Ok' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_GetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_InitType' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_InitType2' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_NewType' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySymtable_Lookup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_AddAuditHook' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_AddWarnOption' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_AddWarnOptionUnicode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_AddXOption' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_Audit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_FormatStderr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_FormatStdout' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_GetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_GetXOptions' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_HasWarnOptions' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_ResetWarnOptions' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_SetArgv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_SetArgvEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_SetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_SetPath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_WriteStderr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySys_WriteStdout' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_Delete' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_DeleteCurrent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_EnterTracing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_Get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_GetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_GetFrame' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_GetID' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_GetInterpreter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_LeaveTracing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_Next' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_SetAsyncExc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThreadState_Swap' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_GetInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_ReInitTLS' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_acquire_lock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_acquire_lock_timed' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_allocate_lock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_create_key' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_delete_key' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_delete_key_value' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_exit_thread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_free_lock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_get_key_value' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_get_stacksize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_get_thread_ident' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_get_thread_native_id' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_init_thread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_release_lock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_set_key_value' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_set_stacksize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_start_new_thread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_alloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_delete' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_free' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_is_created' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyThread_tss_set' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTraceBack_Here' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTraceBack_Print' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTraceMalloc_Track' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTraceMalloc_Untrack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_GetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_GetSlice' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_Pack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_SetItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_Size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_AddWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_ClearCache' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_ClearWatcher' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_FromMetaclass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_FromModuleAndSpec' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_FromSpec' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_FromSpecWithBases' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GenericAlloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GenericNew' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetModuleByDef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetModuleState' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetQualName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetSlot' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_GetTypeDataSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_IsSubtype' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_Modified' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_Ready' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_SUPPORTS_WEAKREFS' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_Unwatch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_Watch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_Create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_GetEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_GetEnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_GetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_GetReason' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_GetStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_SetEnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_SetReason' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeDecodeError_SetStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_GetEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_GetEnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_GetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_GetReason' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_GetStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_SetEnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_SetReason' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeEncodeError_SetStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_GetEnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_GetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_GetReason' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_GetStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_SetEnd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_SetReason' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeTranslateError_SetStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Append' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AppendAndDel' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsASCIIString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsCharmapString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsDecodedObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsDecodedUnicode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsEncodedObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsEncodedString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsEncodedUnicode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsLatin1String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsRawUnicodeEscapeString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUCS4' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUCS4Copy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUTF16String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUTF32String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUTF8' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUTF8AndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUTF8String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsUnicodeEscapeString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsWideChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_AsWideCharString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_BuildEncodingMap' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Compare' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_CompareWithASCIIString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Concat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Contains' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_CopyCharacters' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Count' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Decode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeCharmap' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeFSDefault' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeFSDefaultAndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeLatin1' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeLocale' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeLocaleAndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeRawUnicodeEscape' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF16' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF16Stateful' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF32' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF32Stateful' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF7' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF7Stateful' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF8' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUTF8Stateful' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_DecodeUnicodeEscape' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_EncodeFSDefault' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_EncodeLocale' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FSConverter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FSDecoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Fill' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Find' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FindChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Format' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromEncodedObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromFormat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromFormatV' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromKindAndData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromOrdinal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromStringAndSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_FromWideChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_GetDefaultEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_GetLength' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_GetSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_InternFromString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_InternImmortal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_InternInPlace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_IsIdentifier' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Join' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Partition' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_RPartition' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_RSplit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_ReadChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Replace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Resize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_RichCompare' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Split' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Splitlines' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Substring' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Tailmatch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Translate' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_WriteChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Code_GetExtra' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Code_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Code_NewWithPosOnlyArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Code_SetExtra' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Eval_RequestCodeExtraIndex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_GC_VisitObjects' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_InterpreterFrame_GetCode' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_InterpreterFrame_GetLasti' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_InterpreterFrame_GetLine' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Long_CompactValue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Long_IsCompact' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Object_GC_NewWithExtraData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_PerfMapState_Fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_PerfMapState_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_Type_AssignVersionTag' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnstable_WritePerfMapEntry' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyVectorcall_Call' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyVectorcall_Function' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyVectorcall_NARGS' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWeakref_GetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWeakref_NewProxy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWeakref_NewRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWideStringList_Append' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWideStringList_Insert' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWrapper_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_AddPendingCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_AtExit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_BuildValue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_BytesMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_CompileString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_CompileStringExFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_CompileStringFlags' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_CompileStringObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_DecRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_DecodeLocale' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_EncodeLocale' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_EndInterpreter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_EnterRecursiveCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_Exit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_ExitStatusException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FatalError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FdIsInteractive' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_Finalize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FinalizeEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FrozenMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GETENV' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GenericAlias' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetArgcArgv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetBuildInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetCompiler' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetCopyright' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetExecPrefix' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetPath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetPlatform' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetPrefix' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetProgramFullPath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetProgramName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetPythonHome' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetRecursionLimit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GetVersion' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IncRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_Initialize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_InitializeEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_InitializeFromConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_Is' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IsFalse' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IsInitialized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IsNone' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IsTrue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_LeaveRecursiveCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_Main' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_MakePendingCalls' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_NewInterpreter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_NewInterpreterFromConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_NewRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_PreInitialize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_PreInitializeFromArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_PreInitializeFromBytesArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_ReprEnter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_ReprLeave' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_RunMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_SetPath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_SetProgramName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_SetPythonHome' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_SetRecursionLimit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_SetStandardStreamEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_UniversalNewlineFgets' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_VaBuildValue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_XNewRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyAST_Compile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArena_AddPyObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArena_Free' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArena_Malloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArena_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_BadArgument' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_CheckPositional' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_NoKeywords' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_NoKwnames' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_NoPositional' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseStack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseStackAndKeywords' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseStackAndKeywords_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseStack_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseTupleAndKeywordsFast' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseTupleAndKeywordsFast_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseTupleAndKeywords_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_ParseTuple_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_Parse_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_UnpackKeywords' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_UnpackKeywordsWithVararg' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_UnpackStack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_VaParseTupleAndKeywordsFast' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_VaParseTupleAndKeywordsFast_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_VaParseTupleAndKeywords_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArg_VaParse_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyArgv_AsWstrList' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_Alloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_Dealloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_Finish' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_Prepare' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_Resize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytesWriter_WriteBytes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_DecodeEscape' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_Find' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_FormatEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_FromHex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_Join' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_Repeat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_Resize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBytes_ReverseFind' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCode_CheckLineNumber' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCode_ConstantKey' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCode_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCode_Validate' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCodecInfo_GetIncrementalDecoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCodecInfo_GetIncrementalEncoder' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCodec_DecodeText' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCodec_EncodeText' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCodec_Lookup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCodec_LookupTextEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCompile_Assemble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCompile_CodeGen' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCompile_OptimizeCfg' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyConfig_AsDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyConfig_FromDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyConfig_InitCompatConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyContext_NewHamtForTests' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_InitWithSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_Lookup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_NewObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_RegisterClass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_Release' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCrossInterpreterData_UnregisterClass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDeadline_Get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDeadline_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDebugAllocatorStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDictView_Intersect' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDictView_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_CheckConsistency' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_ContainsId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_Contains_KnownHash' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_DebugMallocStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_DelItemId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_DelItemIf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_DelItem_KnownHash' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_GetItemIdWithError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_GetItemStringWithError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_GetItemWithError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_GetItem_KnownHash' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_HasOnlyStringKeys' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_MaybeUntrack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_MergeEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_NewPresized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_Next' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_Pop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_SetItemId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_SetItem_KnownHash' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyDict_SizeOf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_BadInternalCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_ChainExceptions' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_ChainExceptions1' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_ChainStackItem' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_CheckSignals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_CheckSignalsTstate' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_Display' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_DisplayException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_ExceptionMatches' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_Fetch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_Format' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_FormatFromCause' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_FormatFromCauseTstate' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_GetExcInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_GetHandledException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_GetTopmostException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_NoMemory' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_NormalizeException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_Print' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_ProgramDecodedTextObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_Restore' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_SetFromPyStatus' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_SetHandledException' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_SetKeyError' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_SetNone' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_SetObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_SetString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_StackItemToExcInfoTuple' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyErr_WriteUnraisableMsg' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_AddPendingCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_EvalFrameDefault' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_GetBuiltin' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_GetBuiltinId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_GetSwitchInterval' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SetProfile' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SetSwitchInterval' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SetTrace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SignalAsyncExc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SignalReceived' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SliceIndex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyEval_SliceIndexNotNone' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyExc_CreateExceptionGroup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyExc_PrepReraiseStar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyException_AddNote' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyFloat_DebugMallocStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyFloat_FormatAdvancedWriter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyFrame_IsEntryFrame' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyFunction_Vectorcall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyGILState_GetInterpreterStateUnsafe' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyGen_FetchStopIterationValue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyGen_Finalize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyGen_SetStopIterationValue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_AcquireLock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_CheckSubinterpIncompatibleExtensionAllowed' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_ClearExtension' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_FixupBuiltin' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_FixupExtensionObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_GetModuleAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_GetModuleAttrString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_GetModuleId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_IsInitialized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_ReleaseLock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_SetModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_SetModuleString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterID_LookUp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterID_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_Enable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_GetConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_GetConfigCopy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_GetEvalFrameFunc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_GetIDObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_GetMainModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_HasFeature' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_IDDecref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_IDIncref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_IDInitref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_LookUpID' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_RequireIDRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_RequiresIDRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_SetConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterState_SetEvalFrameFunc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyList_DebugMallocStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyList_Extend' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_AsByteArray' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_AsInt' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_AsTime_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Copy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_DivmodNear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FileDescriptor_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Format' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FormatAdvancedWriter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FormatBytesWriter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FormatWriter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Frexp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FromByteArray' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FromBytes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FromDigits' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FromGid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FromTime_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_FromUid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_GCD' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Lshift' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_NumBits' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Rshift' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Sign' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_Size_t_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_UnsignedInt_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_UnsignedLongLong_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_UnsignedLong_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_UnsignedShort_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_GetAllocatorName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_GetCurrentAllocatorName' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_RawStrdup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_RawWcsdup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_SetDefaultAllocator' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_SetupAllocators' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMem_Strdup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyModuleSpec_IsInitializing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyModule_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyModule_ClearDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyModule_CreateInitialized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyNamespace_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyNumber_Index' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyOS_InterruptOccurred' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyOS_IsMainThread' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyOS_URandom' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyOS_URandomNonblock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_AssertFailed' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_Call' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CallFunction_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CallMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CallMethodId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CallMethodIdObjArgs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CallMethodId_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CallMethod_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_Call_Prepend' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CheckConsistency' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_CheckCrossInterpreterData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_ClearManagedDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_DebugMallocStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_DebugTypeStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_Dump' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_FastCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_FastCallDictTstate' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_FunctionStr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GC_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GC_NewVar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GC_Resize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GenericGetAttrWithDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GenericSetAttrWithDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GetAttrId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GetCrossInterpreterData' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GetDictPtr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GetMethod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_GetState' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_HasLen' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_IsAbstract' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_IsFreed' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_LookupAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_LookupAttrId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_LookupSpecial' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_LookupSpecialId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_MakeTpCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_NewVar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_NextNotImplemented' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_RealIsInstance' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_RealIsSubclass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_SetAttrId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyObject_VisitManagedDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyPathConfig_ClearGlobal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyPreConfig_InitCompatConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRun_AnyFileObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRun_InteractiveLoopObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRun_SimpleFileObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRuntimeState_Fini' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRuntimeState_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRuntime_Finalize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRuntime_Initialize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySequence_BytesToCharpArray' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySequence_IterSearch' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySet_NextEntry' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySet_Update' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySlice_FromIndices' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySlice_GetLongIndices' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyStack_AsDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyState_AddModule' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyStructSequence_NewType' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySys_GetAttr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySys_GetSizeOf' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_Bind' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_DeleteCurrent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_DeleteExcept' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_GetCurrent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_GetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_New' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_Prealloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_Swap' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThreadState_UncheckedGet' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThread_CurrentExceptions' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThread_CurrentFrames' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyThread_at_fork_reinit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_Add' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsMicroseconds' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsMilliseconds' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsNanoseconds' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsNanosecondsObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsSecondsDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsTimespec' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsTimespec_clamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsTimeval' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsTimevalTime_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_AsTimeval_clamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromMicrosecondsClamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromMillisecondsObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromNanoseconds' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromNanosecondsObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromSeconds' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromSecondsObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromTimespec' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_FromTimeval' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_GetMonotonicClock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_GetMonotonicClockWithInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_GetPerfCounter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_GetPerfCounterWithInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_GetSystemClock' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_GetSystemClockWithInfo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_MulDiv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_ObjectToTime_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_ObjectToTimespec' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_ObjectToTimeval' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_gmtime' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTime_localtime' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyToken_OneChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyToken_ThreeChars' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyToken_TwoChars' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceBack_FromFrame' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceBack_Print_Indented' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_ClearTraces' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_GetMemory' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_GetObjectTraceback' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_GetTraceback' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_GetTracebackLimit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_GetTracedMemory' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_GetTraces' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_IsTracing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_ResetPeak' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_Start' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceMalloc_Stop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTraceback_Add' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTrash_begin' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTrash_cond' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTrash_end' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTuple_DebugMallocStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTuple_MaybeUntrack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyTuple_Resize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_CalculateMetaclass' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_CheckConsistency' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_GetDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_GetDocFromInternalDoc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_GetTextSignatureFromInternalDoc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_Lookup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_LookupId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyType_Name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeTranslateError_Create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_Dealloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_Finish' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_PrepareInternal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_PrepareKindInternal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_WriteASCIIString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_WriteChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_WriteLatin1String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_WriteStr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicodeWriter_WriteSubstring' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_AsASCIIString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_AsLatin1String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_AsUTF8String' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_CheckConsistency' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_Copy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_DecodeRawUnicodeEscapeStateful' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_DecodeUnicodeEscapeInternal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_DecodeUnicodeEscapeStateful' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EQ' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EncodeCharmap' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EncodeUTF16' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EncodeUTF32' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EncodeUTF7' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_Equal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EqualToASCIIId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_EqualToASCIIString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FastCopyCharacters' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FastFill' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FindMaxChar' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FormatAdvancedWriter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FormatLong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FromASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_FromId' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_InsertThousandsGrouping' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsAlpha' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsCaseIgnorable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsCased' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsDecimalDigit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsDigit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsLinebreak' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsLowercase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsNumeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsPrintable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsTitlecase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsUppercase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsWhitespace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsXidContinue' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_IsXidStart' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_JoinArray' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ScanIdentifier' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToDecimalDigit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToDigit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToFoldedFull' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToLowerFull' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToLowercase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToNumeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToTitleFull' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToTitlecase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToUpperFull' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_ToUppercase' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_TransformDecimalAndSpaceToASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_WideCharString_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_WideCharString_Opt_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyUnicode_XStrip' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWarnings_Init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWeakref_ClearRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWeakref_GetWeakrefCount' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWideStringList_AsList' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWideStringList_Clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWideStringList_Copy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWideStringList_Extend' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_AtExit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_BreakPoint' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_BuildValue_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_CheckFunctionResult' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_CheckRecursiveCall' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ClearArgcArgv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ClearStandardStreamEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_CoerceLegacyLocale' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_Dealloc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DecRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DecodeLocaleEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DecodeUTF8Ex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DecodeUTF8_surrogateescape' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DisplaySourceLine' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DumpASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DumpDecimal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DumpExtensionModules' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DumpHexadecimal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DumpTraceback' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_DumpTracebackThreads' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_EncodeLocaleEx' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_EncodeLocaleRaw' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_EncodeUTF8Ex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_FatalErrorFormat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_FatalErrorFunc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_FatalRefcountErrorFunc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_FdIsInteractive' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_FreeCharPArray' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetConfigsAsDict' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetEnv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetErrorHandler' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetForceASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetLocaleEncoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetLocaleEncodingObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_GetLocaleconvNumeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_Get_Getpath_CodeObject' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_Gid_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HandleSystemExit' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HashBytes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HashDouble' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HashPointer' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HashPointerRaw' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_IncRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_InitializeMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_IsCoreInitialized' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_IsFinalizing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_IsInterpreterFinalizing' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_IsLocaleCoercionTarget' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_LegacyLocaleDetected' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_NewReference' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_NewReferenceNoTotal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_PreInitializeFromConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_PreInitializeFromPyArgv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ResetForceASCII' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_RestoreSignals' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_SetLocaleFromEnv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_SetProgramFullPath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_Sigset_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_SourceAsString' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_UTF8_Edit_Cost' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_Uid_Converter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_UniversalNewlineFgetsWithSize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_VaBuildStack' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_VaBuildStack_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_VaBuildValue_SizeT' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_WriteIndent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_WriteIndentedMargin' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_add_one_to_index_C' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_add_one_to_index_F' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_abs' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_diff' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_neg' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_pow' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_prod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_quot' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_c_sum' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_closerange' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_convert_optional_to_ssize_t' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_device_encoding' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_dg_dtoa' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_dg_freedtoa' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_dg_strtod' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_dup' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_fopen_obj' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_fstat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_fstat_noraise' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_get_blocking' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_get_env_flag' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_get_inheritable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_get_xoption' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_gitidentifier' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_gitversion' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_clear' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_compare_direct' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_destroy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_foreach' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_get' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_hash_ptr' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_new' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_new_full' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_set' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_size' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_hashtable_steal' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_normpath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_open' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_open_noraise' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_parse_inf_or_nan' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_read' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_set_blocking' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_set_inheritable' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_set_inheritable_async_safe' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_stat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_str_to_int' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_strhex' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_strhex_bytes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_strhex_bytes_with_sep' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_strhex_with_sep' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_string_to_number_with_underscores' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_wfopen' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_wgetcwd' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_wreadlink' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_wrealpath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_write' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_write_noraise' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + </elf-function-symbols> + <elf-variable-symbols> + <elf-symbol name='PyAsyncGen_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBaseObject_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBool_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArrayIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyByteArray_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytesIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyBytes_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCFunction_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCMethod_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCallIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCapsule_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCell_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyClassMethodDescr_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyClassMethod_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCode_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyComplex_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContextToken_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContextVar_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyContext_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyCoro_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictItems_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictIterItem_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictIterKey_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictIterValue_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictKeys_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictProxy_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictRevIterItem_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictRevIterKey_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictRevIterValue_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDictValues_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyDict_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEllipsis_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyEnum_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ArithmeticError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_AssertionError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_AttributeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_BaseException' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_BaseExceptionGroup' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_BlockingIOError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_BrokenPipeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_BufferError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_BytesWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ChildProcessError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ConnectionAbortedError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ConnectionError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ConnectionRefusedError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ConnectionResetError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_DeprecationWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_EOFError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_EncodingWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_EnvironmentError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_Exception' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_FileExistsError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_FileNotFoundError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_FloatingPointError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_FutureWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_GeneratorExit' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_IOError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ImportError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ImportWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_IndentationError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_IndexError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_InterruptedError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_IsADirectoryError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_KeyError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_KeyboardInterrupt' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_LookupError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_MemoryError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ModuleNotFoundError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_NameError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_NotADirectoryError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_NotImplementedError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_OSError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_OverflowError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_PendingDeprecationWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_PermissionError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ProcessLookupError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_RecursionError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ReferenceError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ResourceWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_RuntimeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_RuntimeWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_StopAsyncIteration' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_StopIteration' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_SyntaxError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_SyntaxWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_SystemError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_SystemExit' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_TabError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_TimeoutError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_TypeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UnboundLocalError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UnicodeDecodeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UnicodeEncodeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UnicodeError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UnicodeTranslateError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UnicodeWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_UserWarning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ValueError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_Warning' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyExc_ZeroDivisionError' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFilter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFloat_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrame_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFrozenSet_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyFunction_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGen_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyGetSetDescr_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_FrozenModules' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyImport_Inittab' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyInstanceMethod_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyListIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyListRevIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyList_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLongRangeIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyLong_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMap_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMemberDescr_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMemoryView_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMethodDescr_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyMethod_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModuleDef_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyModule_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODictItems_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODictIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODictKeys_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODictValues_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyODict_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_InputHook' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyOS_ReadlineFunctionPointer' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyPickleBuffer_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyProperty_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRangeIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyRange_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyReversed_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySeqIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySetIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySet_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySlice_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStaticMethod_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStdPrinter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyStructSequence_UnnamedField' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PySuper_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTraceBack_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTupleIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyTuple_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyType_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicodeIter_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyUnicode_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyWrapperDescr_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='PyZip_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_BytesWarningFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_DebugFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_DontWriteBytecodeFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FileSystemDefaultEncodeErrors' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FileSystemDefaultEncoding' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_FrozenFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_GenericAliasType' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_HasFileSystemDefaultEncoding' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_HashRandomizationFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IgnoreEnvironmentFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_InspectFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_InteractiveFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_IsolatedFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_NoSiteFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_NoUserSiteDirectory' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_OptimizeFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_QuietFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_UTF8Mode' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_UnbufferedStdioFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_VerboseFlag' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_Version' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='Py_hexdigits' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyAsyncGenASend_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyAsyncGenAThrow_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyAsyncGenWrappedValue_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyBufferWrapper_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyByteArray_empty_string' size='1' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyCoroWrapper_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_FrozenBootstrap' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_FrozenStdlib' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyImport_FrozenTest' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyInterpreterID_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyLong_DigitValue' size='256' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyManagedBuffer_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyMethodWrapper_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyNamespace_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyNone_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyNotImplemented_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyOS_ReadlineTState' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyParser_TokenNames' size='552' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyRuntime' size='462560' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PySet_Dummy' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWeakref_CallableProxyType' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWeakref_ProxyType' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_PyWeakref_RefType' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_EllipsisObject' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_FalseStruct' size='32' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HasFileSystemDefaultEncodeErrors' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_HashSecret' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_NoneStruct' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_NotImplementedStruct' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_SwappedOp' size='24' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_TrueStruct' size='32' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ascii_whitespace' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ctype_table' size='1024' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ctype_tolower' size='256' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + <elf-symbol name='_Py_ctype_toupper' size='256' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/> + </elf-variable-symbols> + <abi-instr address-size='64' path='./Modules/_abc.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyType_GetMRO' filepath='./Include/internal/pycore_typeobject.h' line='121' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyType_GetSubclasses' filepath='./Include/internal/pycore_typeobject.h' line='122' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/_iomodule.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyIO_Module' type-id='type-id-3' visibility='default' filepath='./Modules/_io/_iomodule.h' line='143' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/bufferedio.c' comp-dir-path='/src' language='LANG_C11'> + <typedef-decl name='_PyIO_State' type-id='type-id-4' filepath='./Modules/_io/_iomodule.h' line='35' column='1' id='type-id-5'/> + <typedef-decl name='Py_off_t' type-id='type-id-6' filepath='./Modules/_io/_iomodule.h' line='109' column='1' id='type-id-7'/> + <class-decl name='_io_state' size-in-bits='1024' is-struct='yes' visibility='default' filepath='./Modules/_io/_iomodule.h' line='145' column='1' id='type-id-4'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='initialized' type-id='type-id-8' visibility='default' filepath='./Modules/_io/_iomodule.h' line='146' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='unsupported_operation' type-id='type-id-2' visibility='default' filepath='./Modules/_io/_iomodule.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='PyIOBase_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='PyIncrementalNewlineDecoder_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='151' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='PyRawIOBase_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='152' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='PyBufferedIOBase_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='PyBufferedRWPair_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='PyBufferedRandom_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='155' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='PyBufferedReader_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='PyBufferedWriter_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='PyBytesIOBuffer_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='158' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='PyBytesIO_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='PyFileIO_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='PyStringIO_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='PyTextIOBase_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='PyTextIOWrapper_Type' type-id='type-id-1' visibility='default' filepath='./Modules/_io/_iomodule.h' line='163' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='off_t' type-id='type-id-9' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='87' column='1' id='type-id-6'/> + <pointer-type-def type-id='type-id-5' size-in-bits='64' id='type-id-10'/> + <var-decl name='bufferediobase_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='12' column='1'/> + <var-decl name='bufferedrandom_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='13' column='1'/> + <var-decl name='bufferedreader_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='14' column='1'/> + <var-decl name='bufferedrwpair_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='15' column='1'/> + <var-decl name='bufferedwriter_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='16' column='1'/> + <function-decl name='_PyIOBase_check_readable' filepath='./Modules/_io/_iomodule.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-10'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyIOBase_check_writable' filepath='./Modules/_io/_iomodule.h' line='38' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-10'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyIOBase_check_seekable' filepath='./Modules/_io/_iomodule.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-10'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyFileIO_closed' filepath='./Modules/_io/_iomodule.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyNumber_AsOff_t' filepath='./Modules/_io/_iomodule.h' line='137' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-7'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/bytesio.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='bytesio_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='17' column='1'/> + <var-decl name='bytesiobuf_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='18' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/fileio.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='fileio_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='19' column='1'/> + <function-decl name='_PyIOBase_finalize' filepath='./Modules/_io/_iomodule.h' line='48' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyIOBase_cannot_pickle' filepath='./Modules/_io/_iomodule.h' line='193' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/iobase.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='iobase_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='20' column='1'/> + <var-decl name='rawiobase_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='22' column='1'/> + <function-decl name='_PyIO_trap_eintr' filepath='./Modules/_io/_iomodule.h' line='79' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/stringio.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='stringio_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='23' column='1'/> + <function-decl name='_PyIncrementalNewlineDecoder_decode' filepath='./Modules/_io/_iomodule.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyIO_find_line_ending' filepath='./Modules/_io/_iomodule.h' line='71' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-14'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_io/textio.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='nldecoder_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='21' column='1'/> + <var-decl name='textiobase_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='24' column='1'/> + <var-decl name='textiowrapper_spec' type-id='type-id-11' visibility='default' filepath='./Modules/_io/_iomodule.h' line='25' column='1'/> + <function-decl name='_PyIOBase_check_closed' filepath='./Modules/_io/_iomodule.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_localemodule.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='gettext' filepath='/usr/include/libintl.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='dgettext' filepath='/usr/include/libintl.h' line='44' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='dcgettext' filepath='/usr/include/libintl.h' line='51' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='textdomain' filepath='/usr/include/libintl.h' line='82' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='bindtextdomain' filepath='/usr/include/libintl.h' line='86' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='bind_textdomain_codeset' filepath='/usr/include/libintl.h' line='91' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='wcscoll' filepath='/usr/include/wchar.h' line='131' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-16'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='wcsxfrm' filepath='/usr/include/wchar.h' line='135' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-18'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-19'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/_sre/sre.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='toupper' filepath='/usr/include/ctype.h' line='125' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/atexitmodule.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_AtExit' mangled-name='_Py_AtExit' filepath='./Modules/atexitmodule.c' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_AtExit'> + <parameter type-id='type-id-20' name='interp' filepath='./Modules/atexitmodule.c' line='27' column='1'/> + <parameter type-id='type-id-21' name='func' filepath='./Modules/atexitmodule.c' line='28' column='1'/> + <parameter type-id='type-id-22' name='data' filepath='./Modules/atexitmodule.c' line='28' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/faulthandler.c' comp-dir-path='/src' language='LANG_C11'> + <enum-decl name='__rlimit_resource' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='31' column='1' id='type-id-23'> + <underlying-type type-id='type-id-24'/> + <enumerator name='RLIMIT_CPU' value='0'/> + <enumerator name='RLIMIT_FSIZE' value='1'/> + <enumerator name='RLIMIT_DATA' value='2'/> + <enumerator name='RLIMIT_STACK' value='3'/> + <enumerator name='RLIMIT_CORE' value='4'/> + <enumerator name='__RLIMIT_RSS' value='5'/> + <enumerator name='RLIMIT_NOFILE' value='7'/> + <enumerator name='__RLIMIT_OFILE' value='7'/> + <enumerator name='RLIMIT_AS' value='9'/> + <enumerator name='__RLIMIT_NPROC' value='6'/> + <enumerator name='__RLIMIT_MEMLOCK' value='8'/> + <enumerator name='__RLIMIT_LOCKS' value='10'/> + <enumerator name='__RLIMIT_SIGPENDING' value='11'/> + <enumerator name='__RLIMIT_MSGQUEUE' value='12'/> + <enumerator name='__RLIMIT_NICE' value='13'/> + <enumerator name='__RLIMIT_RTPRIO' value='14'/> + <enumerator name='__RLIMIT_RTTIME' value='15'/> + <enumerator name='__RLIMIT_NLIMITS' value='16'/> + <enumerator name='__RLIM_NLIMITS' value='16'/> + </enum-decl> + <typedef-decl name='rlim_t' type-id='type-id-25' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='133' column='1' id='type-id-26'/> + <class-decl name='rlimit' size-in-bits='128' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='139' column='1' id='type-id-27'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='rlim_cur' type-id='type-id-26' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='142' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='rlim_max' type-id='type-id-26' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='144' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__rlim64_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='158' column='1' id='type-id-25'/> + <typedef-decl name='__rlimit_resource_t' type-id='type-id-23' filepath='/usr/include/x86_64-linux-gnu/sys/resource.h' line='38' column='1' id='type-id-29'/> + <pointer-type-def type-id='type-id-30' size-in-bits='64' id='type-id-31'/> + <qualified-type-def type-id='type-id-31' restrict='yes' id='type-id-32'/> + <qualified-type-def type-id='type-id-30' const='yes' id='type-id-33'/> + <pointer-type-def type-id='type-id-33' size-in-bits='64' id='type-id-34'/> + <qualified-type-def type-id='type-id-34' restrict='yes' id='type-id-35'/> + <qualified-type-def type-id='type-id-27' const='yes' id='type-id-36'/> + <pointer-type-def type-id='type-id-36' size-in-bits='64' id='type-id-37'/> + <qualified-type-def type-id='type-id-38' const='yes' id='type-id-39'/> + <pointer-type-def type-id='type-id-39' size-in-bits='64' id='type-id-40'/> + <qualified-type-def type-id='type-id-40' restrict='yes' id='type-id-41'/> + <pointer-type-def type-id='type-id-27' size-in-bits='64' id='type-id-42'/> + <pointer-type-def type-id='type-id-38' size-in-bits='64' id='type-id-43'/> + <qualified-type-def type-id='type-id-43' restrict='yes' id='type-id-44'/> + <function-decl name='raise' filepath='/usr/include/signal.h' line='123' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigfillset' filepath='/usr/include/signal.h' line='202' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-45'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigaltstack' filepath='/usr/include/signal.h' line='333' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-41'/> + <parameter type-id='type-id-44'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_exit' filepath='/usr/include/unistd.h' line='624' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='sysconf' filepath='/usr/include/unistd.h' line='640' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='pthread_sigmask' filepath='/usr/include/x86_64-linux-gnu/bits/sigthread.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-35'/> + <parameter type-id='type-id-32'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getauxval' filepath='/usr/include/x86_64-linux-gnu/sys/auxv.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-28'/> + <return type-id='type-id-28'/> + </function-decl> + <type-decl name='unsigned long int' size-in-bits='64' id='type-id-28'/> + </abi-instr> + <abi-instr address-size='64' path='./Modules/getbuildinfo.c' comp-dir-path='/src' language='LANG_C11'> + <type-decl name='char' size-in-bits='8' id='type-id-48'/> + <type-decl name='int' size-in-bits='32' id='type-id-8'/> + <type-decl name='unsigned long int' size-in-bits='64' id='type-id-28'/> + <type-decl name='variadic parameter type' id='type-id-49'/> + <typedef-decl name='size_t' type-id='type-id-28' filepath='/usr/lib/gcc/x86_64-linux-gnu/11/include/stddef.h' line='209' column='1' id='type-id-19'/> + <pointer-type-def type-id='type-id-48' size-in-bits='64' id='type-id-15'/> + <qualified-type-def type-id='type-id-48' const='yes' id='type-id-50'/> + <pointer-type-def type-id='type-id-50' size-in-bits='64' id='type-id-12'/> + <function-decl name='PyOS_snprintf' mangled-name='PyOS_snprintf' filepath='./Include/pyerrors.h' line='323' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_snprintf'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_GetBuildInfo' mangled-name='Py_GetBuildInfo' filepath='./Modules/getbuildinfo.c' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetBuildInfo'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_Py_gitversion' mangled-name='_Py_gitversion' filepath='./Modules/getbuildinfo.c' line='59' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_gitversion'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_Py_gitidentifier' mangled-name='_Py_gitidentifier' filepath='./Modules/getbuildinfo.c' line='65' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_gitidentifier'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='strcmp' filepath='/usr/include/string.h' line='156' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/getpath.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_wstat' filepath='./Include/internal/pycore_fileutils.h' line='210' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-51'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_join_relfile' filepath='./Include/internal/pycore_fileutils.h' line='249' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-16'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_Py_add_relfile' filepath='./Include/internal/pycore_fileutils.h' line='251' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-52'/> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPathConfig_ReadGlobal' filepath='./Include/internal/pycore_pathconfig.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-53'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyPathConfig_GetGlobalModuleSearchPath' filepath='./Include/internal/pycore_pathconfig.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-16'/> + </function-decl> + <function-decl name='_Py_Get_Getpath_CodeObject' mangled-name='_Py_Get_Getpath_CodeObject' filepath='./Modules/getpath.c' line='790' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_Get_Getpath_CodeObject'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/posixmodule.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-55' size-in-bits='1024' id='type-id-56'> + <subrange length='16' type-id='type-id-28' id='type-id-57'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-58' size-in-bits='256' id='type-id-59'> + <subrange length='32' type-id='type-id-28' id='type-id-60'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='2048' id='type-id-61'> + <subrange length='256' type-id='type-id-28' id='type-id-62'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='520' id='type-id-63'> + <subrange length='65' type-id='type-id-28' id='type-id-64'/> + </array-type-def> + <class-decl name='__dirstream' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-65'/> + <class-decl name='__spawn_action' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-66'/> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='512' id='type-id-67'> + <subrange length='16' type-id='type-id-28' id='type-id-57'/> + </array-type-def> + <typedef-decl name='DIR' type-id='type-id-65' filepath='/usr/include/dirent.h' line='127' column='1' id='type-id-68'/> + <class-decl name='posix_spawnattr_t' size-in-bits='2688' is-struct='yes' naming-typedef-id='type-id-69' visibility='default' filepath='/usr/include/spawn.h' line='29' column='1' id='type-id-70'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__flags' type-id='type-id-71' visibility='default' filepath='/usr/include/spawn.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='__pgrp' type-id='type-id-72' visibility='default' filepath='/usr/include/spawn.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='__sd' type-id='type-id-73' visibility='default' filepath='/usr/include/spawn.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='__ss' type-id='type-id-73' visibility='default' filepath='/usr/include/spawn.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='__sp' type-id='type-id-74' visibility='default' filepath='/usr/include/spawn.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2144'> + <var-decl name='__policy' type-id='type-id-8' visibility='default' filepath='/usr/include/spawn.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2176'> + <var-decl name='__pad' type-id='type-id-67' visibility='default' filepath='/usr/include/spawn.h' line='37' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='posix_spawnattr_t' type-id='type-id-70' filepath='/usr/include/spawn.h' line='38' column='1' id='type-id-69'/> + <class-decl name='posix_spawn_file_actions_t' size-in-bits='640' is-struct='yes' naming-typedef-id='type-id-75' visibility='default' filepath='/usr/include/spawn.h' line='43' column='1' id='type-id-76'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__allocated' type-id='type-id-8' visibility='default' filepath='/usr/include/spawn.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='__used' type-id='type-id-8' visibility='default' filepath='/usr/include/spawn.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='__actions' type-id='type-id-77' visibility='default' filepath='/usr/include/spawn.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='__pad' type-id='type-id-67' visibility='default' filepath='/usr/include/spawn.h' line='48' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='posix_spawn_file_actions_t' type-id='type-id-76' filepath='/usr/include/spawn.h' line='49' column='1' id='type-id-75'/> + <typedef-decl name='__compar_fn_t' type-id='type-id-78' filepath='/usr/include/stdlib.h' line='816' column='1' id='type-id-79'/> + <typedef-decl name='__cpu_mask' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='32' column='1' id='type-id-55'/> + <class-decl name='cpu_set_t' size-in-bits='1024' is-struct='yes' naming-typedef-id='type-id-80' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='39' column='1' id='type-id-81'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__bits' type-id='type-id-56' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='41' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='cpu_set_t' type-id='type-id-81' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='42' column='1' id='type-id-80'/> + <class-decl name='dirent' size-in-bits='2240' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/dirent.h' line='22' column='1' id='type-id-82'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='d_ino' type-id='type-id-83' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/dirent.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='d_off' type-id='type-id-9' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/dirent.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='d_reclen' type-id='type-id-84' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/dirent.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='144'> + <var-decl name='d_type' type-id='type-id-85' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/dirent.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='152'> + <var-decl name='d_name' type-id='type-id-61' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/dirent.h' line='33' column='1'/> + </data-member> + </class-decl> + <class-decl name='winsize' size-in-bits='64' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/ioctl-types.h' line='27' column='1' id='type-id-86'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ws_row' type-id='type-id-84' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/ioctl-types.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='16'> + <var-decl name='ws_col' type-id='type-id-84' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/ioctl-types.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='ws_xpixel' type-id='type-id-84' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/ioctl-types.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='48'> + <var-decl name='ws_ypixel' type-id='type-id-84' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/ioctl-types.h' line='32' column='1'/> + </data-member> + </class-decl> + <enum-decl name='__priority_which' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='187' column='1' id='type-id-87'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PRIO_PROCESS' value='0'/> + <enumerator name='PRIO_PGRP' value='1'/> + <enumerator name='PRIO_USER' value='2'/> + </enum-decl> + <class-decl name='statvfs' size-in-bits='896' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='29' column='1' id='type-id-88'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='f_bsize' type-id='type-id-28' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='f_frsize' type-id='type-id-28' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='f_blocks' type-id='type-id-89' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='f_bfree' type-id='type-id-89' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='f_bavail' type-id='type-id-89' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='f_files' type-id='type-id-90' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='f_ffree' type-id='type-id-90' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='f_favail' type-id='type-id-90' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='f_fsid' type-id='type-id-28' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='f_flag' type-id='type-id-28' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='f_namemax' type-id='type-id-28' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='__f_spare' type-id='type-id-91' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/statvfs.h' line='54' column='1'/> + </data-member> + </class-decl> + <class-decl name='termios' size-in-bits='480' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='24' column='1' id='type-id-92'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='c_iflag' type-id='type-id-93' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='26' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='c_oflag' type-id='type-id-93' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='c_cflag' type-id='type-id-93' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='c_lflag' type-id='type-id-93' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='c_line' type-id='type-id-58' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='136'> + <var-decl name='c_cc' type-id='type-id-59' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='416'> + <var-decl name='c_ispeed' type-id='type-id-94' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='c_ospeed' type-id='type-id-94' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/termios-struct.h' line='33' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='cc_t' type-id='type-id-85' filepath='/usr/include/x86_64-linux-gnu/bits/termios.h' line='23' column='1' id='type-id-58'/> + <typedef-decl name='speed_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/termios.h' line='24' column='1' id='type-id-94'/> + <typedef-decl name='tcflag_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/termios.h' line='25' column='1' id='type-id-93'/> + <typedef-decl name='__id_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='159' column='1' id='type-id-96'/> + <typedef-decl name='__fsblkcnt64_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='185' column='1' id='type-id-89'/> + <typedef-decl name='__fsfilcnt64_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='189' column='1' id='type-id-90'/> + <typedef-decl name='clock_t' type-id='type-id-97' filepath='/usr/include/x86_64-linux-gnu/bits/types/clock_t.h' line='7' column='1' id='type-id-98'/> + <class-decl name='iovec' size-in-bits='128' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_iovec.h' line='26' column='1' id='type-id-99'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='iov_base' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_iovec.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='iov_len' type-id='type-id-19' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_iovec.h' line='29' column='1'/> + </data-member> + </class-decl> + <class-decl name='rusage' size-in-bits='1152' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='33' column='1' id='type-id-100'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ru_utime' type-id='type-id-101' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ru_stime' type-id='type-id-101' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='' type-id='type-id-102' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='' type-id='type-id-103' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='' type-id='type-id-104' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='' type-id='type-id-105' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='' type-id='type-id-106' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='' type-id='type-id-107' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='' type-id='type-id-108' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='' type-id='type-id-109' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='' type-id='type-id-110' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='' type-id='type-id-111' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='' type-id='type-id-112' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='' type-id='type-id-113' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='' type-id='type-id-114' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='' type-id='type-id-115' visibility='default'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='40' column='1' id='type-id-102'> + <data-member access='public'> + <var-decl name='ru_maxrss' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='42' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_maxrss_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='43' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__1' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='47' column='1' id='type-id-103'> + <data-member access='public'> + <var-decl name='ru_ixrss' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='49' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_ixrss_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='50' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__2' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='53' column='1' id='type-id-104'> + <data-member access='public'> + <var-decl name='ru_idrss' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='55' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_idrss_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='56' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__3' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='59' column='1' id='type-id-105'> + <data-member access='public'> + <var-decl name='ru_isrss' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='61' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_isrss_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='62' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__4' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='66' column='1' id='type-id-106'> + <data-member access='public'> + <var-decl name='ru_minflt' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='68' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_minflt_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='69' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__5' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='72' column='1' id='type-id-107'> + <data-member access='public'> + <var-decl name='ru_majflt' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='74' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_majflt_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='75' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__6' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='78' column='1' id='type-id-108'> + <data-member access='public'> + <var-decl name='ru_nswap' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='80' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_nswap_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='81' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__7' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='85' column='1' id='type-id-109'> + <data-member access='public'> + <var-decl name='ru_inblock' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='87' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_inblock_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='88' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__8' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='91' column='1' id='type-id-110'> + <data-member access='public'> + <var-decl name='ru_oublock' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='93' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_oublock_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='94' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__9' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='97' column='1' id='type-id-111'> + <data-member access='public'> + <var-decl name='ru_msgsnd' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='99' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_msgsnd_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='100' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__10' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='103' column='1' id='type-id-112'> + <data-member access='public'> + <var-decl name='ru_msgrcv' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='105' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_msgrcv_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='106' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__11' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='109' column='1' id='type-id-113'> + <data-member access='public'> + <var-decl name='ru_nsignals' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='111' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_nsignals_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='112' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__12' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='117' column='1' id='type-id-114'> + <data-member access='public'> + <var-decl name='ru_nvcsw' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='119' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_nvcsw_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='120' column='1'/> + </data-member> + </union-decl> + <union-decl name='__anonymous_union__13' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='124' column='1' id='type-id-115'> + <data-member access='public'> + <var-decl name='ru_nivcsw' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='126' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__ru_nivcsw_word' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_rusage.h' line='127' column='1'/> + </data-member> + </union-decl> + <class-decl name='sched_param' size-in-bits='32' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_sched_param.h' line='23' column='1' id='type-id-74'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='sched_priority' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_sched_param.h' line='25' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='eventfd_t' type-id='type-id-117' filepath='/usr/include/x86_64-linux-gnu/sys/eventfd.h' line='27' column='1' id='type-id-118'/> + <typedef-decl name='__priority_which_t' type-id='type-id-87' filepath='/usr/include/x86_64-linux-gnu/sys/resource.h' line='40' column='1' id='type-id-119'/> + <class-decl name='tms' size-in-bits='256' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/times.h' line='32' column='1' id='type-id-120'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tms_utime' type-id='type-id-98' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/times.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='tms_stime' type-id='type-id-98' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/times.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='tms_cutime' type-id='type-id-98' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/times.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='tms_cstime' type-id='type-id-98' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/times.h' line='38' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='gid_t' type-id='type-id-121' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='64' column='1' id='type-id-122'/> + <typedef-decl name='mode_t' type-id='type-id-123' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='69' column='1' id='type-id-124'/> + <typedef-decl name='uid_t' type-id='type-id-125' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='79' column='1' id='type-id-126'/> + <typedef-decl name='pid_t' type-id='type-id-127' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='97' column='1' id='type-id-72'/> + <typedef-decl name='id_t' type-id='type-id-96' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='103' column='1' id='type-id-128'/> + <class-decl name='utsname' size-in-bits='3120' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='48' column='1' id='type-id-129'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='sysname' type-id='type-id-63' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='520'> + <var-decl name='nodename' type-id='type-id-63' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1040'> + <var-decl name='release' type-id='type-id-63' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1560'> + <var-decl name='version' type-id='type-id-63' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2080'> + <var-decl name='machine' type-id='type-id-63' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2600'> + <var-decl name='domainname' type-id='type-id-63' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='67' column='1'/> + </data-member> + </class-decl> + <enum-decl name='idtype_t' naming-typedef-id='type-id-130' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='75' column='1' id='type-id-131'> + <underlying-type type-id='type-id-24'/> + <enumerator name='P_ALL' value='0'/> + <enumerator name='P_PID' value='1'/> + <enumerator name='P_PGID' value='2'/> + </enum-decl> + <typedef-decl name='idtype_t' type-id='type-id-131' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='79' column='1' id='type-id-130'/> + <pointer-type-def type-id='type-id-68' size-in-bits='64' id='type-id-132'/> + <pointer-type-def type-id='type-id-121' size-in-bits='64' id='type-id-133'/> + <pointer-type-def type-id='type-id-9' size-in-bits='64' id='type-id-134'/> + <pointer-type-def type-id='type-id-66' size-in-bits='64' id='type-id-77'/> + <pointer-type-def type-id='type-id-125' size-in-bits='64' id='type-id-135'/> + <qualified-type-def type-id='type-id-136' restrict='yes' id='type-id-137'/> + <qualified-type-def type-id='type-id-121' const='yes' id='type-id-138'/> + <pointer-type-def type-id='type-id-138' size-in-bits='64' id='type-id-139'/> + <qualified-type-def type-id='type-id-80' const='yes' id='type-id-140'/> + <pointer-type-def type-id='type-id-140' size-in-bits='64' id='type-id-141'/> + <qualified-type-def type-id='type-id-99' const='yes' id='type-id-142'/> + <pointer-type-def type-id='type-id-142' size-in-bits='64' id='type-id-143'/> + <qualified-type-def type-id='type-id-75' const='yes' id='type-id-144'/> + <pointer-type-def type-id='type-id-144' size-in-bits='64' id='type-id-145'/> + <qualified-type-def type-id='type-id-145' restrict='yes' id='type-id-146'/> + <qualified-type-def type-id='type-id-69' const='yes' id='type-id-147'/> + <pointer-type-def type-id='type-id-147' size-in-bits='64' id='type-id-148'/> + <qualified-type-def type-id='type-id-148' restrict='yes' id='type-id-149'/> + <qualified-type-def type-id='type-id-74' const='yes' id='type-id-150'/> + <pointer-type-def type-id='type-id-150' size-in-bits='64' id='type-id-151'/> + <qualified-type-def type-id='type-id-151' restrict='yes' id='type-id-152'/> + <qualified-type-def type-id='type-id-73' const='yes' id='type-id-153'/> + <pointer-type-def type-id='type-id-153' size-in-bits='64' id='type-id-154'/> + <qualified-type-def type-id='type-id-154' restrict='yes' id='type-id-155'/> + <qualified-type-def type-id='type-id-92' const='yes' id='type-id-156'/> + <pointer-type-def type-id='type-id-156' size-in-bits='64' id='type-id-157'/> + <qualified-type-def type-id='type-id-86' const='yes' id='type-id-158'/> + <pointer-type-def type-id='type-id-158' size-in-bits='64' id='type-id-159'/> + <pointer-type-def type-id='type-id-80' size-in-bits='64' id='type-id-160'/> + <pointer-type-def type-id='type-id-82' size-in-bits='64' id='type-id-161'/> + <pointer-type-def type-id='type-id-118' size-in-bits='64' id='type-id-162'/> + <pointer-type-def type-id='type-id-122' size-in-bits='64' id='type-id-163'/> + <pointer-type-def type-id='type-id-72' size-in-bits='64' id='type-id-164'/> + <qualified-type-def type-id='type-id-164' restrict='yes' id='type-id-165'/> + <pointer-type-def type-id='type-id-75' size-in-bits='64' id='type-id-166'/> + <qualified-type-def type-id='type-id-166' restrict='yes' id='type-id-167'/> + <pointer-type-def type-id='type-id-69' size-in-bits='64' id='type-id-168'/> + <qualified-type-def type-id='type-id-168' restrict='yes' id='type-id-169'/> + <pointer-type-def type-id='type-id-100' size-in-bits='64' id='type-id-170'/> + <pointer-type-def type-id='type-id-74' size-in-bits='64' id='type-id-171'/> + <pointer-type-def type-id='type-id-88' size-in-bits='64' id='type-id-172'/> + <qualified-type-def type-id='type-id-172' restrict='yes' id='type-id-173'/> + <pointer-type-def type-id='type-id-120' size-in-bits='64' id='type-id-174'/> + <pointer-type-def type-id='type-id-126' size-in-bits='64' id='type-id-175'/> + <pointer-type-def type-id='type-id-129' size-in-bits='64' id='type-id-176'/> + <class-decl name='__dirstream' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-65'/> + <class-decl name='__spawn_action' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-66'/> + <function-decl name='_PyEval_ReInitThreads' filepath='./Include/internal/pycore_ceval.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyPerfTrampoline_AfterFork_Child' filepath='./Include/internal/pycore_ceval.h' line='77' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyImport_ReInitLock' filepath='./Include/internal/pycore_import.h' line='157' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyInterpreterState_DeleteExceptMain' filepath='./Include/internal/pycore_pystate.h' line='154' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-178'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PySignal_AfterFork' filepath='./Include/internal/pycore_pystate.h' line='155' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyRuntimeState_ReInitThreads' filepath='./Include/internal/pycore_runtime.h' line='183' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-178'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyOS_BeforeFork' mangled-name='PyOS_BeforeFork' filepath='./Modules/posixmodule.c' line='585' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_BeforeFork'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyOS_AfterFork_Parent' mangled-name='PyOS_AfterFork_Parent' filepath='./Modules/posixmodule.c' line='594' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_AfterFork_Parent'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyOS_AfterFork_Child' mangled-name='PyOS_AfterFork_Child' filepath='./Modules/posixmodule.c' line='605' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_AfterFork_Child'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyOS_AfterFork' mangled-name='PyOS_AfterFork' filepath='./Modules/posixmodule.c' line='669' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_AfterFork'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyLong_FromUid' mangled-name='_PyLong_FromUid' filepath='./Modules/posixmodule.c' line='690' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FromUid'> + <parameter type-id='type-id-126' name='uid' filepath='./Modules/posixmodule.c' line='690' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_FromGid' mangled-name='_PyLong_FromGid' filepath='./Modules/posixmodule.c' line='698' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FromGid'> + <parameter type-id='type-id-122' name='gid' filepath='./Modules/posixmodule.c' line='698' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_Uid_Converter' mangled-name='_Py_Uid_Converter' filepath='./Modules/posixmodule.c' line='706' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_Uid_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='./Modules/posixmodule.c' line='706' column='1'/> + <parameter type-id='type-id-175' name='p' filepath='./Modules/posixmodule.c' line='706' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_Gid_Converter' mangled-name='_Py_Gid_Converter' filepath='./Modules/posixmodule.c' line='812' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_Gid_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='./Modules/posixmodule.c' line='812' column='1'/> + <parameter type-id='type-id-163' name='p' filepath='./Modules/posixmodule.c' line='812' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_Sigset_Converter' mangled-name='_Py_Sigset_Converter' filepath='./Modules/posixmodule.c' line='1475' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_Sigset_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='./Modules/posixmodule.c' line='1475' column='1'/> + <parameter type-id='type-id-22' name='addr' filepath='./Modules/posixmodule.c' line='1475' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='opendir' filepath='/usr/include/dirent.h' line='134' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-132'/> + </function-decl> + <function-decl name='fdopendir' filepath='/usr/include/dirent.h' line='141' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-132'/> + </function-decl> + <function-decl name='closedir' filepath='/usr/include/dirent.h' line='149' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-132'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='rewinddir' filepath='/usr/include/dirent.h' line='209' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-132'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='setgroups' filepath='/usr/include/grp.h' line='176' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-139'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getgrouplist' filepath='/usr/include/grp.h' line='186' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-121'/> + <parameter type-id='type-id-133'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='initgroups' filepath='/usr/include/grp.h' line='197' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='openpty' filepath='/usr/include/pty.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-157'/> + <parameter type-id='type-id-159'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='forkpty' filepath='/usr/include/pty.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-157'/> + <parameter type-id='type-id-159'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_setparam' filepath='/usr/include/sched.h' line='54' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-151'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_getparam' filepath='/usr/include/sched.h' line='58' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-171'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_setscheduler' filepath='/usr/include/sched.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-151'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_getscheduler' filepath='/usr/include/sched.h' line='65' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_yield' filepath='/usr/include/sched.h' line='68' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_get_priority_max' filepath='/usr/include/sched.h' line='71' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_get_priority_min' filepath='/usr/include/sched.h' line='74' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_rr_get_interval' filepath='/usr/include/sched.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-180'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_setaffinity' filepath='/usr/include/sched.h' line='130' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-141'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sched_getaffinity' filepath='/usr/include/sched.h' line='134' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-160'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='killpg' filepath='/usr/include/signal.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigaddset' filepath='/usr/include/signal.h' line='205' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-45'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawn' filepath='/usr/include/spawn.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-165'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-146'/> + <parameter type-id='type-id-149'/> + <parameter type-id='type-id-137'/> + <parameter type-id='type-id-137'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnp' filepath='/usr/include/spawn.h' line='85' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-164'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-145'/> + <parameter type-id='type-id-148'/> + <parameter type-id='type-id-136'/> + <parameter type-id='type-id-136'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_init' filepath='/usr/include/spawn.h' line='93' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-168'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_destroy' filepath='/usr/include/spawn.h' line='97' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-168'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_setsigdefault' filepath='/usr/include/spawn.h' line='108' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-169'/> + <parameter type-id='type-id-155'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_setsigmask' filepath='/usr/include/spawn.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-169'/> + <parameter type-id='type-id-155'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_setflags' filepath='/usr/include/spawn.h' line='131' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-168'/> + <parameter type-id='type-id-71'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_setpgroup' filepath='/usr/include/spawn.h' line='141' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-168'/> + <parameter type-id='type-id-72'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_setschedpolicy' filepath='/usr/include/spawn.h' line='152' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-168'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawnattr_setschedparam' filepath='/usr/include/spawn.h' line='164' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-169'/> + <parameter type-id='type-id-152'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawn_file_actions_init' filepath='/usr/include/spawn.h' line='170' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-166'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawn_file_actions_destroy' filepath='/usr/include/spawn.h' line='175' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-166'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawn_file_actions_addopen' filepath='/usr/include/spawn.h' line='181' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-167'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-124'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawn_file_actions_addclose' filepath='/usr/include/spawn.h' line='190' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-166'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='posix_spawn_file_actions_adddup2' filepath='/usr/include/spawn.h' line='196' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-166'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='rename' filepath='/usr/include/stdio.h' line='154' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='renameat' filepath='/usr/include/stdio.h' line='158' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='ctermid' filepath='/usr/include/stdio.h' line='837' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='atoi' filepath='/usr/include/stdlib.h' line='105' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='unsetenv' filepath='/usr/include/stdlib.h' line='664' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='system' filepath='/usr/include/stdlib.h' line='791' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='qsort' filepath='/usr/include/stdlib.h' line='838' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-79'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='getloadavg' filepath='/usr/include/stdlib.h' line='1013' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-182'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='strtok_r' filepath='/usr/include/string.h' line='366' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-184'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='access' filepath='/usr/include/unistd.h' line='287' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='faccessat' filepath='/usr/include/unistd.h' line='309' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pipe' filepath='/usr/include/unistd.h' line='437' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-179'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pipe2' filepath='/usr/include/unistd.h' line='442' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='chown' filepath='/usr/include/unistd.h' line='493' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fchown' filepath='/usr/include/unistd.h' line='498' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='lchown' filepath='/usr/include/unistd.h' line='503' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fchownat' filepath='/usr/include/unistd.h' line='511' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-121'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='chdir' filepath='/usr/include/unistd.h' line='517' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fchdir' filepath='/usr/include/unistd.h' line='521' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='dup2' filepath='/usr/include/unistd.h' line='555' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='dup3' filepath='/usr/include/unistd.h' line='560' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='execve' filepath='/usr/include/unistd.h' line='572' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-136'/> + <parameter type-id='type-id-136'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fexecve' filepath='/usr/include/unistd.h' line='578' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-136'/> + <parameter type-id='type-id-136'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='execv' filepath='/usr/include/unistd.h' line='584' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-136'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='nice' filepath='/usr/include/unistd.h' line='619' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pathconf' filepath='/usr/include/unistd.h' line='633' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='fpathconf' filepath='/usr/include/unistd.h' line='637' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='getppid' filepath='/usr/include/unistd.h' line='653' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='getpgrp' filepath='/usr/include/unistd.h' line='656' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='getpgid' filepath='/usr/include/unistd.h' line='661' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='setpgid' filepath='/usr/include/unistd.h' line='668' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-127'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setpgrp' filepath='/usr/include/unistd.h' line='682' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setsid' filepath='/usr/include/unistd.h' line='689' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='getsid' filepath='/usr/include/unistd.h' line='693' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='getuid' filepath='/usr/include/unistd.h' line='697' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-125'/> + </function-decl> + <function-decl name='geteuid' filepath='/usr/include/unistd.h' line='700' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-125'/> + </function-decl> + <function-decl name='getgid' filepath='/usr/include/unistd.h' line='703' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-121'/> + </function-decl> + <function-decl name='getegid' filepath='/usr/include/unistd.h' line='706' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-121'/> + </function-decl> + <function-decl name='getgroups' filepath='/usr/include/unistd.h' line='711' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-133'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setuid' filepath='/usr/include/unistd.h' line='722' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-125'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setreuid' filepath='/usr/include/unistd.h' line='727' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-125'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='seteuid' filepath='/usr/include/unistd.h' line='732' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-125'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setgid' filepath='/usr/include/unistd.h' line='739' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setregid' filepath='/usr/include/unistd.h' line='744' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-121'/> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setegid' filepath='/usr/include/unistd.h' line='749' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getresuid' filepath='/usr/include/unistd.h' line='755' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-135'/> + <parameter type-id='type-id-135'/> + <parameter type-id='type-id-135'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getresgid' filepath='/usr/include/unistd.h' line='760' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-133'/> + <parameter type-id='type-id-133'/> + <parameter type-id='type-id-133'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setresuid' filepath='/usr/include/unistd.h' line='765' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-125'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setresgid' filepath='/usr/include/unistd.h' line='770' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-121'/> + <parameter type-id='type-id-121'/> + <parameter type-id='type-id-121'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fork' filepath='/usr/include/unistd.h' line='778' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='ttyname_r' filepath='/usr/include/unistd.h' line='803' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='link' filepath='/usr/include/unistd.h' line='819' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='linkat' filepath='/usr/include/unistd.h' line='825' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='symlink' filepath='/usr/include/unistd.h' line='832' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='symlinkat' filepath='/usr/include/unistd.h' line='847' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='readlinkat' filepath='/usr/include/unistd.h' line='851' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='unlink' filepath='/usr/include/unistd.h' line='858' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='unlinkat' filepath='/usr/include/unistd.h' line='862' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='rmdir' filepath='/usr/include/unistd.h' line='867' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='tcgetpgrp' filepath='/usr/include/unistd.h' line='871' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='tcsetpgrp' filepath='/usr/include/unistd.h' line='874' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-127'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getlogin' filepath='/usr/include/unistd.h' line='881' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='chroot' filepath='/usr/include/unistd.h' line='977' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fsync' filepath='/usr/include/unistd.h' line='989' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sync' filepath='/usr/include/unistd.h' line='1005' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='copy_file_range' filepath='/usr/include/unistd.h' line='1142' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-134'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-134'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-95'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='fdatasync' filepath='/usr/include/unistd.h' line='1150' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='login_tty' filepath='/usr/include/utmp.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='__sched_cpucount' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='117' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-141'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='__sched_cpualloc' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-160'/> + </function-decl> + <function-decl name='__sched_cpufree' filepath='/usr/include/x86_64-linux-gnu/bits/cpu-set.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-160'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='splice' filepath='/usr/include/x86_64-linux-gnu/bits/fcntl-linux.h' line='421' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-134'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-134'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-95'/> + <return type-id='type-id-186'/> + </function-decl> + <function-decl name='memfd_create' filepath='/usr/include/x86_64-linux-gnu/bits/mman-shared.h' line='51' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-95'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='unshare' filepath='/usr/include/x86_64-linux-gnu/bits/sched.h' line='86' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setns' filepath='/usr/include/x86_64-linux-gnu/bits/sched.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='eventfd' filepath='/usr/include/x86_64-linux-gnu/sys/eventfd.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-95'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='eventfd_read' filepath='/usr/include/x86_64-linux-gnu/sys/eventfd.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-162'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='eventfd_write' filepath='/usr/include/x86_64-linux-gnu/sys/eventfd.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-118'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getpriority' filepath='/usr/include/x86_64-linux-gnu/sys/resource.h' line='105' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-119'/> + <parameter type-id='type-id-128'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setpriority' filepath='/usr/include/x86_64-linux-gnu/sys/resource.h' line='109' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-119'/> + <parameter type-id='type-id-128'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='chmod' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='352' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fchmod' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='365' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-123'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fchmodat' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='371' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='umask' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='380' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-123'/> + <return type-id='type-id-123'/> + </function-decl> + <function-decl name='mkdir' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='389' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='mkdirat' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='396' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='mknod' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='404' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <parameter type-id='type-id-187'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='mknodat' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='411' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <parameter type-id='type-id-187'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='mkfifo' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='418' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='mkfifoat' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='425' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-123'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='utimensat' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='433' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-188'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='futimens' filepath='/usr/include/x86_64-linux-gnu/sys/stat.h' line='452' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-188'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='gnu_dev_major' filepath='/usr/include/x86_64-linux-gnu/sys/sysmacros.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-187'/> + <return type-id='type-id-95'/> + </function-decl> + <function-decl name='gnu_dev_minor' filepath='/usr/include/x86_64-linux-gnu/sys/sysmacros.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-187'/> + <return type-id='type-id-95'/> + </function-decl> + <function-decl name='gnu_dev_makedev' filepath='/usr/include/x86_64-linux-gnu/sys/sysmacros.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-95'/> + <parameter type-id='type-id-95'/> + <return type-id='type-id-187'/> + </function-decl> + <function-decl name='times' filepath='/usr/include/x86_64-linux-gnu/sys/times.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-174'/> + <return type-id='type-id-98'/> + </function-decl> + <function-decl name='readv' filepath='/usr/include/x86_64-linux-gnu/sys/uio.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-143'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='writev' filepath='/usr/include/x86_64-linux-gnu/sys/uio.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-143'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='uname' filepath='/usr/include/x86_64-linux-gnu/sys/utsname.h' line='81' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-176'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='wait' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='88' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-179'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='waitpid' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='111' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='waitid' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='132' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-130'/> + <parameter type-id='type-id-96'/> + <parameter type-id='type-id-189'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='wait3' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='148' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-170'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='wait4' filepath='/usr/include/x86_64-linux-gnu/sys/wait.h' line='164' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-170'/> + <return type-id='type-id-127'/> + </function-decl> + <function-decl name='setxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='lsetxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='48' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fsetxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='54' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='lgetxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='65' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='fgetxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='70' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='listxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='llistxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='82' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='flistxattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='removexattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='92' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='lremovexattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='97' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fremovexattr' filepath='/usr/include/x86_64-linux-gnu/sys/xattr.h' line='101' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <type-decl name='unsigned short int' size-in-bits='16' id='type-id-84'/> + <function-type size-in-bits='64' id='type-id-190'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='./Modules/pwdmodule.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='passwd' size-in-bits='384' is-struct='yes' visibility='default' filepath='/usr/include/pwd.h' line='49' column='1' id='type-id-191'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='pw_name' type-id='type-id-15' visibility='default' filepath='/usr/include/pwd.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='pw_passwd' type-id='type-id-15' visibility='default' filepath='/usr/include/pwd.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='pw_uid' type-id='type-id-125' visibility='default' filepath='/usr/include/pwd.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='pw_gid' type-id='type-id-121' visibility='default' filepath='/usr/include/pwd.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='pw_gecos' type-id='type-id-15' visibility='default' filepath='/usr/include/pwd.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='pw_dir' type-id='type-id-15' visibility='default' filepath='/usr/include/pwd.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='pw_shell' type-id='type-id-15' visibility='default' filepath='/usr/include/pwd.h' line='58' column='1'/> + </data-member> + </class-decl> + <pointer-type-def type-id='type-id-191' size-in-bits='64' id='type-id-192'/> + <qualified-type-def type-id='type-id-192' restrict='yes' id='type-id-193'/> + <pointer-type-def type-id='type-id-192' size-in-bits='64' id='type-id-194'/> + <qualified-type-def type-id='type-id-194' restrict='yes' id='type-id-195'/> + <function-decl name='setpwent' filepath='/usr/include/pwd.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='endpwent' filepath='/usr/include/pwd.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='getpwent' filepath='/usr/include/pwd.h' line='84' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-192'/> + </function-decl> + <function-decl name='getpwuid_r' filepath='/usr/include/pwd.h' line='146' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-125'/> + <parameter type-id='type-id-193'/> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-195'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getpwnam_r' filepath='/usr/include/pwd.h' line='153' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-193'/> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-195'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/signalmodule.c' comp-dir-path='/src' language='LANG_C11'> + <enum-decl name='__itimer_which' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='114' column='1' id='type-id-196'> + <underlying-type type-id='type-id-24'/> + <enumerator name='ITIMER_REAL' value='0'/> + <enumerator name='ITIMER_VIRTUAL' value='1'/> + <enumerator name='ITIMER_PROF' value='2'/> + </enum-decl> + <class-decl name='itimerval' size-in-bits='256' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='130' column='1' id='type-id-197'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='it_interval' type-id='type-id-101' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='133' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='it_value' type-id='type-id-101' visibility='default' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='135' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__itimer_which_t' type-id='type-id-196' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='141' column='1' id='type-id-198'/> + <qualified-type-def type-id='type-id-197' const='yes' id='type-id-199'/> + <pointer-type-def type-id='type-id-199' size-in-bits='64' id='type-id-200'/> + <qualified-type-def type-id='type-id-200' restrict='yes' id='type-id-201'/> + <qualified-type-def type-id='type-id-179' restrict='yes' id='type-id-202'/> + <pointer-type-def type-id='type-id-197' size-in-bits='64' id='type-id-203'/> + <qualified-type-def type-id='type-id-203' restrict='yes' id='type-id-204'/> + <qualified-type-def type-id='type-id-189' restrict='yes' id='type-id-205'/> + <function-decl name='_PyErr_CheckSignals' mangled-name='_PyErr_CheckSignals' filepath='./Modules/signalmodule.c' line='1872' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_CheckSignals'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_SetInterruptEx' mangled-name='PyErr_SetInterruptEx' filepath='./Modules/signalmodule.c' line='1884' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetInterruptEx'> + <parameter type-id='type-id-8' name='signum' filepath='./Modules/signalmodule.c' line='1884' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_SetInterrupt' mangled-name='PyErr_SetInterrupt' filepath='./Modules/signalmodule.c' line='1900' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetInterrupt'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_RestoreSignals' mangled-name='_Py_RestoreSignals' filepath='./Modules/signalmodule.c' line='1938' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_RestoreSignals'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyOS_InterruptOccurred' mangled-name='PyOS_InterruptOccurred' filepath='./Modules/signalmodule.c' line='2010' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_InterruptOccurred'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyOS_IsMainThread' mangled-name='_PyOS_IsMainThread' filepath='./Modules/signalmodule.c' line='2043' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyOS_IsMainThread'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigismember' filepath='/usr/include/signal.h' line='211' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-154'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigpending' filepath='/usr/include/signal.h' line='247' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-45'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigwait' filepath='/usr/include/signal.h' line='255' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-155'/> + <parameter type-id='type-id-202'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigwaitinfo' filepath='/usr/include/signal.h' line='264' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-155'/> + <parameter type-id='type-id-205'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigtimedwait' filepath='/usr/include/signal.h' line='273' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-155'/> + <parameter type-id='type-id-205'/> + <parameter type-id='type-id-206'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='__libc_current_sigrtmin' filepath='/usr/include/signal.h' line='383' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='__libc_current_sigrtmax' filepath='/usr/include/signal.h' line='385' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='strstr' filepath='/usr/include/string.h' line='350' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='strsignal' filepath='/usr/include/string.h' line='478' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='alarm' filepath='/usr/include/unistd.h' line='452' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-95'/> + <return type-id='type-id-95'/> + </function-decl> + <function-decl name='pause' filepath='/usr/include/unistd.h' line='489' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_kill' filepath='/usr/include/x86_64-linux-gnu/bits/sigthread.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-207'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getitimer' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='149' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-198'/> + <parameter type-id='type-id-203'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='setitimer' filepath='/usr/include/x86_64-linux-gnu/sys/time.h' line='155' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-198'/> + <parameter type-id='type-id-201'/> + <parameter type-id='type-id-204'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/symtablemodule.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_SymtableStringObjectFlags' filepath='./Include/internal/pycore_symtable.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-208'/> + <return type-id='type-id-209'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Modules/timemodule.c' comp-dir-path='/src' language='LANG_C11'> + <enum-decl name='__rusage_who' filepath='/usr/include/x86_64-linux-gnu/bits/resource.h' line='158' column='1' id='type-id-210'> + <underlying-type type-id='type-id-24'/> + <enumerator name='RUSAGE_SELF' value='0'/> + <enumerator name='RUSAGE_CHILDREN' value='-1'/> + <enumerator name='RUSAGE_THREAD' value='1'/> + </enum-decl> + <typedef-decl name='__rusage_who_t' type-id='type-id-210' filepath='/usr/include/x86_64-linux-gnu/sys/resource.h' line='39' column='1' id='type-id-211'/> + <pointer-type-def type-id='type-id-212' size-in-bits='64' id='type-id-213'/> + <qualified-type-def type-id='type-id-214' const='yes' id='type-id-215'/> + <pointer-type-def type-id='type-id-215' size-in-bits='64' id='type-id-216'/> + <qualified-type-def type-id='type-id-216' restrict='yes' id='type-id-217'/> + <function-decl name='pthread_getcpuclockid' filepath='/usr/include/pthread.h' line='1315' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-207'/> + <parameter type-id='type-id-213'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='clock' filepath='/usr/include/time.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-98'/> + </function-decl> + <function-decl name='time' filepath='/usr/include/time.h' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-218'/> + <return type-id='type-id-219'/> + </function-decl> + <function-decl name='mktime' filepath='/usr/include/time.h' line='83' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-220'/> + <return type-id='type-id-219'/> + </function-decl> + <function-decl name='tzset' filepath='/usr/include/time.h' line='228' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='clock_settime' filepath='/usr/include/time.h' line='282' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-221'/> + <parameter type-id='type-id-188'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='clock_nanosleep' filepath='/usr/include/time.h' line='311' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-221'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-188'/> + <parameter type-id='type-id-180'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='wcsftime' filepath='/usr/include/wchar.h' line='852' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-18'/> + <parameter type-id='type-id-217'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='getrusage' filepath='/usr/include/x86_64-linux-gnu/sys/resource.h' line='89' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-211'/> + <parameter type-id='type-id-170'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Python/dynload_shlib.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-12' size-in-bits='256' id='type-id-222'> + <subrange length='4' type-id='type-id-28' id='type-id-223'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-12' size-in-bits='infinite' id='type-id-224'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <var-decl name='_PyImport_DynLoadFiletab' type-id='type-id-224' visibility='default' filepath='./Python/importdl.h' line='9' column='1'/> + <function-decl name='dlopen' filepath='/usr/include/dlfcn.h' line='58' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='dlsym' filepath='/usr/include/dlfcn.h' line='66' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-226'/> + <parameter type-id='type-id-181'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='dlerror' filepath='/usr/include/dlfcn.h' line='84' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-15'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Python/getplatform.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='Py_GetPlatform' mangled-name='Py_GetPlatform' filepath='./Python/getplatform.c' line='9' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetPlatform'> + <return type-id='type-id-12'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='./Python/importdl.c' comp-dir-path='/src' language='LANG_C11'> + <typedef-decl name='dl_funcptr' type-id='type-id-227' filepath='./Python/importdl.h' line='28' column='1' id='type-id-228'/> + <function-decl name='_PyImport_SwapPackageContext' filepath='./Include/internal/pycore_import.h' line='113' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_PyImport_FindSharedFuncptr' filepath='./Python/importdl.c' line='25' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-229'/> + <return type-id='type-id-228'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-230'> + <return type-id='type-id-46'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='./Python/sysmodule.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyEval_CallTracing' filepath='./Include/internal/pycore_ceval.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyEval_GetAsyncGenFirstiter' filepath='./Include/internal/pycore_ceval.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyEval_GetAsyncGenFinalizer' filepath='./Include/internal/pycore_ceval.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyEval_SetAsyncGenFirstiter' filepath='./Include/internal/pycore_ceval.h' line='44' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_SetAsyncGenFinalizer' filepath='./Include/internal/pycore_ceval.h' line='45' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_GetCoroutineOriginTrackingDepth' filepath='./Include/internal/pycore_ceval.h' line='49' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_SetCoroutineOriginTrackingDepth' filepath='./Include/internal/pycore_ceval.h' line='50' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPerfTrampoline_GetCallbacks' filepath='./Include/internal/pycore_ceval.h' line='73' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-231'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyIsPerfTrampolineActive' filepath='./Include/internal/pycore_ceval.h' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_GetDLOpenFlags' filepath='./Include/internal/pycore_import.h' line='115' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_SetDLOpenFlags' filepath='./Include/internal/pycore_import.h' line='116' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_InitModules' filepath='./Include/internal/pycore_import.h' line='118' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_GetBuiltinModuleNames' filepath='./Include/internal/pycore_import.h' line='161' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_GetGlobalAllocatedBlocks' filepath='./Include/internal/pycore_obmalloc.h' line='682' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyPathConfig_ComputeSysPath0' filepath='./Include/internal/pycore_pathconfig.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-232'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_GetStdlibDir' filepath='./Include/internal/pycore_pylifecycle.h' line='81' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_PyErr_WriteUnraisableDefaultHook' filepath='./Include/internal/pycore_pylifecycle.h' line='85' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_InternedSize' filepath='./Include/internal/pycore_unicodeobject.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyThread_GetInfo' mangled-name='PyThread_GetInfo' filepath='./Include/pythread.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_GetInfo'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySys_AddAuditHook' mangled-name='PySys_AddAuditHook' filepath='./Python/sysmodule.c' line='366' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_AddAuditHook'> + <parameter type-id='type-id-234' name='hook' filepath='./Python/sysmodule.c' line='366' column='1'/> + <parameter type-id='type-id-22' name='userData' filepath='./Python/sysmodule.c' line='366' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySys_GetSizeOf' mangled-name='_PySys_GetSizeOf' filepath='./Python/sysmodule.c' line='1754' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySys_GetSizeOf'> + <parameter type-id='type-id-2' name='o' filepath='./Python/sysmodule.c' line='1754' column='1'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='PyUnstable_PerfMapState_Init' mangled-name='PyUnstable_PerfMapState_Init' filepath='./Python/sysmodule.c' line='2253' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_PerfMapState_Init'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_WritePerfMapEntry' mangled-name='PyUnstable_WritePerfMapEntry' filepath='./Python/sysmodule.c' line='2281' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_WritePerfMapEntry'> + <parameter type-id='type-id-22' name='code_addr' filepath='./Python/sysmodule.c' line='2282' column='1'/> + <parameter type-id='type-id-95' name='code_size' filepath='./Python/sysmodule.c' line='2283' column='1'/> + <parameter type-id='type-id-12' name='entry_name' filepath='./Python/sysmodule.c' line='2284' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySys_ResetWarnOptions' mangled-name='PySys_ResetWarnOptions' filepath='./Python/sysmodule.c' line='2590' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_ResetWarnOptions'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_AddWarnOptionUnicode' mangled-name='PySys_AddWarnOptionUnicode' filepath='./Python/sysmodule.c' line='2618' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_AddWarnOptionUnicode'> + <parameter type-id='type-id-2' name='option' filepath='./Python/sysmodule.c' line='2618' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_AddWarnOption' mangled-name='PySys_AddWarnOption' filepath='./Python/sysmodule.c' line='2630' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_AddWarnOption'> + <parameter type-id='type-id-16' name='s' filepath='./Python/sysmodule.c' line='2630' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_HasWarnOptions' mangled-name='PySys_HasWarnOptions' filepath='./Python/sysmodule.c' line='2649' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_HasWarnOptions'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySys_AddXOption' mangled-name='PySys_AddXOption' filepath='./Python/sysmodule.c' line='2722' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_AddXOption'> + <parameter type-id='type-id-16' name='s' filepath='./Python/sysmodule.c' line='2722' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_GetXOptions' mangled-name='PySys_GetXOptions' filepath='./Python/sysmodule.c' line='2736' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_GetXOptions'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_CreateMonitoringObject' filepath='./Python/sysmodule.c' line='3503' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySys_SetPath' mangled-name='PySys_SetPath' filepath='./Python/sysmodule.c' line='3625' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_SetPath'> + <parameter type-id='type-id-16' name='path' filepath='./Python/sysmodule.c' line='3625' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_SetArgvEx' mangled-name='PySys_SetArgvEx' filepath='./Python/sysmodule.c' line='3657' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_SetArgvEx'> + <parameter type-id='type-id-8' name='argc' filepath='./Python/sysmodule.c' line='3657' column='1'/> + <parameter type-id='type-id-235' name='argv' filepath='./Python/sysmodule.c' line='3657' column='1'/> + <parameter type-id='type-id-8' name='updatepath' filepath='./Python/sysmodule.c' line='3657' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_SetArgv' mangled-name='PySys_SetArgv' filepath='./Python/sysmodule.c' line='3701' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_SetArgv'> + <parameter type-id='type-id-8' name='argc' filepath='./Python/sysmodule.c' line='3701' column='1'/> + <parameter type-id='type-id-235' name='argv' filepath='./Python/sysmodule.c' line='3701' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_WriteStdout' mangled-name='PySys_WriteStdout' filepath='./Python/sysmodule.c' line='3796' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_WriteStdout'> + <parameter type-id='type-id-12' name='format' filepath='./Python/sysmodule.c' line='3796' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_FormatStdout' mangled-name='PySys_FormatStdout' filepath='./Python/sysmodule.c' line='3838' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_FormatStdout'> + <parameter type-id='type-id-12' name='format' filepath='./Python/sysmodule.c' line='3838' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='getpid' filepath='/usr/include/unistd.h' line='650' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-127'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Modules/config.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyInit_atexit' mangled-name='PyInit_atexit' filepath='Modules/config.c' line='26' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_atexit'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_faulthandler' mangled-name='PyInit_faulthandler' filepath='Modules/config.c' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_faulthandler'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_posix' mangled-name='PyInit_posix' filepath='Modules/config.c' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_posix'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__signal' mangled-name='PyInit__signal' filepath='Modules/config.c' line='29' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__signal'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__tracemalloc' mangled-name='PyInit__tracemalloc' filepath='Modules/config.c' line='30' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__tracemalloc'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__codecs' mangled-name='PyInit__codecs' filepath='Modules/config.c' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__codecs'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__collections' mangled-name='PyInit__collections' filepath='Modules/config.c' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__collections'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_errno' mangled-name='PyInit_errno' filepath='Modules/config.c' line='33' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_errno'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__io' mangled-name='PyInit__io' filepath='Modules/config.c' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__io'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_itertools' mangled-name='PyInit_itertools' filepath='Modules/config.c' line='35' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_itertools'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__sre' mangled-name='PyInit__sre' filepath='Modules/config.c' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__sre'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__thread' mangled-name='PyInit__thread' filepath='Modules/config.c' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__thread'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_time' mangled-name='PyInit_time' filepath='Modules/config.c' line='38' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_time'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__typing' mangled-name='PyInit__typing' filepath='Modules/config.c' line='39' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__typing'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__weakref' mangled-name='PyInit__weakref' filepath='Modules/config.c' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__weakref'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__abc' mangled-name='PyInit__abc' filepath='Modules/config.c' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__abc'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__functools' mangled-name='PyInit__functools' filepath='Modules/config.c' line='42' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__functools'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__locale' mangled-name='PyInit__locale' filepath='Modules/config.c' line='43' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__locale'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__operator' mangled-name='PyInit__operator' filepath='Modules/config.c' line='44' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__operator'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__stat' mangled-name='PyInit__stat' filepath='Modules/config.c' line='45' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__stat'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__symtable' mangled-name='PyInit__symtable' filepath='Modules/config.c' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__symtable'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_pwd' mangled-name='PyInit_pwd' filepath='Modules/config.c' line='47' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_pwd'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit_gc' mangled-name='PyInit_gc' filepath='Modules/config.c' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit_gc'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Modules/gcmodule.c' comp-dir-path='/src' language='LANG_C11'> + <typedef-decl name='gcvisitobjects_t' type-id='type-id-236' filepath='./Include/objimpl.h' line='175' column='1' id='type-id-237'/> + <function-decl name='_PyTuple_ClearFreeList' filepath='./Include/internal/pycore_gc.h' line='199' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFloat_ClearFreeList' filepath='./Include/internal/pycore_gc.h' line='200' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyList_ClearFreeList' filepath='./Include/internal/pycore_gc.h' line='201' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyDict_ClearFreeList' filepath='./Include/internal/pycore_gc.h' line='202' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyAsyncGen_ClearFreeLists' filepath='./Include/internal/pycore_gc.h' line='203' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyContext_ClearFreeList' filepath='./Include/internal/pycore_gc.h' line='204' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyGC_Enable' mangled-name='PyGC_Enable' filepath='Modules/gcmodule.c' line='2068' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGC_Enable'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyGC_Disable' mangled-name='PyGC_Disable' filepath='Modules/gcmodule.c' line='2077' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGC_Disable'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyGC_IsEnabled' mangled-name='PyGC_IsEnabled' filepath='Modules/gcmodule.c' line='2086' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGC_IsEnabled'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_Object_GC_NewWithExtraData' mangled-name='PyUnstable_Object_GC_NewWithExtraData' filepath='Modules/gcmodule.c' line='2347' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Object_GC_NewWithExtraData'> + <parameter type-id='type-id-1' name='tp' filepath='Modules/gcmodule.c' line='2347' column='1'/> + <parameter type-id='type-id-19' name='extra_size' filepath='Modules/gcmodule.c' line='2347' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GC_IsTracked' mangled-name='PyObject_GC_IsTracked' filepath='Modules/gcmodule.c' line='2401' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GC_IsTracked'> + <parameter type-id='type-id-2' name='obj' filepath='Modules/gcmodule.c' line='2401' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GC_IsFinalized' mangled-name='PyObject_GC_IsFinalized' filepath='Modules/gcmodule.c' line='2410' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GC_IsFinalized'> + <parameter type-id='type-id-2' name='obj' filepath='Modules/gcmodule.c' line='2410' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_GC_VisitObjects' mangled-name='PyUnstable_GC_VisitObjects' filepath='Modules/gcmodule.c' line='2419' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_GC_VisitObjects'> + <parameter type-id='type-id-237' name='callback' filepath='Modules/gcmodule.c' line='2419' column='1'/> + <parameter type-id='type-id-22' name='arg' filepath='Modules/gcmodule.c' line='2419' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-238'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Modules/main.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyImport_Fini2' filepath='./Include/internal/pycore_import.h' line='145' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='kill' filepath='/usr/include/signal.h' line='112' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-127'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_RunMain' mangled-name='Py_RunMain' filepath='Modules/main.c' line='685' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_RunMain'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_Main' mangled-name='Py_Main' filepath='Modules/main.c' line='724' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Main'> + <parameter type-id='type-id-8' name='argc' filepath='Modules/main.c' line='724' column='1'/> + <parameter type-id='type-id-235' name='argv' filepath='Modules/main.c' line='724' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_BytesMain' mangled-name='Py_BytesMain' filepath='Modules/main.c' line='736' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_BytesMain'> + <parameter type-id='type-id-8' name='argc' filepath='Modules/main.c' line='736' column='1'/> + <parameter type-id='type-id-239' name='argv' filepath='Modules/main.c' line='736' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/abstract.c' comp-dir-path='/src' language='LANG_C11'> + <pointer-type-def type-id='type-id-240' size-in-bits='64' id='type-id-241'/> + <qualified-type-def type-id='type-id-15' const='yes' id='type-id-242'/> + <pointer-type-def type-id='type-id-242' size-in-bits='64' id='type-id-136'/> + <qualified-type-def type-id='type-id-243' const='yes' id='type-id-244'/> + <pointer-type-def type-id='type-id-244' size-in-bits='64' id='type-id-245'/> + <qualified-type-def type-id='type-id-14' const='yes' id='type-id-246'/> + <pointer-type-def type-id='type-id-246' size-in-bits='64' id='type-id-247'/> + <function-decl name='PyObject_CallFunctionObjArgs' mangled-name='PyObject_CallFunctionObjArgs' filepath='./Include/abstract.h' line='215' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallFunctionObjArgs'> + <parameter type-id='type-id-2'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_VectorcallMethod' mangled-name='PyObject_VectorcallMethod' filepath='./Include/abstract.h' line='253' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_VectorcallMethod'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_CallOneArg' mangled-name='PyObject_CallOneArg' filepath='./Include/cpython/abstract.h' line='88' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallOneArg'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyGen_FetchStopIterationValue' mangled-name='_PyGen_FetchStopIterationValue' filepath='./Include/cpython/genobject.h' line='45' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyGen_FetchStopIterationValue'> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyList_Extend' mangled-name='_PyList_Extend' filepath='./Include/cpython/listobject.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyList_Extend'> + <parameter type-id='type-id-249'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_Copy' mangled-name='_PyLong_Copy' filepath='./Include/cpython/longintrepr.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Copy'> + <parameter type-id='type-id-241'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_FromUnicodeObject' mangled-name='PyLong_FromUnicodeObject' filepath='./Include/cpython/longobject.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromUnicodeObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_FromBytes' mangled-name='_PyLong_FromBytes' filepath='./Include/cpython/longobject.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FromBytes'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_Format' mangled-name='_PyLong_Format' filepath='./Include/cpython/longobject.h' line='89' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Format'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_LookupAttr' mangled-name='_PyObject_LookupAttr' filepath='./Include/cpython/object.h' line='304' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_LookupAttr'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_NextNotImplemented' mangled-name='_PyObject_NextNotImplemented' filepath='./Include/cpython/object.h' line='310' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_NextNotImplemented'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTuple_Resize' mangled-name='_PyTuple_Resize' filepath='./Include/cpython/tupleobject.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTuple_Resize'> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_New' mangled-name='PyUnicode_New' filepath='./Include/cpython/unicodeobject.h' line='387' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_New'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-250'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_Keys' mangled-name='PyDict_Keys' filepath='./Include/dictobject.h' line='29' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Keys'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_Values' mangled-name='PyDict_Values' filepath='./Include/dictobject.h' line='30' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Values'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_Items' mangled-name='PyDict_Items' filepath='./Include/dictobject.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Items'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFloat_FromString' mangled-name='PyFloat_FromString' filepath='./Include/floatobject.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_FromString'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_GenericAlias' mangled-name='Py_GenericAlias' filepath='./Include/genericaliasobject.h' line='8' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GenericAlias'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_CheckRecursiveCall' mangled-name='_Py_CheckRecursiveCall' filepath='./Include/internal/pycore_ceval.h' line='124' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_CheckRecursiveCall'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_LookupSpecial' mangled-name='_PyObject_LookupSpecial' filepath='./Include/internal/pycore_object.h' line='395' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_LookupSpecial'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_ExceptionMatches' mangled-name='_PyErr_ExceptionMatches' filepath='./Include/internal/pycore_pyerrors.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_ExceptionMatches'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_Clear' mangled-name='_PyErr_Clear' filepath='./Include/internal/pycore_pyerrors.h' line='67' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_Clear'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_SetString' mangled-name='_PyErr_SetString' filepath='./Include/internal/pycore_pyerrors.h' line='73' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_SetString'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_Format' mangled-name='_PyErr_Format' filepath='./Include/internal/pycore_pyerrors.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_Format'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_union_args' filepath='./Include/internal/pycore_unionobject.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySeqIter_New' mangled-name='PySeqIter_New' filepath='./Include/iterobject.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySeqIter_New'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyList_New' mangled-name='PyList_New' filepath='./Include/listobject.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_New'> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyList_AsTuple' mangled-name='PyList_AsTuple' filepath='./Include/listobject.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_AsTuple'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_FromSsize_t' mangled-name='PyLong_FromSsize_t' filepath='./Include/longobject.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromSsize_t'> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_AsSsize_t' mangled-name='PyLong_AsSsize_t' filepath='./Include/longobject.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsSsize_t'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyLong_AsDouble' mangled-name='PyLong_AsDouble' filepath='./Include/longobject.h' line='63' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsDouble'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyType_IsSubtype' mangled-name='PyType_IsSubtype' filepath='./Include/object.h' line='363' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_IsSubtype'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_RichCompareBool' mangled-name='PyObject_RichCompareBool' filepath='./Include/object.h' line='391' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_RichCompareBool'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_IsTrue' mangled-name='PyObject_IsTrue' filepath='./Include/object.h' line='406' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_IsTrue'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_GivenExceptionMatches' mangled-name='PyErr_GivenExceptionMatches' filepath='./Include/pyerrors.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_GivenExceptionMatches'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySlice_FromIndices' mangled-name='_PySlice_FromIndices' filepath='./Include/sliceobject.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySlice_FromIndices'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyTuple_New' mangled-name='PyTuple_New' filepath='./Include/tupleobject.h' line='30' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTuple_New'> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_WarnEx' mangled-name='PyErr_WarnEx' filepath='./Include/warnings.h' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_WarnEx'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_WarnFormat' mangled-name='PyErr_WarnFormat' filepath='./Include/warnings.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_WarnFormat'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_Type' mangled-name='PyObject_Type' filepath='Objects/abstract.c' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Type'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='40' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Size' mangled-name='PyObject_Size' filepath='Objects/abstract.c' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Size'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='53' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyObject_Length' mangled-name='PyObject_Length' filepath='Objects/abstract.c' line='72' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Length'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='72' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyObject_HasLen' mangled-name='_PyObject_HasLen' filepath='Objects/abstract.c' line='79' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_HasLen'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='79' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_LengthHint' mangled-name='PyObject_LengthHint' filepath='Objects/abstract.c' line='91' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_LengthHint'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='91' column='1'/> + <parameter type-id='type-id-14' name='defaultvalue' filepath='Objects/abstract.c' line='91' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyObject_GetItem' mangled-name='PyObject_GetItem' filepath='Objects/abstract.c' line='149' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetItem'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='149' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/abstract.c' line='149' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_SetItem' mangled-name='PyObject_SetItem' filepath='Objects/abstract.c' line='203' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_SetItem'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='203' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/abstract.c' line='203' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Objects/abstract.c' line='203' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_DelItem' mangled-name='PyObject_DelItem' filepath='Objects/abstract.c' line='237' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_DelItem'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='237' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/abstract.c' line='237' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_DelItemString' mangled-name='PyObject_DelItemString' filepath='Objects/abstract.c' line='271' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_DelItemString'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='271' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/abstract.c' line='271' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_CheckBuffer' mangled-name='PyObject_CheckBuffer' filepath='Objects/abstract.c' line='291' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CheckBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='291' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_CheckReadBuffer' mangled-name='PyObject_CheckReadBuffer' filepath='Objects/abstract.c' line='302' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CheckReadBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='302' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_AsCharBuffer' mangled-name='PyObject_AsCharBuffer' filepath='Objects/abstract.c' line='337' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_AsCharBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='337' column='1'/> + <parameter type-id='type-id-252' name='buffer' filepath='Objects/abstract.c' line='338' column='1'/> + <parameter type-id='type-id-13' name='buffer_len' filepath='Objects/abstract.c' line='339' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_AsReadBuffer' mangled-name='PyObject_AsReadBuffer' filepath='Objects/abstract.c' line='344' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_AsReadBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='344' column='1'/> + <parameter type-id='type-id-253' name='buffer' filepath='Objects/abstract.c' line='345' column='1'/> + <parameter type-id='type-id-13' name='buffer_len' filepath='Objects/abstract.c' line='346' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_AsWriteBuffer' mangled-name='PyObject_AsWriteBuffer' filepath='Objects/abstract.c' line='351' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_AsWriteBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='351' column='1'/> + <parameter type-id='type-id-253' name='buffer' filepath='Objects/abstract.c' line='352' column='1'/> + <parameter type-id='type-id-13' name='buffer_len' filepath='Objects/abstract.c' line='353' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GetBuffer' mangled-name='PyObject_GetBuffer' filepath='Objects/abstract.c' line='380' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='380' column='1'/> + <parameter type-id='type-id-254' name='view' filepath='Objects/abstract.c' line='380' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/abstract.c' line='380' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyBuffer_IsContiguous' mangled-name='PyBuffer_IsContiguous' filepath='Objects/abstract.c' line='463' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_IsContiguous'> + <parameter type-id='type-id-245' name='view' filepath='Objects/abstract.c' line='463' column='1'/> + <parameter type-id='type-id-48' name='order' filepath='Objects/abstract.c' line='463' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyBuffer_GetPointer' mangled-name='PyBuffer_GetPointer' filepath='Objects/abstract.c' line='479' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_GetPointer'> + <parameter type-id='type-id-245' name='view' filepath='Objects/abstract.c' line='479' column='1'/> + <parameter type-id='type-id-247' name='indices' filepath='Objects/abstract.c' line='479' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_Py_add_one_to_index_F' mangled-name='_Py_add_one_to_index_F' filepath='Objects/abstract.c' line='495' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_add_one_to_index_F'> + <parameter type-id='type-id-8' name='nd' filepath='Objects/abstract.c' line='495' column='1'/> + <parameter type-id='type-id-13' name='index' filepath='Objects/abstract.c' line='495' column='1'/> + <parameter type-id='type-id-247' name='shape' filepath='Objects/abstract.c' line='495' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_add_one_to_index_C' mangled-name='_Py_add_one_to_index_C' filepath='Objects/abstract.c' line='511' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_add_one_to_index_C'> + <parameter type-id='type-id-8' name='nd' filepath='Objects/abstract.c' line='511' column='1'/> + <parameter type-id='type-id-13' name='index' filepath='Objects/abstract.c' line='511' column='1'/> + <parameter type-id='type-id-247' name='shape' filepath='Objects/abstract.c' line='511' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyBuffer_SizeFromFormat' mangled-name='PyBuffer_SizeFromFormat' filepath='Objects/abstract.c' line='527' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_SizeFromFormat'> + <parameter type-id='type-id-12' name='format' filepath='Objects/abstract.c' line='527' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyBuffer_FromContiguous' mangled-name='PyBuffer_FromContiguous' filepath='Objects/abstract.c' line='562' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_FromContiguous'> + <parameter type-id='type-id-245' name='view' filepath='Objects/abstract.c' line='562' column='1'/> + <parameter type-id='type-id-22' name='buf' filepath='Objects/abstract.c' line='562' column='1'/> + <parameter type-id='type-id-14' name='len' filepath='Objects/abstract.c' line='562' column='1'/> + <parameter type-id='type-id-48' name='fort' filepath='Objects/abstract.c' line='562' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_CopyData' mangled-name='PyObject_CopyData' filepath='Objects/abstract.c' line='614' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CopyData'> + <parameter type-id='type-id-2' name='dest' filepath='Objects/abstract.c' line='614' column='1'/> + <parameter type-id='type-id-2' name='src' filepath='Objects/abstract.c' line='614' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyBuffer_FillContiguousStrides' mangled-name='PyBuffer_FillContiguousStrides' filepath='Objects/abstract.c' line='685' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_FillContiguousStrides'> + <parameter type-id='type-id-8' name='nd' filepath='Objects/abstract.c' line='685' column='1'/> + <parameter type-id='type-id-13' name='shape' filepath='Objects/abstract.c' line='685' column='1'/> + <parameter type-id='type-id-13' name='strides' filepath='Objects/abstract.c' line='686' column='1'/> + <parameter type-id='type-id-8' name='itemsize' filepath='Objects/abstract.c' line='686' column='1'/> + <parameter type-id='type-id-48' name='fort' filepath='Objects/abstract.c' line='687' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyBuffer_FillInfo' mangled-name='PyBuffer_FillInfo' filepath='Objects/abstract.c' line='709' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_FillInfo'> + <parameter type-id='type-id-254' name='view' filepath='Objects/abstract.c' line='709' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='709' column='1'/> + <parameter type-id='type-id-22' name='buf' filepath='Objects/abstract.c' line='709' column='1'/> + <parameter type-id='type-id-14' name='len' filepath='Objects/abstract.c' line='709' column='1'/> + <parameter type-id='type-id-8' name='readonly' filepath='Objects/abstract.c' line='710' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/abstract.c' line='710' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyBuffer_Release' mangled-name='PyBuffer_Release' filepath='Objects/abstract.c' line='746' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_Release'> + <parameter type-id='type-id-254' name='view' filepath='Objects/abstract.c' line='746' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_Format' mangled-name='PyObject_Format' filepath='Objects/abstract.c' line='761' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Format'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='761' column='1'/> + <parameter type-id='type-id-2' name='format_spec' filepath='Objects/abstract.c' line='761' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Check' mangled-name='PyNumber_Check' filepath='Objects/abstract.c' line='821' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Check'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='821' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyNumber_Or' mangled-name='PyNumber_Or' filepath='Objects/abstract.c' line='1051' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Or'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1051' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1051' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Xor' mangled-name='PyNumber_Xor' filepath='Objects/abstract.c' line='1052' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Xor'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1052' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1052' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_And' mangled-name='PyNumber_And' filepath='Objects/abstract.c' line='1053' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_And'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1053' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1053' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Lshift' mangled-name='PyNumber_Lshift' filepath='Objects/abstract.c' line='1054' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Lshift'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1054' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1054' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Rshift' mangled-name='PyNumber_Rshift' filepath='Objects/abstract.c' line='1055' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Rshift'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1055' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1055' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Subtract' mangled-name='PyNumber_Subtract' filepath='Objects/abstract.c' line='1056' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Subtract'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1056' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1056' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Divmod' mangled-name='PyNumber_Divmod' filepath='Objects/abstract.c' line='1057' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Divmod'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1057' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1057' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Add' mangled-name='PyNumber_Add' filepath='Objects/abstract.c' line='1060' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Add'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1060' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1060' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Multiply' mangled-name='PyNumber_Multiply' filepath='Objects/abstract.c' line='1098' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Multiply'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1098' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1098' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_MatrixMultiply' mangled-name='PyNumber_MatrixMultiply' filepath='Objects/abstract.c' line='1117' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_MatrixMultiply'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1117' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1117' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_FloorDivide' mangled-name='PyNumber_FloorDivide' filepath='Objects/abstract.c' line='1123' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_FloorDivide'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1123' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1123' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_TrueDivide' mangled-name='PyNumber_TrueDivide' filepath='Objects/abstract.c' line='1129' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_TrueDivide'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1129' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1129' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Remainder' mangled-name='PyNumber_Remainder' filepath='Objects/abstract.c' line='1135' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Remainder'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1135' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1135' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Power' mangled-name='PyNumber_Power' filepath='Objects/abstract.c' line='1141' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Power'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1141' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1141' column='1'/> + <parameter type-id='type-id-2' name='z' filepath='Objects/abstract.c' line='1141' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceOr' mangled-name='PyNumber_InPlaceOr' filepath='Objects/abstract.c' line='1236' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceOr'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1236' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1236' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceXor' mangled-name='PyNumber_InPlaceXor' filepath='Objects/abstract.c' line='1237' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceXor'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1237' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1237' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceAnd' mangled-name='PyNumber_InPlaceAnd' filepath='Objects/abstract.c' line='1238' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceAnd'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1238' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1238' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceLshift' mangled-name='PyNumber_InPlaceLshift' filepath='Objects/abstract.c' line='1239' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceLshift'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1239' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1239' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceRshift' mangled-name='PyNumber_InPlaceRshift' filepath='Objects/abstract.c' line='1240' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceRshift'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1240' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1240' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceSubtract' mangled-name='PyNumber_InPlaceSubtract' filepath='Objects/abstract.c' line='1241' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceSubtract'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1241' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1241' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceMatrixMultiply' mangled-name='PyNumber_InPlaceMatrixMultiply' filepath='Objects/abstract.c' line='1242' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceMatrixMultiply'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1242' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1242' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceFloorDivide' mangled-name='PyNumber_InPlaceFloorDivide' filepath='Objects/abstract.c' line='1243' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceFloorDivide'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1243' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1243' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceTrueDivide' mangled-name='PyNumber_InPlaceTrueDivide' filepath='Objects/abstract.c' line='1244' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceTrueDivide'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1244' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1244' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceRemainder' mangled-name='PyNumber_InPlaceRemainder' filepath='Objects/abstract.c' line='1245' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceRemainder'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1245' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1245' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceAdd' mangled-name='PyNumber_InPlaceAdd' filepath='Objects/abstract.c' line='1248' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceAdd'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1248' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1248' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlaceMultiply' mangled-name='PyNumber_InPlaceMultiply' filepath='Objects/abstract.c' line='1271' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlaceMultiply'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1271' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1271' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_InPlacePower' mangled-name='PyNumber_InPlacePower' filepath='Objects/abstract.c' line='1300' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_InPlacePower'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='1300' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='1300' column='1'/> + <parameter type-id='type-id-2' name='z' filepath='Objects/abstract.c' line='1300' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Negative' mangled-name='PyNumber_Negative' filepath='Objects/abstract.c' line='1316' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Negative'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1316' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Positive' mangled-name='PyNumber_Positive' filepath='Objects/abstract.c' line='1333' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Positive'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1333' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Invert' mangled-name='PyNumber_Invert' filepath='Objects/abstract.c' line='1350' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Invert'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1350' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Absolute' mangled-name='PyNumber_Absolute' filepath='Objects/abstract.c' line='1367' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Absolute'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1367' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyIndex_Check' mangled-name='PyIndex_Check' filepath='Objects/abstract.c' line='1385' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyIndex_Check'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='1385' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyNumber_Index' mangled-name='_PyNumber_Index' filepath='Objects/abstract.c' line='1397' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyNumber_Index'> + <parameter type-id='type-id-2' name='item' filepath='Objects/abstract.c' line='1397' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Index' mangled-name='PyNumber_Index' filepath='Objects/abstract.c' line='1443' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Index'> + <parameter type-id='type-id-2' name='item' filepath='Objects/abstract.c' line='1443' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_AsSsize_t' mangled-name='PyNumber_AsSsize_t' filepath='Objects/abstract.c' line='1455' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_AsSsize_t'> + <parameter type-id='type-id-2' name='item' filepath='Objects/abstract.c' line='1455' column='1'/> + <parameter type-id='type-id-2' name='err' filepath='Objects/abstract.c' line='1455' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyNumber_Long' mangled-name='PyNumber_Long' filepath='Objects/abstract.c' line='1506' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Long'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1506' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_Float' mangled-name='PyNumber_Float' filepath='Objects/abstract.c' line='1621' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_Float'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1621' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyNumber_ToBase' mangled-name='PyNumber_ToBase' filepath='Objects/abstract.c' line='1682' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyNumber_ToBase'> + <parameter type-id='type-id-2' name='n' filepath='Objects/abstract.c' line='1682' column='1'/> + <parameter type-id='type-id-8' name='base' filepath='Objects/abstract.c' line='1682' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_Check' mangled-name='PySequence_Check' filepath='Objects/abstract.c' line='1701' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Check'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1701' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_Size' mangled-name='PySequence_Size' filepath='Objects/abstract.c' line='1710' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Size'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1710' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PySequence_Length' mangled-name='PySequence_Length' filepath='Objects/abstract.c' line='1734' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Length'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1734' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PySequence_Concat' mangled-name='PySequence_Concat' filepath='Objects/abstract.c' line='1741' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Concat'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1741' column='1'/> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1741' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_Repeat' mangled-name='PySequence_Repeat' filepath='Objects/abstract.c' line='1767' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Repeat'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1767' column='1'/> + <parameter type-id='type-id-14' name='count' filepath='Objects/abstract.c' line='1767' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_InPlaceConcat' mangled-name='PySequence_InPlaceConcat' filepath='Objects/abstract.c' line='1798' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_InPlaceConcat'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1798' column='1'/> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1798' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_InPlaceRepeat' mangled-name='PySequence_InPlaceRepeat' filepath='Objects/abstract.c' line='1827' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_InPlaceRepeat'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1827' column='1'/> + <parameter type-id='type-id-14' name='count' filepath='Objects/abstract.c' line='1827' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_GetItem' mangled-name='PySequence_GetItem' filepath='Objects/abstract.c' line='1861' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_GetItem'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1861' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/abstract.c' line='1861' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_GetSlice' mangled-name='PySequence_GetSlice' filepath='Objects/abstract.c' line='1891' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_GetSlice'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1891' column='1'/> + <parameter type-id='type-id-14' name='i1' filepath='Objects/abstract.c' line='1891' column='1'/> + <parameter type-id='type-id-14' name='i2' filepath='Objects/abstract.c' line='1891' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_SetItem' mangled-name='PySequence_SetItem' filepath='Objects/abstract.c' line='1913' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_SetItem'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1913' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/abstract.c' line='1913' column='1'/> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1913' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_DelItem' mangled-name='PySequence_DelItem' filepath='Objects/abstract.c' line='1946' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_DelItem'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1946' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/abstract.c' line='1946' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_SetSlice' mangled-name='PySequence_SetSlice' filepath='Objects/abstract.c' line='1979' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_SetSlice'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='1979' column='1'/> + <parameter type-id='type-id-14' name='i1' filepath='Objects/abstract.c' line='1979' column='1'/> + <parameter type-id='type-id-14' name='i2' filepath='Objects/abstract.c' line='1979' column='1'/> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='1979' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_DelSlice' mangled-name='PySequence_DelSlice' filepath='Objects/abstract.c' line='2002' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_DelSlice'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='2002' column='1'/> + <parameter type-id='type-id-14' name='i1' filepath='Objects/abstract.c' line='2002' column='1'/> + <parameter type-id='type-id-14' name='i2' filepath='Objects/abstract.c' line='2002' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_Tuple' mangled-name='PySequence_Tuple' filepath='Objects/abstract.c' line='2025' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Tuple'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='2025' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_List' mangled-name='PySequence_List' filepath='Objects/abstract.c' line='2108' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_List'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='2108' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySequence_Fast' mangled-name='PySequence_Fast' filepath='Objects/abstract.c' line='2131' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Fast'> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='2131' column='1'/> + <parameter type-id='type-id-12' name='m' filepath='Objects/abstract.c' line='2131' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PySequence_IterSearch' mangled-name='_PySequence_IterSearch' filepath='Objects/abstract.c' line='2165' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySequence_IterSearch'> + <parameter type-id='type-id-2' name='seq' filepath='Objects/abstract.c' line='2165' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='2165' column='1'/> + <parameter type-id='type-id-8' name='operation' filepath='Objects/abstract.c' line='2165' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PySequence_Count' mangled-name='PySequence_Count' filepath='Objects/abstract.c' line='2250' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Count'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='2250' column='1'/> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2250' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PySequence_Contains' mangled-name='PySequence_Contains' filepath='Objects/abstract.c' line='2259' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Contains'> + <parameter type-id='type-id-2' name='seq' filepath='Objects/abstract.c' line='2259' column='1'/> + <parameter type-id='type-id-2' name='ob' filepath='Objects/abstract.c' line='2259' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_In' mangled-name='PySequence_In' filepath='Objects/abstract.c' line='2274' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_In'> + <parameter type-id='type-id-2' name='w' filepath='Objects/abstract.c' line='2274' column='1'/> + <parameter type-id='type-id-2' name='v' filepath='Objects/abstract.c' line='2274' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySequence_Index' mangled-name='PySequence_Index' filepath='Objects/abstract.c' line='2280' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySequence_Index'> + <parameter type-id='type-id-2' name='s' filepath='Objects/abstract.c' line='2280' column='1'/> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2280' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyMapping_Check' mangled-name='PyMapping_Check' filepath='Objects/abstract.c' line='2288' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_Check'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2288' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyMapping_Size' mangled-name='PyMapping_Size' filepath='Objects/abstract.c' line='2295' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_Size'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2295' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyMapping_Length' mangled-name='PyMapping_Length' filepath='Objects/abstract.c' line='2320' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_Length'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2320' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyMapping_GetItemString' mangled-name='PyMapping_GetItemString' filepath='Objects/abstract.c' line='2327' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_GetItemString'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2327' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/abstract.c' line='2327' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMapping_SetItemString' mangled-name='PyMapping_SetItemString' filepath='Objects/abstract.c' line='2344' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_SetItemString'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2344' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/abstract.c' line='2344' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Objects/abstract.c' line='2344' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyMapping_HasKeyString' mangled-name='PyMapping_HasKeyString' filepath='Objects/abstract.c' line='2363' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_HasKeyString'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2363' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/abstract.c' line='2363' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyMapping_HasKey' mangled-name='PyMapping_HasKey' filepath='Objects/abstract.c' line='2377' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_HasKey'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2377' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/abstract.c' line='2377' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyMapping_Keys' mangled-name='PyMapping_Keys' filepath='Objects/abstract.c' line='2423' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_Keys'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2423' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMapping_Items' mangled-name='PyMapping_Items' filepath='Objects/abstract.c' line='2435' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_Items'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2435' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMapping_Values' mangled-name='PyMapping_Values' filepath='Objects/abstract.c' line='2447' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMapping_Values'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2447' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_IsInstance' mangled-name='PyObject_IsInstance' filepath='Objects/abstract.c' line='2667' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_IsInstance'> + <parameter type-id='type-id-2' name='inst' filepath='Objects/abstract.c' line='2667' column='1'/> + <parameter type-id='type-id-2' name='cls' filepath='Objects/abstract.c' line='2667' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_IsSubclass' mangled-name='PyObject_IsSubclass' filepath='Objects/abstract.c' line='2755' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_IsSubclass'> + <parameter type-id='type-id-2' name='derived' filepath='Objects/abstract.c' line='2755' column='1'/> + <parameter type-id='type-id-2' name='cls' filepath='Objects/abstract.c' line='2755' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_RealIsInstance' mangled-name='_PyObject_RealIsInstance' filepath='Objects/abstract.c' line='2763' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_RealIsInstance'> + <parameter type-id='type-id-2' name='inst' filepath='Objects/abstract.c' line='2763' column='1'/> + <parameter type-id='type-id-2' name='cls' filepath='Objects/abstract.c' line='2763' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_RealIsSubclass' mangled-name='_PyObject_RealIsSubclass' filepath='Objects/abstract.c' line='2769' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_RealIsSubclass'> + <parameter type-id='type-id-2' name='derived' filepath='Objects/abstract.c' line='2769' column='1'/> + <parameter type-id='type-id-2' name='cls' filepath='Objects/abstract.c' line='2769' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GetIter' mangled-name='PyObject_GetIter' filepath='Objects/abstract.c' line='2776' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetIter'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2776' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GetAIter' mangled-name='PyObject_GetAIter' filepath='Objects/abstract.c' line='2801' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetAIter'> + <parameter type-id='type-id-2' name='o' filepath='Objects/abstract.c' line='2801' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyIter_Check' mangled-name='PyIter_Check' filepath='Objects/abstract.c' line='2820' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyIter_Check'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='2820' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyAIter_Check' mangled-name='PyAIter_Check' filepath='Objects/abstract.c' line='2828' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyAIter_Check'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/abstract.c' line='2828' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyIter_Next' mangled-name='PyIter_Next' filepath='Objects/abstract.c' line='2844' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyIter_Next'> + <parameter type-id='type-id-2' name='iter' filepath='Objects/abstract.c' line='2844' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyIter_Send' mangled-name='PyIter_Send' filepath='Objects/abstract.c' line='2860' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyIter_Send'> + <parameter type-id='type-id-2' name='iter' filepath='Objects/abstract.c' line='2860' column='1'/> + <parameter type-id='type-id-2' name='arg' filepath='Objects/abstract.c' line='2860' column='1'/> + <parameter type-id='type-id-233' name='result' filepath='Objects/abstract.c' line='2860' column='1'/> + <return type-id='type-id-255'/> + </function-decl> + <function-decl name='_PySequence_BytesToCharpArray' mangled-name='_PySequence_BytesToCharpArray' filepath='Objects/abstract.c' line='2893' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySequence_BytesToCharpArray'> + <parameter type-id='type-id-2' name='self' filepath='Objects/abstract.c' line='2893' column='1'/> + <return type-id='type-id-136'/> + </function-decl> + <function-decl name='_Py_FreeCharPArray' mangled-name='_Py_FreeCharPArray' filepath='Objects/abstract.c' line='2952' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_FreeCharPArray'> + <parameter type-id='type-id-136' name='array' filepath='Objects/abstract.c' line='2952' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <pointer-type-def type-id='type-id-22' size-in-bits='64' id='type-id-253'/> + </abi-instr> + <abi-instr address-size='64' path='Objects/boolobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_Py_FalseStruct' type-id='type-id-240' mangled-name='_Py_FalseStruct' visibility='default' filepath='./Include/boolobject.h' line='17' column='1' elf-symbol-id='_Py_FalseStruct'/> + <var-decl name='_Py_TrueStruct' type-id='type-id-240' mangled-name='_Py_TrueStruct' visibility='default' filepath='./Include/boolobject.h' line='18' column='1' elf-symbol-id='_Py_TrueStruct'/> + <function-decl name='_PyArg_NoKeywords' mangled-name='_PyArg_NoKeywords' filepath='./Include/cpython/modsupport.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_NoKeywords'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_NoKwnames' mangled-name='_PyArg_NoKwnames' filepath='./Include/cpython/modsupport.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_NoKwnames'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_CheckPositional' mangled-name='_PyArg_CheckPositional' filepath='./Include/cpython/modsupport.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_CheckPositional'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyArg_UnpackTuple' mangled-name='PyArg_UnpackTuple' filepath='./Include/modsupport.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_UnpackTuple'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyBool_Type' type-id='type-id-256' mangled-name='PyBool_Type' visibility='default' filepath='./Include/object.h' line='211' column='1' elf-symbol-id='PyBool_Type'/> + <function-decl name='PyBool_FromLong' mangled-name='PyBool_FromLong' filepath='Objects/boolobject.c' line='21' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBool_FromLong'> + <parameter type-id='type-id-47' name='ok' filepath='Objects/boolobject.c' line='21' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/bytearrayobject.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='infinite' id='type-id-257'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <qualified-type-def type-id='type-id-258' const='yes' id='type-id-259'/> + <pointer-type-def type-id='type-id-259' size-in-bits='64' id='type-id-260'/> + <qualified-type-def type-id='type-id-8' const='yes' id='type-id-261'/> + <var-decl name='PyByteArray_Type' type-id='type-id-256' mangled-name='PyByteArray_Type' visibility='default' filepath='./Include/bytearrayobject.h' line='20' column='1' elf-symbol-id='PyByteArray_Type'/> + <var-decl name='PyByteArrayIter_Type' type-id='type-id-256' mangled-name='PyByteArrayIter_Type' visibility='default' filepath='./Include/bytearrayobject.h' line='21' column='1' elf-symbol-id='PyByteArrayIter_Type'/> + <var-decl name='_PyByteArray_empty_string' type-id='type-id-257' mangled-name='_PyByteArray_empty_string' visibility='default' filepath='./Include/cpython/bytearrayobject.h' line='14' column='1' elf-symbol-id='_PyByteArray_empty_string'/> + <function-decl name='_PyBytes_FormatEx' mangled-name='_PyBytes_FormatEx' filepath='./Include/cpython/bytesobject.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_FormatEx'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyBytes_FromHex' mangled-name='_PyBytes_FromHex' filepath='./Include/cpython/bytesobject.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_FromHex'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyEval_GetBuiltin' mangled-name='_PyEval_GetBuiltin' filepath='./Include/cpython/ceval.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_GetBuiltin'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_AsInt' mangled-name='_PyLong_AsInt' filepath='./Include/cpython/longobject.h' line='5' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_AsInt'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_BadArgument' mangled-name='_PyArg_BadArgument' filepath='./Include/cpython/modsupport.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_BadArgument'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyArg_UnpackKeywords' mangled-name='_PyArg_UnpackKeywords' filepath='./Include/cpython/modsupport.h' line='88' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_UnpackKeywords'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-262'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-248'/> + </function-decl> + <function-decl name='_Py_GetConfig' mangled-name='_Py_GetConfig' filepath='./Include/cpython/pystate.h' line='367' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetConfig'> + <return type-id='type-id-260'/> + </function-decl> + <function-decl name='_Py_bytes_isspace' filepath='./Include/internal/pycore_bytes_methods.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_isalpha' filepath='./Include/internal/pycore_bytes_methods.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_isalnum' filepath='./Include/internal/pycore_bytes_methods.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_isascii' filepath='./Include/internal/pycore_bytes_methods.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_isdigit' filepath='./Include/internal/pycore_bytes_methods.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_islower' filepath='./Include/internal/pycore_bytes_methods.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_isupper' filepath='./Include/internal/pycore_bytes_methods.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_istitle' filepath='./Include/internal/pycore_bytes_methods.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_lower' filepath='./Include/internal/pycore_bytes_methods.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_bytes_upper' filepath='./Include/internal/pycore_bytes_methods.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_bytes_title' filepath='./Include/internal/pycore_bytes_methods.h' line='25' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_bytes_capitalize' filepath='./Include/internal/pycore_bytes_methods.h' line='26' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_bytes_swapcase' filepath='./Include/internal/pycore_bytes_methods.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_bytes_find' filepath='./Include/internal/pycore_bytes_methods.h' line='29' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_index' filepath='./Include/internal/pycore_bytes_methods.h' line='30' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_rfind' filepath='./Include/internal/pycore_bytes_methods.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_rindex' filepath='./Include/internal/pycore_bytes_methods.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_count' filepath='./Include/internal/pycore_bytes_methods.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_contains' filepath='./Include/internal/pycore_bytes_methods.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_bytes_startswith' filepath='./Include/internal/pycore_bytes_methods.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_endswith' filepath='./Include/internal/pycore_bytes_methods.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_bytes_maketrans' filepath='./Include/internal/pycore_bytes_methods.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-254'/> + <parameter type-id='type-id-254'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyBytes_Repeat' mangled-name='_PyBytes_Repeat' filepath='./Include/internal/pycore_bytesobject.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_Repeat'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_strhex_with_sep' mangled-name='_Py_strhex_with_sep' filepath='./Include/internal/pycore_strhex.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_strhex_with_sep'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-246'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-261'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyList_Append' mangled-name='PyList_Append' filepath='./Include/listobject.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_Append'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyList_Reverse' mangled-name='PyList_Reverse' filepath='./Include/listobject.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_Reverse'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyLong_FromSize_t' mangled-name='PyLong_FromSize_t' filepath='./Include/longobject.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromSize_t'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_AsLongAndOverflow' mangled-name='PyLong_AsLongAndOverflow' filepath='./Include/longobject.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsLongAndOverflow'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='PyType_GenericAlloc' mangled-name='PyType_GenericAlloc' filepath='./Include/object.h' line='379' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GenericAlloc'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_GenericNew' mangled-name='PyType_GenericNew' filepath='./Include/object.h' line='380' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GenericNew'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_SelfIter' mangled-name='PyObject_SelfIter' filepath='./Include/object.h' line='398' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_SelfIter'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GenericGetAttr' mangled-name='PyObject_GenericGetAttr' filepath='./Include/object.h' line='399' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GenericGetAttr'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_GetState' mangled-name='_PyObject_GetState' filepath='./Include/object.h' line='420' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetState'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Malloc' mangled-name='PyObject_Malloc' filepath='./Include/objimpl.h' line='97' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Malloc'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyObject_Realloc' mangled-name='PyObject_Realloc' filepath='./Include/objimpl.h' line='101' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Realloc'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyObject_Free' mangled-name='PyObject_Free' filepath='./Include/objimpl.h' line='102' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Free'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_New' mangled-name='_PyObject_New' filepath='./Include/objimpl.h' line='131' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_New'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_GC_New' mangled-name='_PyObject_GC_New' filepath='./Include/objimpl.h' line='188' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GC_New'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GC_Del' mangled-name='PyObject_GC_Del' filepath='./Include/objimpl.h' line='201' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GC_Del'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyBuffer_ToContiguous' mangled-name='PyBuffer_ToContiguous' filepath='./Include/pybuffer.h' line='58' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBuffer_ToContiguous'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-245'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-48'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_Print' mangled-name='PyErr_Print' filepath='./Include/pythonrun.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Print'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySlice_Unpack' mangled-name='PySlice_Unpack' filepath='./Include/sliceobject.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySlice_Unpack'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySlice_AdjustIndices' mangled-name='PySlice_AdjustIndices' filepath='./Include/sliceobject.h' line='57' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySlice_AdjustIndices'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_FromEncodedObject' mangled-name='PyUnicode_FromEncodedObject' filepath='./Include/unicodeobject.h' line='226' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromEncodedObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_GetDefaultEncoding' mangled-name='PyUnicode_GetDefaultEncoding' filepath='./Include/unicodeobject.h' line='338' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_GetDefaultEncoding'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyUnicode_AsEncodedString' mangled-name='PyUnicode_AsEncodedString' filepath='./Include/unicodeobject.h' line='395' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsEncodedString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeLatin1' mangled-name='PyUnicode_DecodeLatin1' filepath='./Include/unicodeobject.h' line='617' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeLatin1'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='memmove' filepath='/usr/include/string.h' line='47' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='memset' filepath='/usr/include/string.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyByteArray_FromObject' mangled-name='PyByteArray_FromObject' filepath='Objects/bytearrayobject.c' line='83' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyByteArray_FromObject'> + <parameter type-id='type-id-2' name='input' filepath='Objects/bytearrayobject.c' line='83' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyByteArray_FromStringAndSize' mangled-name='PyByteArray_FromStringAndSize' filepath='Objects/bytearrayobject.c' line='109' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyByteArray_FromStringAndSize'> + <parameter type-id='type-id-12' name='bytes' filepath='Objects/bytearrayobject.c' line='109' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/bytearrayobject.c' line='109' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyByteArray_Size' mangled-name='PyByteArray_Size' filepath='Objects/bytearrayobject.c' line='153' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyByteArray_Size'> + <parameter type-id='type-id-2' name='self' filepath='Objects/bytearrayobject.c' line='153' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyByteArray_AsString' mangled-name='PyByteArray_AsString' filepath='Objects/bytearrayobject.c' line='162' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyByteArray_AsString'> + <parameter type-id='type-id-2' name='self' filepath='Objects/bytearrayobject.c' line='162' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyByteArray_Resize' mangled-name='PyByteArray_Resize' filepath='Objects/bytearrayobject.c' line='171' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyByteArray_Resize'> + <parameter type-id='type-id-2' name='self' filepath='Objects/bytearrayobject.c' line='171' column='1'/> + <parameter type-id='type-id-14' name='requested_size' filepath='Objects/bytearrayobject.c' line='171' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyByteArray_Concat' mangled-name='PyByteArray_Concat' filepath='Objects/bytearrayobject.c' line='250' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyByteArray_Concat'> + <parameter type-id='type-id-2' name='a' filepath='Objects/bytearrayobject.c' line='250' column='1'/> + <parameter type-id='type-id-2' name='b' filepath='Objects/bytearrayobject.c' line='250' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/bytes_methods.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='984' id='type-id-263'> + <subrange length='123' type-id='type-id-28' id='type-id-264'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='992' id='type-id-265'> + <subrange length='124' type-id='type-id-28' id='type-id-266'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1008' id='type-id-267'> + <subrange length='126' type-id='type-id-28' id='type-id-268'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1040' id='type-id-269'> + <subrange length='130' type-id='type-id-28' id='type-id-270'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1056' id='type-id-271'> + <subrange length='132' type-id='type-id-28' id='type-id-272'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1128' id='type-id-273'> + <subrange length='141' type-id='type-id-28' id='type-id-274'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1240' id='type-id-275'> + <subrange length='155' type-id='type-id-28' id='type-id-276'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1592' id='type-id-277'> + <subrange length='199' type-id='type-id-28' id='type-id-278'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1840' id='type-id-279'> + <subrange length='230' type-id='type-id-28' id='type-id-280'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1912' id='type-id-281'> + <subrange length='239' type-id='type-id-28' id='type-id-282'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='1928' id='type-id-283'> + <subrange length='241' type-id='type-id-28' id='type-id-284'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='2112' id='type-id-285'> + <subrange length='264' type-id='type-id-28' id='type-id-286'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='2144' id='type-id-287'> + <subrange length='268' type-id='type-id-28' id='type-id-288'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='2160' id='type-id-289'> + <subrange length='270' type-id='type-id-28' id='type-id-290'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='2168' id='type-id-291'> + <subrange length='271' type-id='type-id-28' id='type-id-292'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='2328' id='type-id-293'> + <subrange length='291' type-id='type-id-28' id='type-id-294'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='744' id='type-id-295'> + <subrange length='93' type-id='type-id-28' id='type-id-296'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='784' id='type-id-297'> + <subrange length='98' type-id='type-id-28' id='type-id-298'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-50' size-in-bits='infinite' id='type-id-299'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <function-decl name='_PyEval_SliceIndex' mangled-name='_PyEval_SliceIndex' filepath='./Include/cpython/ceval.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SliceIndex'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='_Py_isspace__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='42' column='1'/> + <var-decl name='_Py_isalpha__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='43' column='1'/> + <var-decl name='_Py_isalnum__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='44' column='1'/> + <var-decl name='_Py_isascii__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='45' column='1'/> + <var-decl name='_Py_isdigit__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='46' column='1'/> + <var-decl name='_Py_islower__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='47' column='1'/> + <var-decl name='_Py_isupper__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='48' column='1'/> + <var-decl name='_Py_istitle__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='49' column='1'/> + <var-decl name='_Py_lower__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='50' column='1'/> + <var-decl name='_Py_upper__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='51' column='1'/> + <var-decl name='_Py_title__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='52' column='1'/> + <var-decl name='_Py_capitalize__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='53' column='1'/> + <var-decl name='_Py_swapcase__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='54' column='1'/> + <var-decl name='_Py_count__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='55' column='1'/> + <var-decl name='_Py_find__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='56' column='1'/> + <var-decl name='_Py_index__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='57' column='1'/> + <var-decl name='_Py_rfind__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='58' column='1'/> + <var-decl name='_Py_rindex__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='59' column='1'/> + <var-decl name='_Py_startswith__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='60' column='1'/> + <var-decl name='_Py_endswith__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='61' column='1'/> + <var-decl name='_Py_maketrans__doc__' type-id='type-id-299' visibility='default' filepath='./Include/internal/pycore_bytes_methods.h' line='62' column='1'/> + <function-decl name='_PyArg_ParseTuple_SizeT' mangled-name='_PyArg_ParseTuple_SizeT' filepath='./Include/modsupport.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseTuple_SizeT'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='memrchr' filepath='/usr/include/string.h' line='133' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/bytesobject.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='4096' id='type-id-300'> + <subrange length='512' type-id='type-id-28' id='type-id-301'/> + </array-type-def> + <class-decl name='_PyBytesWriter' size-in-bits='4416' is-struct='yes' naming-typedef-id='type-id-302' visibility='default' filepath='./Include/cpython/bytesobject.h' line='55' column='1' id='type-id-303'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='buffer' type-id='type-id-2' visibility='default' filepath='./Include/cpython/bytesobject.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='allocated' type-id='type-id-14' visibility='default' filepath='./Include/cpython/bytesobject.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='min_size' type-id='type-id-14' visibility='default' filepath='./Include/cpython/bytesobject.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='use_bytearray' type-id='type-id-8' visibility='default' filepath='./Include/cpython/bytesobject.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='overallocate' type-id='type-id-8' visibility='default' filepath='./Include/cpython/bytesobject.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='use_small_buffer' type-id='type-id-8' visibility='default' filepath='./Include/cpython/bytesobject.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='small_buffer' type-id='type-id-300' visibility='default' filepath='./Include/cpython/bytesobject.h' line='75' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyBytesWriter' type-id='type-id-303' filepath='./Include/cpython/bytesobject.h' line='76' column='1' id='type-id-302'/> + <pointer-type-def type-id='type-id-302' size-in-bits='64' id='type-id-304'/> + <var-decl name='PyBytes_Type' type-id='type-id-256' mangled-name='PyBytes_Type' visibility='default' filepath='./Include/bytesobject.h' line='27' column='1' elf-symbol-id='PyBytes_Type'/> + <var-decl name='PyBytesIter_Type' type-id='type-id-256' mangled-name='PyBytesIter_Type' visibility='default' filepath='./Include/bytesobject.h' line='28' column='1' elf-symbol-id='PyBytesIter_Type'/> + <function-decl name='_Py_NewReference' mangled-name='_Py_NewReference' filepath='./Include/cpython/object.h' line='5' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_NewReference'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_NewReferenceNoTotal' mangled-name='_Py_NewReferenceNoTotal' filepath='./Include/cpython/object.h' line='6' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_NewReferenceNoTotal'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_FormatLong' mangled-name='_PyUnicode_FormatLong' filepath='./Include/cpython/unicodeobject.h' line='946' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FormatLong'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFloat_AsDouble' mangled-name='PyFloat_AsDouble' filepath='./Include/floatobject.h' line='43' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_AsDouble'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='_PyLong_FormatBytesWriter' mangled-name='_PyLong_FormatBytesWriter' filepath='./Include/internal/pycore_long.h' line='104' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FormatBytesWriter'> + <parameter type-id='type-id-304'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyObject_ASCII' mangled-name='PyObject_ASCII' filepath='./Include/object.h' line='388' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_ASCII'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Calloc' mangled-name='PyObject_Calloc' filepath='./Include/objimpl.h' line='99' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Calloc'> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyErr_BadArgument' mangled-name='PyErr_BadArgument' filepath='./Include/pyerrors.h' line='168' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_BadArgument'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_HashBytes' mangled-name='_Py_HashBytes' filepath='./Include/pyhash.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_HashBytes'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-305'/> + </function-decl> + <function-decl name='PyOS_double_to_string' mangled-name='PyOS_double_to_string' filepath='./Include/pystrtod.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_double_to_string'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-48'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyTuple_GetItem' mangled-name='PyTuple_GetItem' filepath='./Include/tupleobject.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTuple_GetItem'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_FromFormatV' mangled-name='PyBytes_FromFormatV' filepath='Objects/bytesobject.c' line='181' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_FromFormatV'> + <parameter type-id='type-id-12' name='format' filepath='Objects/bytesobject.c' line='181' column='1'/> + <parameter type-id='type-id-306' name='vargs' filepath='Objects/bytesobject.c' line='181' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_FromFormat' mangled-name='PyBytes_FromFormat' filepath='Objects/bytesobject.c' line='372' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_FromFormat'> + <parameter type-id='type-id-12' name='format' filepath='Objects/bytesobject.c' line='372' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_DecodeEscape' mangled-name='PyBytes_DecodeEscape' filepath='Objects/bytesobject.c' line='1165' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_DecodeEscape'> + <parameter type-id='type-id-12' name='s' filepath='Objects/bytesobject.c' line='1165' column='1'/> + <parameter type-id='type-id-14' name='len' filepath='Objects/bytesobject.c' line='1166' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/bytesobject.c' line='1167' column='1'/> + <parameter type-id='type-id-14' name='_unused_unicode' filepath='Objects/bytesobject.c' line='1168' column='1'/> + <parameter type-id='type-id-12' name='_unused_recode_encoding' filepath='Objects/bytesobject.c' line='1169' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_Size' mangled-name='PyBytes_Size' filepath='Objects/bytesobject.c' line='1204' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_Size'> + <parameter type-id='type-id-2' name='op' filepath='Objects/bytesobject.c' line='1204' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyBytes_Find' mangled-name='_PyBytes_Find' filepath='Objects/bytesobject.c' line='1273' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_Find'> + <parameter type-id='type-id-12' name='haystack' filepath='Objects/bytesobject.c' line='1273' column='1'/> + <parameter type-id='type-id-14' name='len_haystack' filepath='Objects/bytesobject.c' line='1273' column='1'/> + <parameter type-id='type-id-12' name='needle' filepath='Objects/bytesobject.c' line='1274' column='1'/> + <parameter type-id='type-id-14' name='len_needle' filepath='Objects/bytesobject.c' line='1274' column='1'/> + <parameter type-id='type-id-14' name='offset' filepath='Objects/bytesobject.c' line='1275' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyBytes_ReverseFind' mangled-name='_PyBytes_ReverseFind' filepath='Objects/bytesobject.c' line='1282' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_ReverseFind'> + <parameter type-id='type-id-12' name='haystack' filepath='Objects/bytesobject.c' line='1282' column='1'/> + <parameter type-id='type-id-14' name='len_haystack' filepath='Objects/bytesobject.c' line='1282' column='1'/> + <parameter type-id='type-id-12' name='needle' filepath='Objects/bytesobject.c' line='1283' column='1'/> + <parameter type-id='type-id-14' name='len_needle' filepath='Objects/bytesobject.c' line='1283' column='1'/> + <parameter type-id='type-id-14' name='offset' filepath='Objects/bytesobject.c' line='1284' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyBytes_Repr' mangled-name='PyBytes_Repr' filepath='Objects/bytesobject.c' line='1291' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_Repr'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/bytesobject.c' line='1291' column='1'/> + <parameter type-id='type-id-8' name='smartquotes' filepath='Objects/bytesobject.c' line='1291' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyBytes_Join' mangled-name='_PyBytes_Join' filepath='Objects/bytesobject.c' line='1846' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_Join'> + <parameter type-id='type-id-2' name='sep' filepath='Objects/bytesobject.c' line='1846' column='1'/> + <parameter type-id='type-id-2' name='x' filepath='Objects/bytesobject.c' line='1846' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_FromObject' mangled-name='PyBytes_FromObject' filepath='Objects/bytesobject.c' line='2818' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_FromObject'> + <parameter type-id='type-id-2' name='x' filepath='Objects/bytesobject.c' line='2818' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_ConcatAndDel' mangled-name='PyBytes_ConcatAndDel' filepath='Objects/bytesobject.c' line='3009' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_ConcatAndDel'> + <parameter type-id='type-id-233' name='pv' filepath='Objects/bytesobject.c' line='3009' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/bytesobject.c' line='3009' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyBytes_Resize' mangled-name='_PyBytes_Resize' filepath='Objects/bytesobject.c' line='3031' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_Resize'> + <parameter type-id='type-id-233' name='pv' filepath='Objects/bytesobject.c' line='3031' column='1'/> + <parameter type-id='type-id-14' name='newsize' filepath='Objects/bytesobject.c' line='3031' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyBytesWriter_Init' mangled-name='_PyBytesWriter_Init' filepath='Objects/bytesobject.c' line='3254' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_Init'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3254' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyBytesWriter_Dealloc' mangled-name='_PyBytesWriter_Dealloc' filepath='Objects/bytesobject.c' line='3265' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_Dealloc'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3265' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyBytesWriter_Resize' mangled-name='_PyBytesWriter_Resize' filepath='Objects/bytesobject.c' line='3335' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_Resize'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3335' column='1'/> + <parameter type-id='type-id-22' name='str' filepath='Objects/bytesobject.c' line='3335' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/bytesobject.c' line='3335' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyBytesWriter_Prepare' mangled-name='_PyBytesWriter_Prepare' filepath='Objects/bytesobject.c' line='3405' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_Prepare'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3405' column='1'/> + <parameter type-id='type-id-22' name='str' filepath='Objects/bytesobject.c' line='3405' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/bytesobject.c' line='3405' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyBytesWriter_Alloc' mangled-name='_PyBytesWriter_Alloc' filepath='Objects/bytesobject.c' line='3435' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_Alloc'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3435' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/bytesobject.c' line='3435' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyBytesWriter_Finish' mangled-name='_PyBytesWriter_Finish' filepath='Objects/bytesobject.c' line='3465' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_Finish'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3465' column='1'/> + <parameter type-id='type-id-22' name='str' filepath='Objects/bytesobject.c' line='3465' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyBytesWriter_WriteBytes' mangled-name='_PyBytesWriter_WriteBytes' filepath='Objects/bytesobject.c' line='3509' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytesWriter_WriteBytes'> + <parameter type-id='type-id-304' name='writer' filepath='Objects/bytesobject.c' line='3509' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/bytesobject.c' line='3509' column='1'/> + <parameter type-id='type-id-22' name='bytes' filepath='Objects/bytesobject.c' line='3510' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/bytesobject.c' line='3510' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/call.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='_Py_Identifier' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/cpython/object.h' line='42' column='1' id='type-id-307'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='string' type-id='type-id-12' visibility='default' filepath='./Include/cpython/object.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='index' type-id='type-id-14' visibility='default' filepath='./Include/cpython/object.h' line='46' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_Identifier' type-id='type-id-307' filepath='./Include/cpython/object.h' line='47' column='1' id='type-id-308'/> + <pointer-type-def type-id='type-id-308' size-in-bits='64' id='type-id-309'/> + <function-decl name='_Py_VaBuildStack_SizeT' mangled-name='_Py_VaBuildStack_SizeT' filepath='./Include/cpython/modsupport.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_VaBuildStack_SizeT'> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-306'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-233'/> + </function-decl> + <function-decl name='_Py_VaBuildStack' mangled-name='_Py_VaBuildStack' filepath='./Include/cpython/modsupport.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_VaBuildStack'> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-306'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-233'/> + </function-decl> + <function-decl name='_PyObject_GetAttrId' mangled-name='_PyObject_GetAttrId' filepath='./Include/cpython/object.h' line='293' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetAttrId'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-309'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_GetMethod' mangled-name='_PyObject_GetMethod' filepath='./Include/cpython/object.h' line='307' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetMethod'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_FatalErrorFormat' mangled-name='_Py_FatalErrorFormat' filepath='./Include/cpython/pyerrors.h' line='162' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_FatalErrorFormat'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_FromId' mangled-name='_PyUnicode_FromId' filepath='./Include/cpython/unicodeobject.h' line='949' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FromId'> + <parameter type-id='type-id-309'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_Next' mangled-name='PyDict_Next' filepath='./Include/dictobject.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Next'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_Vector' filepath='./Include/internal/pycore_ceval.h' line='93' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-310'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_FromItems' filepath='./Include/internal/pycore_dict.h' line='179' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_NoMemory' mangled-name='_PyErr_NoMemory' filepath='./Include/internal/pycore_pyerrors.h' line='71' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_NoMemory'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_FormatFromCauseTstate' mangled-name='_PyErr_FormatFromCauseTstate' filepath='./Include/internal/pycore_pyerrors.h' line='90' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_FormatFromCauseTstate'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTuple_FromArray' filepath='./Include/internal/pycore_tuple.h' line='66' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_GetNameObject' mangled-name='PyModule_GetNameObject' filepath='./Include/moduleobject.h' line='25' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetNameObject'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GetAttrString' mangled-name='PyObject_GetAttrString' filepath='./Include/object.h' line='392' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetAttrString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCallable_Check' mangled-name='PyCallable_Check' filepath='./Include/object.h' line='408' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCallable_Check'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_FastCallDictTstate' mangled-name='_PyObject_FastCallDictTstate' filepath='Objects/call.c' line='109' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_FastCallDictTstate'> + <parameter type-id='type-id-177' name='tstate' filepath='Objects/call.c' line='109' column='1'/> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='109' column='1'/> + <parameter type-id='type-id-248' name='args' filepath='Objects/call.c' line='110' column='1'/> + <parameter type-id='type-id-19' name='nargsf' filepath='Objects/call.c' line='110' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='111' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_VectorcallDict' mangled-name='PyObject_VectorcallDict' filepath='Objects/call.c' line='153' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_VectorcallDict'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='153' column='1'/> + <parameter type-id='type-id-248' name='args' filepath='Objects/call.c' line='153' column='1'/> + <parameter type-id='type-id-19' name='nargsf' filepath='Objects/call.c' line='154' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='154' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyVectorcall_Function' mangled-name='PyVectorcall_Function' filepath='Objects/call.c' line='255' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyVectorcall_Function'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='255' column='1'/> + <return type-id='type-id-311'/> + </function-decl> + <function-decl name='PyVectorcall_Call' mangled-name='PyVectorcall_Call' filepath='Objects/call.c' line='292' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyVectorcall_Call'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='292' column='1'/> + <parameter type-id='type-id-2' name='tuple' filepath='Objects/call.c' line='292' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='292' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Vectorcall' mangled-name='PyObject_Vectorcall' filepath='Objects/call.c' line='321' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Vectorcall'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='321' column='1'/> + <parameter type-id='type-id-248' name='args' filepath='Objects/call.c' line='321' column='1'/> + <parameter type-id='type-id-19' name='nargsf' filepath='Objects/call.c' line='322' column='1'/> + <parameter type-id='type-id-2' name='kwnames' filepath='Objects/call.c' line='322' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_Call' mangled-name='_PyObject_Call' filepath='Objects/call.c' line='339' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_Call'> + <parameter type-id='type-id-177' name='tstate' filepath='Objects/call.c' line='339' column='1'/> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='339' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/call.c' line='340' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='340' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Call' mangled-name='PyObject_Call' filepath='Objects/call.c' line='376' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Call'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='376' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/call.c' line='376' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='376' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCFunction_Call' mangled-name='PyCFunction_Call' filepath='Objects/call.c' line='384' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCFunction_Call'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='384' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/call.c' line='384' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='384' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyFunction_Vectorcall' mangled-name='_PyFunction_Vectorcall' filepath='Objects/call.c' line='408' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyFunction_Vectorcall'> + <parameter type-id='type-id-2' name='func' filepath='Objects/call.c' line='408' column='1'/> + <parameter type-id='type-id-248' name='stack' filepath='Objects/call.c' line='408' column='1'/> + <parameter type-id='type-id-19' name='nargsf' filepath='Objects/call.c' line='409' column='1'/> + <parameter type-id='type-id-2' name='kwnames' filepath='Objects/call.c' line='409' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_CallObjectWithKeywords' mangled-name='PyEval_CallObjectWithKeywords' filepath='Objects/call.c' line='431' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_CallObjectWithKeywords'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='431' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/call.c' line='432' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='432' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_CallObject' mangled-name='PyObject_CallObject' filepath='Objects/call.c' line='464' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallObject'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='464' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/call.c' line='464' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_Call_Prepend' mangled-name='_PyObject_Call_Prepend' filepath='Objects/call.c' line='482' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_Call_Prepend'> + <parameter type-id='type-id-177' name='tstate' filepath='Objects/call.c' line='482' column='1'/> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='482' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='483' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/call.c' line='483' column='1'/> + <parameter type-id='type-id-2' name='kwargs' filepath='Objects/call.c' line='483' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_CallFunction' mangled-name='PyObject_CallFunction' filepath='Objects/call.c' line='577' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallFunction'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='577' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='577' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_CallFunction' mangled-name='PyEval_CallFunction' filepath='Objects/call.c' line='595' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_CallFunction'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/call.c' line='595' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='595' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_CallMethod' mangled-name='PyObject_CallMethod' filepath='Objects/call.c' line='638' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallMethod'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='638' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/call.c' line='638' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='638' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_CallMethod' mangled-name='PyEval_CallMethod' filepath='Objects/call.c' line='665' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_CallMethod'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='665' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/call.c' line='665' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='665' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_CallMethod' mangled-name='_PyObject_CallMethod' filepath='Objects/call.c' line='688' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CallMethod'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='688' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/call.c' line='688' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='689' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_CallMethodId' mangled-name='_PyObject_CallMethodId' filepath='Objects/call.c' line='712' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CallMethodId'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='712' column='1'/> + <parameter type-id='type-id-309' name='name' filepath='Objects/call.c' line='712' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='713' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_CallMethod_SizeT' mangled-name='_PyObject_CallMethod_SizeT' filepath='Objects/call.c' line='747' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CallMethod_SizeT'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='747' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/call.c' line='747' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='748' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_CallMethodId_SizeT' mangled-name='_PyObject_CallMethodId_SizeT' filepath='Objects/call.c' line='771' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CallMethodId_SizeT'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='771' column='1'/> + <parameter type-id='type-id-309' name='name' filepath='Objects/call.c' line='771' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Objects/call.c' line='772' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_CallMethodObjArgs' mangled-name='PyObject_CallMethodObjArgs' filepath='Objects/call.c' line='895' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallMethodObjArgs'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='895' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/call.c' line='895' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_CallMethodIdObjArgs' mangled-name='_PyObject_CallMethodIdObjArgs' filepath='Objects/call.c' line='920' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CallMethodIdObjArgs'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/call.c' line='920' column='1'/> + <parameter type-id='type-id-309' name='name' filepath='Objects/call.c' line='920' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyStack_AsDict' mangled-name='_PyStack_AsDict' filepath='Objects/call.c' line='967' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyStack_AsDict'> + <parameter type-id='type-id-248' name='values' filepath='Objects/call.c' line='967' column='1'/> + <parameter type-id='type-id-2' name='kwnames' filepath='Objects/call.c' line='967' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyVectorcall_NARGS' mangled-name='PyVectorcall_NARGS' filepath='Objects/call.c' line='1080' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyVectorcall_NARGS'> + <parameter type-id='type-id-19' name='n' filepath='Objects/call.c' line='1080' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/capsule.c' comp-dir-path='/src' language='LANG_C11'> + <typedef-decl name='PyCapsule_Destructor' type-id='type-id-312' filepath='./Include/pycapsule.h' line='23' column='1' id='type-id-313'/> + <function-decl name='PyImport_ImportModule' mangled-name='PyImport_ImportModule' filepath='./Include/import.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ImportModule'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='PyCapsule_Type' type-id='type-id-256' mangled-name='PyCapsule_Type' visibility='default' filepath='./Include/pycapsule.h' line='21' column='1' elf-symbol-id='PyCapsule_Type'/> + <function-decl name='PyCapsule_New' mangled-name='PyCapsule_New' filepath='Objects/capsule.c' line='44' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_New'> + <parameter type-id='type-id-22' name='pointer' filepath='Objects/capsule.c' line='44' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/capsule.c' line='44' column='1'/> + <parameter type-id='type-id-313' name='destructor' filepath='Objects/capsule.c' line='44' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCapsule_IsValid' mangled-name='PyCapsule_IsValid' filepath='Objects/capsule.c' line='68' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_IsValid'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='68' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/capsule.c' line='68' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCapsule_GetPointer' mangled-name='PyCapsule_GetPointer' filepath='Objects/capsule.c' line='80' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_GetPointer'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='80' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/capsule.c' line='80' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyCapsule_GetName' mangled-name='PyCapsule_GetName' filepath='Objects/capsule.c' line='98' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_GetName'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='98' column='1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyCapsule_GetDestructor' mangled-name='PyCapsule_GetDestructor' filepath='Objects/capsule.c' line='110' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_GetDestructor'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='110' column='1'/> + <return type-id='type-id-313'/> + </function-decl> + <function-decl name='PyCapsule_GetContext' mangled-name='PyCapsule_GetContext' filepath='Objects/capsule.c' line='122' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_GetContext'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='122' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyCapsule_SetPointer' mangled-name='PyCapsule_SetPointer' filepath='Objects/capsule.c' line='134' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_SetPointer'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='134' column='1'/> + <parameter type-id='type-id-22' name='pointer' filepath='Objects/capsule.c' line='134' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCapsule_SetName' mangled-name='PyCapsule_SetName' filepath='Objects/capsule.c' line='153' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_SetName'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='153' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/capsule.c' line='153' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCapsule_SetDestructor' mangled-name='PyCapsule_SetDestructor' filepath='Objects/capsule.c' line='167' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_SetDestructor'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='167' column='1'/> + <parameter type-id='type-id-313' name='destructor' filepath='Objects/capsule.c' line='167' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCapsule_SetContext' mangled-name='PyCapsule_SetContext' filepath='Objects/capsule.c' line='181' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_SetContext'> + <parameter type-id='type-id-2' name='o' filepath='Objects/capsule.c' line='181' column='1'/> + <parameter type-id='type-id-22' name='context' filepath='Objects/capsule.c' line='181' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCapsule_Import' mangled-name='PyCapsule_Import' filepath='Objects/capsule.c' line='195' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCapsule_Import'> + <parameter type-id='type-id-12' name='name' filepath='Objects/capsule.c' line='195' column='1'/> + <parameter type-id='type-id-8' name='no_block' filepath='Objects/capsule.c' line='195' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-314'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Objects/cellobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyCell_Type' type-id='type-id-256' mangled-name='PyCell_Type' visibility='default' filepath='./Include/cpython/cellobject.h' line='16' column='1' elf-symbol-id='PyCell_Type'/> + <function-decl name='PyObject_RichCompare' mangled-name='PyObject_RichCompare' filepath='./Include/object.h' line='390' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_RichCompare'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCell_New' mangled-name='PyCell_New' filepath='Objects/cellobject.c' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCell_New'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/cellobject.c' line='7' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCell_Get' mangled-name='PyCell_Get' filepath='Objects/cellobject.c' line='52' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCell_Get'> + <parameter type-id='type-id-2' name='op' filepath='Objects/cellobject.c' line='52' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCell_Set' mangled-name='PyCell_Set' filepath='Objects/cellobject.c' line='63' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCell_Set'> + <parameter type-id='type-id-2' name='op' filepath='Objects/cellobject.c' line='63' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Objects/cellobject.c' line='63' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/classobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyMethod_Type' type-id='type-id-256' mangled-name='PyMethod_Type' visibility='default' filepath='./Include/cpython/classobject.h' line='20' column='1' elf-symbol-id='PyMethod_Type'/> + <var-decl name='PyInstanceMethod_Type' type-id='type-id-256' mangled-name='PyInstanceMethod_Type' visibility='default' filepath='./Include/cpython/classobject.h' line='49' column='1' elf-symbol-id='PyInstanceMethod_Type'/> + <function-decl name='_PyType_Lookup' mangled-name='_PyType_Lookup' filepath='./Include/cpython/object.h' line='274' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_Lookup'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyType_GetDict' mangled-name='_PyType_GetDict' filepath='./Include/internal/pycore_typeobject.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_GetDict'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_Ready' mangled-name='PyType_Ready' filepath='./Include/object.h' line='378' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_Ready'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GenericSetAttr' mangled-name='PyObject_GenericSetAttr' filepath='./Include/object.h' line='400' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GenericSetAttr'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_Hash' mangled-name='PyObject_Hash' filepath='./Include/object.h' line='404' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Hash'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-305'/> + </function-decl> + <function-decl name='PyObject_ClearWeakRefs' mangled-name='PyObject_ClearWeakRefs' filepath='./Include/object.h' line='409' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_ClearWeakRefs'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_HashPointer' mangled-name='_Py_HashPointer' filepath='./Include/pyhash.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_HashPointer'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-305'/> + </function-decl> + <function-decl name='PyMethod_Function' mangled-name='PyMethod_Function' filepath='Objects/classobject.c' line='21' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMethod_Function'> + <parameter type-id='type-id-2' name='im' filepath='Objects/classobject.c' line='21' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMethod_Self' mangled-name='PyMethod_Self' filepath='Objects/classobject.c' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMethod_Self'> + <parameter type-id='type-id-2' name='im' filepath='Objects/classobject.c' line='31' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMethod_New' mangled-name='PyMethod_New' filepath='Objects/classobject.c' line='105' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMethod_New'> + <parameter type-id='type-id-2' name='func' filepath='Objects/classobject.c' line='105' column='1'/> + <parameter type-id='type-id-2' name='self' filepath='Objects/classobject.c' line='105' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInstanceMethod_New' mangled-name='PyInstanceMethod_New' filepath='Objects/classobject.c' line='352' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInstanceMethod_New'> + <parameter type-id='type-id-2' name='func' filepath='Objects/classobject.c' line='352' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInstanceMethod_Function' mangled-name='PyInstanceMethod_Function' filepath='Objects/classobject.c' line='363' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInstanceMethod_Function'> + <parameter type-id='type-id-2' name='im' filepath='Objects/classobject.c' line='363' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/codeobject.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='_opaque' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/cpython/code.h' line='309' column='1' id='type-id-315'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='computed_line' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='310' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='lo_next' type-id='type-id-316' visibility='default' filepath='./Include/cpython/code.h' line='311' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='limit' type-id='type-id-316' visibility='default' filepath='./Include/cpython/code.h' line='312' column='1'/> + </data-member> + </class-decl> + <class-decl name='_line_offsets' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/cpython/code.h' line='315' column='1' id='type-id-317'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ar_start' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='316' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='ar_end' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='317' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ar_line' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='318' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='opaque' type-id='type-id-315' visibility='default' filepath='./Include/cpython/code.h' line='319' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyCodeAddressRange' type-id='type-id-317' filepath='./Include/cpython/code.h' line='320' column='1' id='type-id-318'/> + <class-decl name='_PyCodeConstructor' size-in-bits='896' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_code.h' line='157' column='1' id='type-id-319'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='filename' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='name' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='qualname' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='flags' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='code' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='firstlineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='linetable' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='167' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='consts' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='170' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='names' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='localsplusnames' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='localspluskinds' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='175' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='argcount' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='178' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='736'> + <var-decl name='posonlyargcount' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='179' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='kwonlyargcount' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='800'> + <var-decl name='stacksize' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='184' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='exceptiontable' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='187' column='1'/> + </data-member> + </class-decl> + <pointer-type-def type-id='type-id-318' size-in-bits='64' id='type-id-320'/> + <pointer-type-def type-id='type-id-321' size-in-bits='64' id='type-id-322'/> + <pointer-type-def type-id='type-id-305' size-in-bits='64' id='type-id-323'/> + <pointer-type-def type-id='type-id-319' size-in-bits='64' id='type-id-324'/> + <qualified-type-def type-id='type-id-325' const='yes' id='type-id-326'/> + <pointer-type-def type-id='type-id-326' size-in-bits='64' id='type-id-316'/> + <var-decl name='PyCode_Type' type-id='type-id-256' mangled-name='PyCode_Type' visibility='default' filepath='./Include/cpython/code.h' line='205' column='1' elf-symbol-id='PyCode_Type'/> + <function-decl name='PyComplex_AsCComplex' mangled-name='PyComplex_AsCComplex' filepath='./Include/cpython/complexobject.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyComplex_AsCComplex'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_PySet_NextEntry' mangled-name='_PySet_NextEntry' filepath='./Include/cpython/setobject.h' line='71' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySet_NextEntry'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-323'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_Copy' mangled-name='_PyUnicode_Copy' filepath='./Include/cpython/unicodeobject.h' line='400' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_Copy'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_FromASCII' mangled-name='_PyUnicode_FromASCII' filepath='./Include/cpython/unicodeobject.h' line='474' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FromASCII'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_GetBaseOpcode' filepath='./Include/internal/pycore_code.h' line='488' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyLong_FromVoidPtr' mangled-name='PyLong_FromVoidPtr' filepath='./Include/longobject.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromVoidPtr'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_NewVar' mangled-name='_PyObject_NewVar' filepath='./Include/objimpl.h' line='132' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_NewVar'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-322'/> + </function-decl> + <function-decl name='PyErr_WriteUnraisable' mangled-name='PyErr_WriteUnraisable' filepath='./Include/pyerrors.h' line='235' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_WriteUnraisable'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyFrozenSet_New' mangled-name='PyFrozenSet_New' filepath='./Include/setobject.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrozenSet_New'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeFSDefault' mangled-name='PyUnicode_DecodeFSDefault' filepath='./Include/unicodeobject.h' line='762' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeFSDefault'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Compare' mangled-name='PyUnicode_Compare' filepath='./Include/unicodeobject.h' line='952' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Compare'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='copysign' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='198' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyCode_AddWatcher' mangled-name='PyCode_AddWatcher' filepath='Objects/codeobject.c' line='66' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_AddWatcher'> + <parameter type-id='type-id-329' name='callback' filepath='Objects/codeobject.c' line='66' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCode_ClearWatcher' mangled-name='PyCode_ClearWatcher' filepath='Objects/codeobject.c' line='98' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_ClearWatcher'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/codeobject.c' line='98' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCode_Validate' mangled-name='_PyCode_Validate' filepath='Objects/codeobject.c' line='335' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCode_Validate'> + <parameter type-id='type-id-324' name='con' filepath='Objects/codeobject.c' line='335' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCode_Quicken' filepath='Objects/codeobject.c' line='392' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyCode_New' mangled-name='_PyCode_New' filepath='Objects/codeobject.c' line='547' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCode_New'> + <parameter type-id='type-id-324' name='con' filepath='Objects/codeobject.c' line='547' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='PyUnstable_Code_NewWithPosOnlyArgs' mangled-name='PyUnstable_Code_NewWithPosOnlyArgs' filepath='Objects/codeobject.c' line='599' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Code_NewWithPosOnlyArgs'> + <parameter type-id='type-id-8' name='argcount' filepath='Objects/codeobject.c' line='600' column='1'/> + <parameter type-id='type-id-8' name='posonlyargcount' filepath='Objects/codeobject.c' line='600' column='1'/> + <parameter type-id='type-id-8' name='kwonlyargcount' filepath='Objects/codeobject.c' line='600' column='1'/> + <parameter type-id='type-id-8' name='nlocals' filepath='Objects/codeobject.c' line='601' column='1'/> + <parameter type-id='type-id-8' name='stacksize' filepath='Objects/codeobject.c' line='601' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/codeobject.c' line='601' column='1'/> + <parameter type-id='type-id-2' name='code' filepath='Objects/codeobject.c' line='602' column='1'/> + <parameter type-id='type-id-2' name='consts' filepath='Objects/codeobject.c' line='602' column='1'/> + <parameter type-id='type-id-2' name='names' filepath='Objects/codeobject.c' line='602' column='1'/> + <parameter type-id='type-id-2' name='varnames' filepath='Objects/codeobject.c' line='603' column='1'/> + <parameter type-id='type-id-2' name='freevars' filepath='Objects/codeobject.c' line='603' column='1'/> + <parameter type-id='type-id-2' name='cellvars' filepath='Objects/codeobject.c' line='603' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Objects/codeobject.c' line='604' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/codeobject.c' line='604' column='1'/> + <parameter type-id='type-id-2' name='qualname' filepath='Objects/codeobject.c' line='605' column='1'/> + <parameter type-id='type-id-8' name='firstlineno' filepath='Objects/codeobject.c' line='605' column='1'/> + <parameter type-id='type-id-2' name='linetable' filepath='Objects/codeobject.c' line='606' column='1'/> + <parameter type-id='type-id-2' name='exceptiontable' filepath='Objects/codeobject.c' line='607' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='PyUnstable_Code_New' mangled-name='PyUnstable_Code_New' filepath='Objects/codeobject.c' line='724' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Code_New'> + <parameter type-id='type-id-8' name='argcount' filepath='Objects/codeobject.c' line='724' column='1'/> + <parameter type-id='type-id-8' name='kwonlyargcount' filepath='Objects/codeobject.c' line='724' column='1'/> + <parameter type-id='type-id-8' name='nlocals' filepath='Objects/codeobject.c' line='725' column='1'/> + <parameter type-id='type-id-8' name='stacksize' filepath='Objects/codeobject.c' line='725' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/codeobject.c' line='725' column='1'/> + <parameter type-id='type-id-2' name='code' filepath='Objects/codeobject.c' line='726' column='1'/> + <parameter type-id='type-id-2' name='consts' filepath='Objects/codeobject.c' line='726' column='1'/> + <parameter type-id='type-id-2' name='names' filepath='Objects/codeobject.c' line='726' column='1'/> + <parameter type-id='type-id-2' name='varnames' filepath='Objects/codeobject.c' line='727' column='1'/> + <parameter type-id='type-id-2' name='freevars' filepath='Objects/codeobject.c' line='727' column='1'/> + <parameter type-id='type-id-2' name='cellvars' filepath='Objects/codeobject.c' line='727' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Objects/codeobject.c' line='728' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/codeobject.c' line='728' column='1'/> + <parameter type-id='type-id-2' name='qualname' filepath='Objects/codeobject.c' line='728' column='1'/> + <parameter type-id='type-id-8' name='firstlineno' filepath='Objects/codeobject.c' line='729' column='1'/> + <parameter type-id='type-id-2' name='linetable' filepath='Objects/codeobject.c' line='730' column='1'/> + <parameter type-id='type-id-2' name='exceptiontable' filepath='Objects/codeobject.c' line='731' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='PyCode_NewEmpty' mangled-name='PyCode_NewEmpty' filepath='Objects/codeobject.c' line='758' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_NewEmpty'> + <parameter type-id='type-id-12' name='filename' filepath='Objects/codeobject.c' line='758' column='1'/> + <parameter type-id='type-id-12' name='funcname' filepath='Objects/codeobject.c' line='758' column='1'/> + <parameter type-id='type-id-8' name='firstlineno' filepath='Objects/codeobject.c' line='758' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='PyCode_Addr2Line' mangled-name='PyCode_Addr2Line' filepath='Objects/codeobject.c' line='820' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_Addr2Line'> + <parameter type-id='type-id-328' name='co' filepath='Objects/codeobject.c' line='820' column='1'/> + <parameter type-id='type-id-8' name='addrq' filepath='Objects/codeobject.c' line='820' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCode_CheckLineNumber' mangled-name='_PyCode_CheckLineNumber' filepath='Objects/codeobject.c' line='855' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCode_CheckLineNumber'> + <parameter type-id='type-id-8' name='lasti' filepath='Objects/codeobject.c' line='855' column='1'/> + <parameter type-id='type-id-320' name='bounds' filepath='Objects/codeobject.c' line='855' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCode_Addr2Location' mangled-name='PyCode_Addr2Location' filepath='Objects/codeobject.c' line='1032' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_Addr2Location'> + <parameter type-id='type-id-328' name='co' filepath='Objects/codeobject.c' line='1032' column='1'/> + <parameter type-id='type-id-8' name='addrq' filepath='Objects/codeobject.c' line='1032' column='1'/> + <parameter type-id='type-id-179' name='start_line' filepath='Objects/codeobject.c' line='1033' column='1'/> + <parameter type-id='type-id-179' name='start_column' filepath='Objects/codeobject.c' line='1033' column='1'/> + <parameter type-id='type-id-179' name='end_line' filepath='Objects/codeobject.c' line='1034' column='1'/> + <parameter type-id='type-id-179' name='end_column' filepath='Objects/codeobject.c' line='1034' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_Code_GetExtra' mangled-name='PyUnstable_Code_GetExtra' filepath='Objects/codeobject.c' line='1353' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Code_GetExtra'> + <parameter type-id='type-id-2' name='code' filepath='Objects/codeobject.c' line='1353' column='1'/> + <parameter type-id='type-id-14' name='index' filepath='Objects/codeobject.c' line='1353' column='1'/> + <parameter type-id='type-id-253' name='extra' filepath='Objects/codeobject.c' line='1353' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_Code_SetExtra' mangled-name='PyUnstable_Code_SetExtra' filepath='Objects/codeobject.c' line='1374' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Code_SetExtra'> + <parameter type-id='type-id-2' name='code' filepath='Objects/codeobject.c' line='1374' column='1'/> + <parameter type-id='type-id-14' name='index' filepath='Objects/codeobject.c' line='1374' column='1'/> + <parameter type-id='type-id-22' name='extra' filepath='Objects/codeobject.c' line='1374' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCode_GetVarnames' mangled-name='PyCode_GetVarnames' filepath='Objects/codeobject.c' line='1447' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_GetVarnames'> + <parameter type-id='type-id-328' name='code' filepath='Objects/codeobject.c' line='1447' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCode_GetCellvars' mangled-name='PyCode_GetCellvars' filepath='Objects/codeobject.c' line='1462' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_GetCellvars'> + <parameter type-id='type-id-328' name='code' filepath='Objects/codeobject.c' line='1462' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCode_GetFreevars' mangled-name='PyCode_GetFreevars' filepath='Objects/codeobject.c' line='1477' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_GetFreevars'> + <parameter type-id='type-id-328' name='code' filepath='Objects/codeobject.c' line='1477' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCode_GetCode' mangled-name='PyCode_GetCode' filepath='Objects/codeobject.c' line='1518' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_GetCode'> + <parameter type-id='type-id-328' name='co' filepath='Objects/codeobject.c' line='1518' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCode_ConstantKey' mangled-name='_PyCode_ConstantKey' filepath='Objects/codeobject.c' line='2157' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCode_ConstantKey'> + <parameter type-id='type-id-2' name='op' filepath='Objects/codeobject.c' line='2157' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/complexobject.c' comp-dir-path='/src' language='LANG_C11'> + <pointer-type-def type-id='type-id-330' size-in-bits='64' id='type-id-331'/> + <var-decl name='PyComplex_Type' type-id='type-id-256' mangled-name='PyComplex_Type' visibility='default' filepath='./Include/complexobject.h' line='11' column='1' elf-symbol-id='PyComplex_Type'/> + <function-decl name='_PyComplex_FormatAdvancedWriter' filepath='./Include/cpython/complexobject.h' line='38' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_TransformDecimalAndSpaceToASCII' mangled-name='_PyUnicode_TransformDecimalAndSpaceToASCII' filepath='./Include/cpython/unicodeobject.h' line='744' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_TransformDecimalAndSpaceToASCII'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_HashDouble' mangled-name='_Py_HashDouble' filepath='./Include/pyhash.h' line='10' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_HashDouble'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-251'/> + <return type-id='type-id-305'/> + </function-decl> + <function-decl name='_Py_string_to_number_with_underscores' mangled-name='_Py_string_to_number_with_underscores' filepath='./Include/pystrtod.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_string_to_number_with_underscores'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-331'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='atan2' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='cos' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='62' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='sin' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='exp' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='log' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='104' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='pow' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='140' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='hypot' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='147' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='floor' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='165' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='_Py_c_sum' mangled-name='_Py_c_sum' filepath='Objects/complexobject.c' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_sum'> + <parameter type-id='type-id-327' name='a' filepath='Objects/complexobject.c' line='28' column='1'/> + <parameter type-id='type-id-327' name='b' filepath='Objects/complexobject.c' line='28' column='1'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_Py_c_diff' mangled-name='_Py_c_diff' filepath='Objects/complexobject.c' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_diff'> + <parameter type-id='type-id-327' name='a' filepath='Objects/complexobject.c' line='37' column='1'/> + <parameter type-id='type-id-327' name='b' filepath='Objects/complexobject.c' line='37' column='1'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_Py_c_neg' mangled-name='_Py_c_neg' filepath='Objects/complexobject.c' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_neg'> + <parameter type-id='type-id-327' name='a' filepath='Objects/complexobject.c' line='46' column='1'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_Py_c_prod' mangled-name='_Py_c_prod' filepath='Objects/complexobject.c' line='55' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_prod'> + <parameter type-id='type-id-327' name='a' filepath='Objects/complexobject.c' line='55' column='1'/> + <parameter type-id='type-id-327' name='b' filepath='Objects/complexobject.c' line='55' column='1'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_Py_c_quot' mangled-name='_Py_c_quot' filepath='Objects/complexobject.c' line='68' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_quot'> + <parameter type-id='type-id-327' name='a' filepath='Objects/complexobject.c' line='68' column='1'/> + <parameter type-id='type-id-327' name='b' filepath='Objects/complexobject.c' line='68' column='1'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_Py_c_pow' mangled-name='_Py_c_pow' filepath='Objects/complexobject.c' line='129' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_pow'> + <parameter type-id='type-id-327' name='a' filepath='Objects/complexobject.c' line='129' column='1'/> + <parameter type-id='type-id-327' name='b' filepath='Objects/complexobject.c' line='129' column='1'/> + <return type-id='type-id-327'/> + </function-decl> + <function-decl name='_Py_c_abs' mangled-name='_Py_c_abs' filepath='Objects/complexobject.c' line='185' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_c_abs'> + <parameter type-id='type-id-327' name='z' filepath='Objects/complexobject.c' line='185' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyComplex_FromDoubles' mangled-name='PyComplex_FromDoubles' filepath='Objects/complexobject.c' line='250' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyComplex_FromDoubles'> + <parameter type-id='type-id-251' name='real' filepath='Objects/complexobject.c' line='250' column='1'/> + <parameter type-id='type-id-251' name='imag' filepath='Objects/complexobject.c' line='250' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyComplex_RealAsDouble' mangled-name='PyComplex_RealAsDouble' filepath='Objects/complexobject.c' line='259' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyComplex_RealAsDouble'> + <parameter type-id='type-id-2' name='op' filepath='Objects/complexobject.c' line='259' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyComplex_ImagAsDouble' mangled-name='PyComplex_ImagAsDouble' filepath='Objects/complexobject.c' line='270' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyComplex_ImagAsDouble'> + <parameter type-id='type-id-2' name='op' filepath='Objects/complexobject.c' line='270' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-330'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-2'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Objects/descrobject.c' comp-dir-path='/src' language='LANG_C11'> + <pointer-type-def type-id='type-id-333' size-in-bits='64' id='type-id-334'/> + <var-decl name='_PyMethodWrapper_Type' type-id='type-id-256' mangled-name='_PyMethodWrapper_Type' visibility='default' filepath='./Include/cpython/descrobject.h' line='60' column='1' elf-symbol-id='_PyMethodWrapper_Type'/> + <function-decl name='_PyArg_UnpackStack' mangled-name='_PyArg_UnpackStack' filepath='./Include/cpython/modsupport.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_UnpackStack'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyType_GetDocFromInternalDoc' mangled-name='_PyType_GetDocFromInternalDoc' filepath='./Include/cpython/object.h' line='283' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_GetDocFromInternalDoc'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyType_GetTextSignatureFromInternalDoc' mangled-name='_PyType_GetTextSignatureFromInternalDoc' filepath='./Include/cpython/object.h' line='284' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_GetTextSignatureFromInternalDoc'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_IsAbstract' mangled-name='_PyObject_IsAbstract' filepath='./Include/cpython/object.h' line='292' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_IsAbstract'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_FunctionStr' mangled-name='_PyObject_FunctionStr' filepath='./Include/cpython/object.h' line='322' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_FunctionStr'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTrash_begin' mangled-name='_PyTrash_begin' filepath='./Include/cpython/object.h' line='515' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTrash_begin'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTrash_end' mangled-name='_PyTrash_end' filepath='./Include/cpython/object.h' line='516' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTrash_end'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTrash_cond' mangled-name='_PyTrash_cond' filepath='./Include/cpython/object.h' line='518' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTrash_cond'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-335'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyThreadState_UncheckedGet' mangled-name='_PyThreadState_UncheckedGet' filepath='./Include/cpython/pystate.h' line='273' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_UncheckedGet'> + <return type-id='type-id-177'/> + </function-decl> + <var-decl name='PyClassMethodDescr_Type' type-id='type-id-256' mangled-name='PyClassMethodDescr_Type' visibility='default' filepath='./Include/descrobject.h' line='19' column='1' elf-symbol-id='PyClassMethodDescr_Type'/> + <var-decl name='PyGetSetDescr_Type' type-id='type-id-256' mangled-name='PyGetSetDescr_Type' visibility='default' filepath='./Include/descrobject.h' line='20' column='1' elf-symbol-id='PyGetSetDescr_Type'/> + <var-decl name='PyMemberDescr_Type' type-id='type-id-256' mangled-name='PyMemberDescr_Type' visibility='default' filepath='./Include/descrobject.h' line='21' column='1' elf-symbol-id='PyMemberDescr_Type'/> + <var-decl name='PyMethodDescr_Type' type-id='type-id-256' mangled-name='PyMethodDescr_Type' visibility='default' filepath='./Include/descrobject.h' line='22' column='1' elf-symbol-id='PyMethodDescr_Type'/> + <var-decl name='PyWrapperDescr_Type' type-id='type-id-256' mangled-name='PyWrapperDescr_Type' visibility='default' filepath='./Include/descrobject.h' line='23' column='1' elf-symbol-id='PyWrapperDescr_Type'/> + <var-decl name='PyDictProxy_Type' type-id='type-id-256' mangled-name='PyDictProxy_Type' visibility='default' filepath='./Include/descrobject.h' line='24' column='1' elf-symbol-id='PyDictProxy_Type'/> + <var-decl name='PyProperty_Type' type-id='type-id-256' mangled-name='PyProperty_Type' visibility='default' filepath='./Include/descrobject.h' line='25' column='1' elf-symbol-id='PyProperty_Type'/> + <function-decl name='PyMember_GetOne' mangled-name='PyMember_GetOne' filepath='./Include/descrobject.h' line='88' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMember_GetOne'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-336'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMember_SetOne' mangled-name='PyMember_SetOne' filepath='./Include/descrobject.h' line='89' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMember_SetOne'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-336'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Contains' mangled-name='PyDict_Contains' filepath='./Include/dictobject.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Contains'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCMethod_New' mangled-name='PyCMethod_New' filepath='./Include/methodobject.h' line='74' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCMethod_New'> + <parameter type-id='type-id-337'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_GetQualName' mangled-name='PyType_GetQualName' filepath='./Include/object.h' line='354' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetQualName'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_SetAttr' mangled-name='PyObject_SetAttr' filepath='./Include/object.h' line='396' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_SetAttr'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GC_UnTrack' mangled-name='PyObject_GC_UnTrack' filepath='./Include/objimpl.h' line='199' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GC_UnTrack'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyTuple_GetSlice' mangled-name='PyTuple_GetSlice' filepath='./Include/tupleobject.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTuple_GetSlice'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDescr_NewMethod' mangled-name='PyDescr_NewMethod' filepath='Objects/descrobject.c' line='919' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDescr_NewMethod'> + <parameter type-id='type-id-1' name='type' filepath='Objects/descrobject.c' line='919' column='1'/> + <parameter type-id='type-id-337' name='method' filepath='Objects/descrobject.c' line='919' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDescr_NewClassMethod' mangled-name='PyDescr_NewClassMethod' filepath='Objects/descrobject.c' line='965' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDescr_NewClassMethod'> + <parameter type-id='type-id-1' name='type' filepath='Objects/descrobject.c' line='965' column='1'/> + <parameter type-id='type-id-337' name='method' filepath='Objects/descrobject.c' line='965' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDescr_NewMember' mangled-name='PyDescr_NewMember' filepath='Objects/descrobject.c' line='977' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDescr_NewMember'> + <parameter type-id='type-id-1' name='type' filepath='Objects/descrobject.c' line='977' column='1'/> + <parameter type-id='type-id-336' name='member' filepath='Objects/descrobject.c' line='977' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDescr_NewGetSet' mangled-name='PyDescr_NewGetSet' filepath='Objects/descrobject.c' line='995' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDescr_NewGetSet'> + <parameter type-id='type-id-1' name='type' filepath='Objects/descrobject.c' line='995' column='1'/> + <parameter type-id='type-id-338' name='getset' filepath='Objects/descrobject.c' line='995' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDescr_NewWrapper' mangled-name='PyDescr_NewWrapper' filepath='Objects/descrobject.c' line='1007' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDescr_NewWrapper'> + <parameter type-id='type-id-1' name='type' filepath='Objects/descrobject.c' line='1007' column='1'/> + <parameter type-id='type-id-334' name='base' filepath='Objects/descrobject.c' line='1007' column='1'/> + <parameter type-id='type-id-22' name='wrapped' filepath='Objects/descrobject.c' line='1007' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDescr_IsData' mangled-name='PyDescr_IsData' filepath='Objects/descrobject.c' line='1021' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDescr_IsData'> + <parameter type-id='type-id-2' name='ob' filepath='Objects/descrobject.c' line='1021' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDictProxy_New' mangled-name='PyDictProxy_New' filepath='Objects/descrobject.c' line='1256' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDictProxy_New'> + <parameter type-id='type-id-2' name='mapping' filepath='Objects/descrobject.c' line='1256' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyWrapper_New' mangled-name='PyWrapper_New' filepath='Objects/descrobject.c' line='1457' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyWrapper_New'> + <parameter type-id='type-id-2' name='d' filepath='Objects/descrobject.c' line='1457' column='1'/> + <parameter type-id='type-id-2' name='self' filepath='Objects/descrobject.c' line='1457' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/dictobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyObject_AssertFailed' mangled-name='_PyObject_AssertFailed' filepath='./Include/cpython/object.h' line='443' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_AssertFailed'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_IS_GC' mangled-name='PyObject_IS_GC' filepath='./Include/cpython/objimpl.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_IS_GC'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_SetKeyError' mangled-name='_PyErr_SetKeyError' filepath='./Include/cpython/pyerrors.h' line='93' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_SetKeyError'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PySet_Update' mangled-name='_PySet_Update' filepath='./Include/cpython/setobject.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySet_Update'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyDict_Type' type-id='type-id-256' mangled-name='PyDict_Type' visibility='default' filepath='./Include/dictobject.h' line='15' column='1' elf-symbol-id='PyDict_Type'/> + <var-decl name='PyDictKeys_Type' type-id='type-id-256' mangled-name='PyDictKeys_Type' visibility='default' filepath='./Include/dictobject.h' line='66' column='1' elf-symbol-id='PyDictKeys_Type'/> + <var-decl name='PyDictValues_Type' type-id='type-id-256' mangled-name='PyDictValues_Type' visibility='default' filepath='./Include/dictobject.h' line='67' column='1' elf-symbol-id='PyDictValues_Type'/> + <var-decl name='PyDictItems_Type' type-id='type-id-256' mangled-name='PyDictItems_Type' visibility='default' filepath='./Include/dictobject.h' line='68' column='1' elf-symbol-id='PyDictItems_Type'/> + <var-decl name='PyDictIterKey_Type' type-id='type-id-256' mangled-name='PyDictIterKey_Type' visibility='default' filepath='./Include/dictobject.h' line='79' column='1' elf-symbol-id='PyDictIterKey_Type'/> + <var-decl name='PyDictIterValue_Type' type-id='type-id-256' mangled-name='PyDictIterValue_Type' visibility='default' filepath='./Include/dictobject.h' line='80' column='1' elf-symbol-id='PyDictIterValue_Type'/> + <var-decl name='PyDictIterItem_Type' type-id='type-id-256' mangled-name='PyDictIterItem_Type' visibility='default' filepath='./Include/dictobject.h' line='81' column='1' elf-symbol-id='PyDictIterItem_Type'/> + <var-decl name='PyDictRevIterKey_Type' type-id='type-id-256' mangled-name='PyDictRevIterKey_Type' visibility='default' filepath='./Include/dictobject.h' line='83' column='1' elf-symbol-id='PyDictRevIterKey_Type'/> + <var-decl name='PyDictRevIterItem_Type' type-id='type-id-256' mangled-name='PyDictRevIterItem_Type' visibility='default' filepath='./Include/dictobject.h' line='84' column='1' elf-symbol-id='PyDictRevIterItem_Type'/> + <var-decl name='PyDictRevIterValue_Type' type-id='type-id-256' mangled-name='PyDictRevIterValue_Type' visibility='default' filepath='./Include/dictobject.h' line='85' column='1' elf-symbol-id='PyDictRevIterValue_Type'/> + <function-decl name='_PyType_AllocNoTrack' filepath='./Include/internal/pycore_object.h' line='342' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_ComputedDictPointer' filepath='./Include/internal/pycore_object.h' line='391' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-233'/> + </function-decl> + <function-decl name='_PyErr_GetRaisedException' filepath='./Include/internal/pycore_pyerrors.h' line='44' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyArg_ValidateKeywordArguments' mangled-name='PyArg_ValidateKeywordArguments' filepath='./Include/modsupport.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_ValidateKeywordArguments'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_DebugMallocStats' mangled-name='_PyDict_DebugMallocStats' filepath='Objects/dictobject.c' line='289' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_DebugMallocStats'> + <parameter type-id='type-id-229' name='out' filepath='Objects/dictobject.c' line='289' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyDict_CheckConsistency' mangled-name='_PyDict_CheckConsistency' filepath='Objects/dictobject.c' line='511' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_CheckConsistency'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='511' column='1'/> + <parameter type-id='type-id-8' name='check_content' filepath='Objects/dictobject.c' line='511' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_HasOnlyStringKeys' mangled-name='_PyDict_HasOnlyStringKeys' filepath='Objects/dictobject.c' line='1102' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_HasOnlyStringKeys'> + <parameter type-id='type-id-2' name='dict' filepath='Objects/dictobject.c' line='1102' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_MaybeUntrack' mangled-name='_PyDict_MaybeUntrack' filepath='Objects/dictobject.c' line='1127' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_MaybeUntrack'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='1127' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyDict_NewPresized' mangled-name='_PyDict_NewPresized' filepath='Objects/dictobject.c' line='1609' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_NewPresized'> + <parameter type-id='type-id-14' name='minused' filepath='Objects/dictobject.c' line='1609' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_GetItem_KnownHash' mangled-name='_PyDict_GetItem_KnownHash' filepath='Objects/dictobject.c' line='1727' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_GetItem_KnownHash'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='1727' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='1727' column='1'/> + <parameter type-id='type-id-305' name='hash' filepath='Objects/dictobject.c' line='1727' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_GetItemWithError' mangled-name='_PyDict_GetItemWithError' filepath='Objects/dictobject.c' line='1773' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_GetItemWithError'> + <parameter type-id='type-id-2' name='dp' filepath='Objects/dictobject.c' line='1773' column='1'/> + <parameter type-id='type-id-2' name='kv' filepath='Objects/dictobject.c' line='1773' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_GetItemIdWithError' mangled-name='_PyDict_GetItemIdWithError' filepath='Objects/dictobject.c' line='1784' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_GetItemIdWithError'> + <parameter type-id='type-id-2' name='dp' filepath='Objects/dictobject.c' line='1784' column='1'/> + <parameter type-id='type-id-309' name='key' filepath='Objects/dictobject.c' line='1784' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_GetItemStringWithError' mangled-name='_PyDict_GetItemStringWithError' filepath='Objects/dictobject.c' line='1796' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_GetItemStringWithError'> + <parameter type-id='type-id-2' name='v' filepath='Objects/dictobject.c' line='1796' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/dictobject.c' line='1796' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_SetItem_KnownHash' mangled-name='_PyDict_SetItem_KnownHash' filepath='Objects/dictobject.c' line='1888' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_SetItem_KnownHash'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='1888' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='1888' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Objects/dictobject.c' line='1888' column='1'/> + <parameter type-id='type-id-305' name='hash' filepath='Objects/dictobject.c' line='1889' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_DelItem' mangled-name='PyDict_DelItem' filepath='Objects/dictobject.c' line='1970' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_DelItem'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='1970' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='1970' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_DelItem_KnownHash' mangled-name='_PyDict_DelItem_KnownHash' filepath='Objects/dictobject.c' line='1984' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_DelItem_KnownHash'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='1984' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='1984' column='1'/> + <parameter type-id='type-id-305' name='hash' filepath='Objects/dictobject.c' line='1984' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_DelItemIf' mangled-name='_PyDict_DelItemIf' filepath='Objects/dictobject.c' line='2016' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_DelItemIf'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='2016' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='2016' column='1'/> + <parameter type-id='type-id-339' name='predicate' filepath='Objects/dictobject.c' line='2017' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Clear' mangled-name='PyDict_Clear' filepath='Objects/dictobject.c' line='2061' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Clear'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='2061' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyDict_Next' mangled-name='_PyDict_Next' filepath='Objects/dictobject.c' line='2106' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_Next'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='2106' column='1'/> + <parameter type-id='type-id-13' name='ppos' filepath='Objects/dictobject.c' line='2106' column='1'/> + <parameter type-id='type-id-233' name='pkey' filepath='Objects/dictobject.c' line='2106' column='1'/> + <parameter type-id='type-id-233' name='pvalue' filepath='Objects/dictobject.c' line='2107' column='1'/> + <parameter type-id='type-id-323' name='phash' filepath='Objects/dictobject.c' line='2107' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_Pop' mangled-name='_PyDict_Pop' filepath='Objects/dictobject.c' line='2231' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_Pop'> + <parameter type-id='type-id-2' name='dict' filepath='Objects/dictobject.c' line='2231' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='2231' column='1'/> + <parameter type-id='type-id-2' name='deflt' filepath='Objects/dictobject.c' line='2231' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_MergeFromSeq2' mangled-name='PyDict_MergeFromSeq2' filepath='Objects/dictobject.c' line='2722' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_MergeFromSeq2'> + <parameter type-id='type-id-2' name='d' filepath='Objects/dictobject.c' line='2722' column='1'/> + <parameter type-id='type-id-2' name='seq2' filepath='Objects/dictobject.c' line='2722' column='1'/> + <parameter type-id='type-id-8' name='override' filepath='Objects/dictobject.c' line='2722' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Update' mangled-name='PyDict_Update' filepath='Objects/dictobject.c' line='2981' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Update'> + <parameter type-id='type-id-2' name='a' filepath='Objects/dictobject.c' line='2981' column='1'/> + <parameter type-id='type-id-2' name='b' filepath='Objects/dictobject.c' line='2981' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Merge' mangled-name='PyDict_Merge' filepath='Objects/dictobject.c' line='2988' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Merge'> + <parameter type-id='type-id-2' name='a' filepath='Objects/dictobject.c' line='2988' column='1'/> + <parameter type-id='type-id-2' name='b' filepath='Objects/dictobject.c' line='2988' column='1'/> + <parameter type-id='type-id-8' name='override' filepath='Objects/dictobject.c' line='2988' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_MergeEx' mangled-name='_PyDict_MergeEx' filepath='Objects/dictobject.c' line='2996' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_MergeEx'> + <parameter type-id='type-id-2' name='a' filepath='Objects/dictobject.c' line='2996' column='1'/> + <parameter type-id='type-id-2' name='b' filepath='Objects/dictobject.c' line='2996' column='1'/> + <parameter type-id='type-id-8' name='override' filepath='Objects/dictobject.c' line='2996' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Size' mangled-name='PyDict_Size' filepath='Objects/dictobject.c' line='3102' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Size'> + <parameter type-id='type-id-2' name='mp' filepath='Objects/dictobject.c' line='3102' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyDict_SetDefault' mangled-name='PyDict_SetDefault' filepath='Objects/dictobject.c' line='3290' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_SetDefault'> + <parameter type-id='type-id-2' name='d' filepath='Objects/dictobject.c' line='3290' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='3290' column='1'/> + <parameter type-id='type-id-2' name='defaultobj' filepath='Objects/dictobject.c' line='3290' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_SizeOf' mangled-name='_PyDict_SizeOf' filepath='Objects/dictobject.c' line='3571' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_SizeOf'> + <parameter type-id='type-id-340' name='mp' filepath='Objects/dictobject.c' line='3571' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyDict_Contains_KnownHash' mangled-name='_PyDict_Contains_KnownHash' filepath='Objects/dictobject.c' line='3709' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_Contains_KnownHash'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='3709' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/dictobject.c' line='3709' column='1'/> + <parameter type-id='type-id-305' name='hash' filepath='Objects/dictobject.c' line='3709' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_ContainsId' mangled-name='_PyDict_ContainsId' filepath='Objects/dictobject.c' line='3722' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_ContainsId'> + <parameter type-id='type-id-2' name='op' filepath='Objects/dictobject.c' line='3722' column='1'/> + <parameter type-id='type-id-309' name='key' filepath='Objects/dictobject.c' line='3722' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_GetItemString' mangled-name='PyDict_GetItemString' filepath='Objects/dictobject.c' line='3887' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_GetItemString'> + <parameter type-id='type-id-2' name='v' filepath='Objects/dictobject.c' line='3887' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/dictobject.c' line='3887' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_SetItemId' mangled-name='_PyDict_SetItemId' filepath='Objects/dictobject.c' line='3901' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_SetItemId'> + <parameter type-id='type-id-2' name='v' filepath='Objects/dictobject.c' line='3901' column='1'/> + <parameter type-id='type-id-309' name='key' filepath='Objects/dictobject.c' line='3901' column='1'/> + <parameter type-id='type-id-2' name='item' filepath='Objects/dictobject.c' line='3901' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_DelItemId' mangled-name='_PyDict_DelItemId' filepath='Objects/dictobject.c' line='3925' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDict_DelItemId'> + <parameter type-id='type-id-2' name='v' filepath='Objects/dictobject.c' line='3925' column='1'/> + <parameter type-id='type-id-309' name='key' filepath='Objects/dictobject.c' line='3925' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_DelItemString' mangled-name='PyDict_DelItemString' filepath='Objects/dictobject.c' line='3934' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_DelItemString'> + <parameter type-id='type-id-2' name='v' filepath='Objects/dictobject.c' line='3934' column='1'/> + <parameter type-id='type-id-12' name='key' filepath='Objects/dictobject.c' line='3934' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDictView_New' mangled-name='_PyDictView_New' filepath='Objects/dictobject.c' line='4562' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDictView_New'> + <parameter type-id='type-id-2' name='dict' filepath='Objects/dictobject.c' line='4562' column='1'/> + <parameter type-id='type-id-1' name='type' filepath='Objects/dictobject.c' line='4562' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDictView_Intersect' mangled-name='_PyDictView_Intersect' filepath='Objects/dictobject.c' line='4786' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDictView_Intersect'> + <parameter type-id='type-id-2' name='self' filepath='Objects/dictobject.c' line='4786' column='1'/> + <parameter type-id='type-id-2' name='other' filepath='Objects/dictobject.c' line='4786' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_VisitManagedDict' mangled-name='_PyObject_VisitManagedDict' filepath='Objects/dictobject.c' line='5577' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_VisitManagedDict'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/dictobject.c' line='5577' column='1'/> + <parameter type-id='type-id-341' name='visit' filepath='Objects/dictobject.c' line='5577' column='1'/> + <parameter type-id='type-id-22' name='arg' filepath='Objects/dictobject.c' line='5577' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_ClearManagedDict' mangled-name='_PyObject_ClearManagedDict' filepath='Objects/dictobject.c' line='5600' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_ClearManagedDict'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/dictobject.c' line='5600' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyDict_Watch' mangled-name='PyDict_Watch' filepath='Objects/dictobject.c' line='5754' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Watch'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/dictobject.c' line='5754' column='1'/> + <parameter type-id='type-id-2' name='dict' filepath='Objects/dictobject.c' line='5754' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Unwatch' mangled-name='PyDict_Unwatch' filepath='Objects/dictobject.c' line='5769' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Unwatch'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/dictobject.c' line='5769' column='1'/> + <parameter type-id='type-id-2' name='dict' filepath='Objects/dictobject.c' line='5769' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_AddWatcher' mangled-name='PyDict_AddWatcher' filepath='Objects/dictobject.c' line='5784' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_AddWatcher'> + <parameter type-id='type-id-342' name='callback' filepath='Objects/dictobject.c' line='5784' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_ClearWatcher' mangled-name='PyDict_ClearWatcher' filepath='Objects/dictobject.c' line='5800' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_ClearWatcher'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/dictobject.c' line='5800' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <pointer-type-def type-id='type-id-343' size-in-bits='64' id='type-id-340'/> + <typedef-decl name='PyDictObject' type-id='type-id-344' filepath='./Include/cpython/dictobject.h' line='33' column='1' id='type-id-343'/> + <class-decl name='PyDictObject' size-in-bits='384' is-struct='yes' naming-typedef-id='type-id-343' visibility='default' filepath='./Include/cpython/dictobject.h' line='11' column='1' id='type-id-344'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/dictobject.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ma_used' type-id='type-id-14' visibility='default' filepath='./Include/cpython/dictobject.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ma_version_tag' type-id='type-id-117' visibility='default' filepath='./Include/cpython/dictobject.h' line='20' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='ma_keys' type-id='type-id-346' visibility='default' filepath='./Include/cpython/dictobject.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='ma_values' type-id='type-id-347' visibility='default' filepath='./Include/cpython/dictobject.h' line='32' column='1'/> + </data-member> + </class-decl> + <pointer-type-def type-id='type-id-348' size-in-bits='64' id='type-id-346'/> + <pointer-type-def type-id='type-id-349' size-in-bits='64' id='type-id-347'/> + <typedef-decl name='PyDictKeysObject' type-id='type-id-350' filepath='./Include/cpython/dictobject.h' line='5' column='1' id='type-id-348'/> + <typedef-decl name='PyDictValues' type-id='type-id-351' filepath='./Include/cpython/dictobject.h' line='6' column='1' id='type-id-349'/> + <class-decl name='_dictkeysobject' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dict.h' line='72' column='1' id='type-id-350'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='dk_refcnt' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_dict.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='dk_log2_size' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_dict.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='72'> + <var-decl name='dk_log2_index_bytes' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_dict.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='80'> + <var-decl name='dk_kind' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_dict.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='dk_version' type-id='type-id-352' visibility='default' filepath='./Include/internal/pycore_dict.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='dk_usable' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_dict.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='dk_nentries' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_dict.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='dk_indices' type-id='type-id-257' visibility='default' filepath='./Include/internal/pycore_dict.h' line='106' column='1'/> + </data-member> + </class-decl> + <class-decl name='_dictvalues' size-in-bits='64' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dict.h' line='122' column='1' id='type-id-351'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='values' type-id='type-id-353' visibility='default' filepath='./Include/internal/pycore_dict.h' line='123' column='1'/> + </data-member> + </class-decl> + <function-type size-in-bits='64' id='type-id-354'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Objects/enumobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyUnicode_EqualToASCIIString' mangled-name='_PyUnicode_EqualToASCIIString' filepath='./Include/cpython/unicodeobject.h' line='767' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EqualToASCIIString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyEnum_Type' type-id='type-id-256' mangled-name='PyEnum_Type' visibility='default' filepath='./Include/enumobject.h' line='10' column='1' elf-symbol-id='PyEnum_Type'/> + <var-decl name='PyReversed_Type' type-id='type-id-256' mangled-name='PyReversed_Type' visibility='default' filepath='./Include/enumobject.h' line='11' column='1' elf-symbol-id='PyReversed_Type'/> + </abi-instr> + <abi-instr address-size='64' path='Objects/exceptions.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyDict_New' mangled-name='PyDict_New' filepath='./Include/dictobject.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_New'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_GetItemWithError' mangled-name='PyDict_GetItemWithError' filepath='./Include/dictobject.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_GetItemWithError'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_SetItem' mangled-name='PyDict_SetItem' filepath='./Include/dictobject.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_SetItem'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyDict_Copy' mangled-name='PyDict_Copy' filepath='./Include/dictobject.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_Copy'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyDict_SetItemString' mangled-name='PyDict_SetItemString' filepath='./Include/dictobject.h' line='58' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_SetItemString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GenericGetDict' mangled-name='PyObject_GenericGetDict' filepath='./Include/dictobject.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GenericGetDict'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_SetRaisedException' filepath='./Include/internal/pycore_pyerrors.h' line='51' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyStaticType_InitBuiltin' filepath='./Include/internal/pycore_typeobject.h' line='114' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyStaticType_Dealloc' filepath='./Include/internal/pycore_typeobject.h' line='117' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyList_GetItem' mangled-name='PyList_GetItem' filepath='./Include/listobject.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_GetItem'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyArg_ParseTupleAndKeywords_SizeT' mangled-name='_PyArg_ParseTupleAndKeywords_SizeT' filepath='./Include/modsupport.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseTupleAndKeywords_SizeT'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyModule_GetDict' mangled-name='PyModule_GetDict' filepath='./Include/moduleobject.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetDict'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Repr' mangled-name='PyObject_Repr' filepath='./Include/object.h' line='386' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Repr'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_HasAttr' mangled-name='PyObject_HasAttr' filepath='./Include/object.h' line='397' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_HasAttr'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_GenericSetDict' mangled-name='PyObject_GenericSetDict' filepath='./Include/object.h' line='402' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GenericSetDict'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyExc_BaseException' type-id='type-id-2' mangled-name='PyExc_BaseException' visibility='default' filepath='./Include/pyerrors.h' line='78' column='1' elf-symbol-id='PyExc_BaseException'/> + <var-decl name='PyExc_Exception' type-id='type-id-2' mangled-name='PyExc_Exception' visibility='default' filepath='./Include/pyerrors.h' line='79' column='1' elf-symbol-id='PyExc_Exception'/> + <var-decl name='PyExc_BaseExceptionGroup' type-id='type-id-2' mangled-name='PyExc_BaseExceptionGroup' visibility='default' filepath='./Include/pyerrors.h' line='80' column='1' elf-symbol-id='PyExc_BaseExceptionGroup'/> + <var-decl name='PyExc_StopAsyncIteration' type-id='type-id-2' mangled-name='PyExc_StopAsyncIteration' visibility='default' filepath='./Include/pyerrors.h' line='82' column='1' elf-symbol-id='PyExc_StopAsyncIteration'/> + <var-decl name='PyExc_StopIteration' type-id='type-id-2' mangled-name='PyExc_StopIteration' visibility='default' filepath='./Include/pyerrors.h' line='84' column='1' elf-symbol-id='PyExc_StopIteration'/> + <var-decl name='PyExc_GeneratorExit' type-id='type-id-2' mangled-name='PyExc_GeneratorExit' visibility='default' filepath='./Include/pyerrors.h' line='85' column='1' elf-symbol-id='PyExc_GeneratorExit'/> + <var-decl name='PyExc_ArithmeticError' type-id='type-id-2' mangled-name='PyExc_ArithmeticError' visibility='default' filepath='./Include/pyerrors.h' line='86' column='1' elf-symbol-id='PyExc_ArithmeticError'/> + <var-decl name='PyExc_LookupError' type-id='type-id-2' mangled-name='PyExc_LookupError' visibility='default' filepath='./Include/pyerrors.h' line='87' column='1' elf-symbol-id='PyExc_LookupError'/> + <var-decl name='PyExc_AssertionError' type-id='type-id-2' mangled-name='PyExc_AssertionError' visibility='default' filepath='./Include/pyerrors.h' line='89' column='1' elf-symbol-id='PyExc_AssertionError'/> + <var-decl name='PyExc_AttributeError' type-id='type-id-2' mangled-name='PyExc_AttributeError' visibility='default' filepath='./Include/pyerrors.h' line='90' column='1' elf-symbol-id='PyExc_AttributeError'/> + <var-decl name='PyExc_BufferError' type-id='type-id-2' mangled-name='PyExc_BufferError' visibility='default' filepath='./Include/pyerrors.h' line='91' column='1' elf-symbol-id='PyExc_BufferError'/> + <var-decl name='PyExc_EOFError' type-id='type-id-2' mangled-name='PyExc_EOFError' visibility='default' filepath='./Include/pyerrors.h' line='92' column='1' elf-symbol-id='PyExc_EOFError'/> + <var-decl name='PyExc_FloatingPointError' type-id='type-id-2' mangled-name='PyExc_FloatingPointError' visibility='default' filepath='./Include/pyerrors.h' line='93' column='1' elf-symbol-id='PyExc_FloatingPointError'/> + <var-decl name='PyExc_OSError' type-id='type-id-2' mangled-name='PyExc_OSError' visibility='default' filepath='./Include/pyerrors.h' line='94' column='1' elf-symbol-id='PyExc_OSError'/> + <var-decl name='PyExc_ImportError' type-id='type-id-2' mangled-name='PyExc_ImportError' visibility='default' filepath='./Include/pyerrors.h' line='95' column='1' elf-symbol-id='PyExc_ImportError'/> + <var-decl name='PyExc_ModuleNotFoundError' type-id='type-id-2' mangled-name='PyExc_ModuleNotFoundError' visibility='default' filepath='./Include/pyerrors.h' line='97' column='1' elf-symbol-id='PyExc_ModuleNotFoundError'/> + <var-decl name='PyExc_IndexError' type-id='type-id-2' mangled-name='PyExc_IndexError' visibility='default' filepath='./Include/pyerrors.h' line='99' column='1' elf-symbol-id='PyExc_IndexError'/> + <var-decl name='PyExc_KeyError' type-id='type-id-2' mangled-name='PyExc_KeyError' visibility='default' filepath='./Include/pyerrors.h' line='100' column='1' elf-symbol-id='PyExc_KeyError'/> + <var-decl name='PyExc_KeyboardInterrupt' type-id='type-id-2' mangled-name='PyExc_KeyboardInterrupt' visibility='default' filepath='./Include/pyerrors.h' line='101' column='1' elf-symbol-id='PyExc_KeyboardInterrupt'/> + <var-decl name='PyExc_MemoryError' type-id='type-id-2' mangled-name='PyExc_MemoryError' visibility='default' filepath='./Include/pyerrors.h' line='102' column='1' elf-symbol-id='PyExc_MemoryError'/> + <var-decl name='PyExc_NameError' type-id='type-id-2' mangled-name='PyExc_NameError' visibility='default' filepath='./Include/pyerrors.h' line='103' column='1' elf-symbol-id='PyExc_NameError'/> + <var-decl name='PyExc_OverflowError' type-id='type-id-2' mangled-name='PyExc_OverflowError' visibility='default' filepath='./Include/pyerrors.h' line='104' column='1' elf-symbol-id='PyExc_OverflowError'/> + <var-decl name='PyExc_RuntimeError' type-id='type-id-2' mangled-name='PyExc_RuntimeError' visibility='default' filepath='./Include/pyerrors.h' line='105' column='1' elf-symbol-id='PyExc_RuntimeError'/> + <var-decl name='PyExc_RecursionError' type-id='type-id-2' mangled-name='PyExc_RecursionError' visibility='default' filepath='./Include/pyerrors.h' line='107' column='1' elf-symbol-id='PyExc_RecursionError'/> + <var-decl name='PyExc_NotImplementedError' type-id='type-id-2' mangled-name='PyExc_NotImplementedError' visibility='default' filepath='./Include/pyerrors.h' line='109' column='1' elf-symbol-id='PyExc_NotImplementedError'/> + <var-decl name='PyExc_SyntaxError' type-id='type-id-2' mangled-name='PyExc_SyntaxError' visibility='default' filepath='./Include/pyerrors.h' line='110' column='1' elf-symbol-id='PyExc_SyntaxError'/> + <var-decl name='PyExc_IndentationError' type-id='type-id-2' mangled-name='PyExc_IndentationError' visibility='default' filepath='./Include/pyerrors.h' line='111' column='1' elf-symbol-id='PyExc_IndentationError'/> + <var-decl name='PyExc_TabError' type-id='type-id-2' mangled-name='PyExc_TabError' visibility='default' filepath='./Include/pyerrors.h' line='112' column='1' elf-symbol-id='PyExc_TabError'/> + <var-decl name='PyExc_ReferenceError' type-id='type-id-2' mangled-name='PyExc_ReferenceError' visibility='default' filepath='./Include/pyerrors.h' line='113' column='1' elf-symbol-id='PyExc_ReferenceError'/> + <var-decl name='PyExc_SystemError' type-id='type-id-2' mangled-name='PyExc_SystemError' visibility='default' filepath='./Include/pyerrors.h' line='114' column='1' elf-symbol-id='PyExc_SystemError'/> + <var-decl name='PyExc_SystemExit' type-id='type-id-2' mangled-name='PyExc_SystemExit' visibility='default' filepath='./Include/pyerrors.h' line='115' column='1' elf-symbol-id='PyExc_SystemExit'/> + <var-decl name='PyExc_TypeError' type-id='type-id-2' mangled-name='PyExc_TypeError' visibility='default' filepath='./Include/pyerrors.h' line='116' column='1' elf-symbol-id='PyExc_TypeError'/> + <var-decl name='PyExc_UnboundLocalError' type-id='type-id-2' mangled-name='PyExc_UnboundLocalError' visibility='default' filepath='./Include/pyerrors.h' line='117' column='1' elf-symbol-id='PyExc_UnboundLocalError'/> + <var-decl name='PyExc_UnicodeError' type-id='type-id-2' mangled-name='PyExc_UnicodeError' visibility='default' filepath='./Include/pyerrors.h' line='118' column='1' elf-symbol-id='PyExc_UnicodeError'/> + <var-decl name='PyExc_UnicodeEncodeError' type-id='type-id-2' mangled-name='PyExc_UnicodeEncodeError' visibility='default' filepath='./Include/pyerrors.h' line='119' column='1' elf-symbol-id='PyExc_UnicodeEncodeError'/> + <var-decl name='PyExc_UnicodeDecodeError' type-id='type-id-2' mangled-name='PyExc_UnicodeDecodeError' visibility='default' filepath='./Include/pyerrors.h' line='120' column='1' elf-symbol-id='PyExc_UnicodeDecodeError'/> + <var-decl name='PyExc_UnicodeTranslateError' type-id='type-id-2' mangled-name='PyExc_UnicodeTranslateError' visibility='default' filepath='./Include/pyerrors.h' line='121' column='1' elf-symbol-id='PyExc_UnicodeTranslateError'/> + <var-decl name='PyExc_ValueError' type-id='type-id-2' mangled-name='PyExc_ValueError' visibility='default' filepath='./Include/pyerrors.h' line='122' column='1' elf-symbol-id='PyExc_ValueError'/> + <var-decl name='PyExc_ZeroDivisionError' type-id='type-id-2' mangled-name='PyExc_ZeroDivisionError' visibility='default' filepath='./Include/pyerrors.h' line='123' column='1' elf-symbol-id='PyExc_ZeroDivisionError'/> + <var-decl name='PyExc_BlockingIOError' type-id='type-id-2' mangled-name='PyExc_BlockingIOError' visibility='default' filepath='./Include/pyerrors.h' line='126' column='1' elf-symbol-id='PyExc_BlockingIOError'/> + <var-decl name='PyExc_BrokenPipeError' type-id='type-id-2' mangled-name='PyExc_BrokenPipeError' visibility='default' filepath='./Include/pyerrors.h' line='127' column='1' elf-symbol-id='PyExc_BrokenPipeError'/> + <var-decl name='PyExc_ChildProcessError' type-id='type-id-2' mangled-name='PyExc_ChildProcessError' visibility='default' filepath='./Include/pyerrors.h' line='128' column='1' elf-symbol-id='PyExc_ChildProcessError'/> + <var-decl name='PyExc_ConnectionError' type-id='type-id-2' mangled-name='PyExc_ConnectionError' visibility='default' filepath='./Include/pyerrors.h' line='129' column='1' elf-symbol-id='PyExc_ConnectionError'/> + <var-decl name='PyExc_ConnectionAbortedError' type-id='type-id-2' mangled-name='PyExc_ConnectionAbortedError' visibility='default' filepath='./Include/pyerrors.h' line='130' column='1' elf-symbol-id='PyExc_ConnectionAbortedError'/> + <var-decl name='PyExc_ConnectionRefusedError' type-id='type-id-2' mangled-name='PyExc_ConnectionRefusedError' visibility='default' filepath='./Include/pyerrors.h' line='131' column='1' elf-symbol-id='PyExc_ConnectionRefusedError'/> + <var-decl name='PyExc_ConnectionResetError' type-id='type-id-2' mangled-name='PyExc_ConnectionResetError' visibility='default' filepath='./Include/pyerrors.h' line='132' column='1' elf-symbol-id='PyExc_ConnectionResetError'/> + <var-decl name='PyExc_FileExistsError' type-id='type-id-2' mangled-name='PyExc_FileExistsError' visibility='default' filepath='./Include/pyerrors.h' line='133' column='1' elf-symbol-id='PyExc_FileExistsError'/> + <var-decl name='PyExc_FileNotFoundError' type-id='type-id-2' mangled-name='PyExc_FileNotFoundError' visibility='default' filepath='./Include/pyerrors.h' line='134' column='1' elf-symbol-id='PyExc_FileNotFoundError'/> + <var-decl name='PyExc_InterruptedError' type-id='type-id-2' mangled-name='PyExc_InterruptedError' visibility='default' filepath='./Include/pyerrors.h' line='135' column='1' elf-symbol-id='PyExc_InterruptedError'/> + <var-decl name='PyExc_IsADirectoryError' type-id='type-id-2' mangled-name='PyExc_IsADirectoryError' visibility='default' filepath='./Include/pyerrors.h' line='136' column='1' elf-symbol-id='PyExc_IsADirectoryError'/> + <var-decl name='PyExc_NotADirectoryError' type-id='type-id-2' mangled-name='PyExc_NotADirectoryError' visibility='default' filepath='./Include/pyerrors.h' line='137' column='1' elf-symbol-id='PyExc_NotADirectoryError'/> + <var-decl name='PyExc_PermissionError' type-id='type-id-2' mangled-name='PyExc_PermissionError' visibility='default' filepath='./Include/pyerrors.h' line='138' column='1' elf-symbol-id='PyExc_PermissionError'/> + <var-decl name='PyExc_ProcessLookupError' type-id='type-id-2' mangled-name='PyExc_ProcessLookupError' visibility='default' filepath='./Include/pyerrors.h' line='139' column='1' elf-symbol-id='PyExc_ProcessLookupError'/> + <var-decl name='PyExc_TimeoutError' type-id='type-id-2' mangled-name='PyExc_TimeoutError' visibility='default' filepath='./Include/pyerrors.h' line='140' column='1' elf-symbol-id='PyExc_TimeoutError'/> + <var-decl name='PyExc_EnvironmentError' type-id='type-id-2' mangled-name='PyExc_EnvironmentError' visibility='default' filepath='./Include/pyerrors.h' line='145' column='1' elf-symbol-id='PyExc_EnvironmentError'/> + <var-decl name='PyExc_IOError' type-id='type-id-2' mangled-name='PyExc_IOError' visibility='default' filepath='./Include/pyerrors.h' line='146' column='1' elf-symbol-id='PyExc_IOError'/> + <var-decl name='PyExc_Warning' type-id='type-id-2' mangled-name='PyExc_Warning' visibility='default' filepath='./Include/pyerrors.h' line='152' column='1' elf-symbol-id='PyExc_Warning'/> + <var-decl name='PyExc_UserWarning' type-id='type-id-2' mangled-name='PyExc_UserWarning' visibility='default' filepath='./Include/pyerrors.h' line='153' column='1' elf-symbol-id='PyExc_UserWarning'/> + <var-decl name='PyExc_DeprecationWarning' type-id='type-id-2' mangled-name='PyExc_DeprecationWarning' visibility='default' filepath='./Include/pyerrors.h' line='154' column='1' elf-symbol-id='PyExc_DeprecationWarning'/> + <var-decl name='PyExc_PendingDeprecationWarning' type-id='type-id-2' mangled-name='PyExc_PendingDeprecationWarning' visibility='default' filepath='./Include/pyerrors.h' line='155' column='1' elf-symbol-id='PyExc_PendingDeprecationWarning'/> + <var-decl name='PyExc_SyntaxWarning' type-id='type-id-2' mangled-name='PyExc_SyntaxWarning' visibility='default' filepath='./Include/pyerrors.h' line='156' column='1' elf-symbol-id='PyExc_SyntaxWarning'/> + <var-decl name='PyExc_RuntimeWarning' type-id='type-id-2' mangled-name='PyExc_RuntimeWarning' visibility='default' filepath='./Include/pyerrors.h' line='157' column='1' elf-symbol-id='PyExc_RuntimeWarning'/> + <var-decl name='PyExc_FutureWarning' type-id='type-id-2' mangled-name='PyExc_FutureWarning' visibility='default' filepath='./Include/pyerrors.h' line='158' column='1' elf-symbol-id='PyExc_FutureWarning'/> + <var-decl name='PyExc_ImportWarning' type-id='type-id-2' mangled-name='PyExc_ImportWarning' visibility='default' filepath='./Include/pyerrors.h' line='159' column='1' elf-symbol-id='PyExc_ImportWarning'/> + <var-decl name='PyExc_UnicodeWarning' type-id='type-id-2' mangled-name='PyExc_UnicodeWarning' visibility='default' filepath='./Include/pyerrors.h' line='160' column='1' elf-symbol-id='PyExc_UnicodeWarning'/> + <var-decl name='PyExc_BytesWarning' type-id='type-id-2' mangled-name='PyExc_BytesWarning' visibility='default' filepath='./Include/pyerrors.h' line='161' column='1' elf-symbol-id='PyExc_BytesWarning'/> + <var-decl name='PyExc_EncodingWarning' type-id='type-id-2' mangled-name='PyExc_EncodingWarning' visibility='default' filepath='./Include/pyerrors.h' line='162' column='1' elf-symbol-id='PyExc_EncodingWarning'/> + <var-decl name='PyExc_ResourceWarning' type-id='type-id-2' mangled-name='PyExc_ResourceWarning' visibility='default' filepath='./Include/pyerrors.h' line='163' column='1' elf-symbol-id='PyExc_ResourceWarning'/> + <function-decl name='PyErr_NewException' mangled-name='PyErr_NewException' filepath='./Include/pyerrors.h' line='231' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_NewException'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySet_New' mangled-name='PySet_New' filepath='./Include/setobject.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_New'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySet_Add' mangled-name='PySet_Add' filepath='./Include/setobject.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_Add'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySet_Contains' mangled-name='PySet_Contains' filepath='./Include/setobject.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_Contains'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyTuple_Size' mangled-name='PyTuple_Size' filepath='./Include/tupleobject.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTuple_Size'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_ReadChar' mangled-name='PyUnicode_ReadChar' filepath='./Include/unicodeobject.h' line='177' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_ReadChar'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-250'/> + </function-decl> + <function-decl name='PyException_GetTraceback' mangled-name='PyException_GetTraceback' filepath='Objects/exceptions.c' line='378' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_GetTraceback'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='378' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyException_SetTraceback' mangled-name='PyException_SetTraceback' filepath='Objects/exceptions.c' line='386' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_SetTraceback'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='386' column='1'/> + <parameter type-id='type-id-2' name='tb' filepath='Objects/exceptions.c' line='386' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyException_GetCause' mangled-name='PyException_GetCause' filepath='Objects/exceptions.c' line='392' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_GetCause'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='392' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyException_SetCause' mangled-name='PyException_SetCause' filepath='Objects/exceptions.c' line='400' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_SetCause'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='400' column='1'/> + <parameter type-id='type-id-2' name='cause' filepath='Objects/exceptions.c' line='400' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyException_GetContext' mangled-name='PyException_GetContext' filepath='Objects/exceptions.c' line='408' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_GetContext'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='408' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyException_SetContext' mangled-name='PyException_SetContext' filepath='Objects/exceptions.c' line='416' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_SetContext'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='416' column='1'/> + <parameter type-id='type-id-2' name='context' filepath='Objects/exceptions.c' line='416' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyException_GetArgs' mangled-name='PyException_GetArgs' filepath='Objects/exceptions.c' line='422' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_GetArgs'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='422' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyException_SetArgs' mangled-name='PyException_SetArgs' filepath='Objects/exceptions.c' line='429' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyException_SetArgs'> + <parameter type-id='type-id-2' name='self' filepath='Objects/exceptions.c' line='429' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/exceptions.c' line='429' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyExceptionClass_Name' mangled-name='PyExceptionClass_Name' filepath='Objects/exceptions.c' line='436' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyExceptionClass_Name'> + <parameter type-id='type-id-2' name='ob' filepath='Objects/exceptions.c' line='436' column='1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_PyExc_CreateExceptionGroup' mangled-name='_PyExc_CreateExceptionGroup' filepath='Objects/exceptions.c' line='811' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyExc_CreateExceptionGroup'> + <parameter type-id='type-id-12' name='msg_str' filepath='Objects/exceptions.c' line='811' column='1'/> + <parameter type-id='type-id-2' name='excs' filepath='Objects/exceptions.c' line='811' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyExc_PrepReraiseStar' mangled-name='_PyExc_PrepReraiseStar' filepath='Objects/exceptions.c' line='1352' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyExc_PrepReraiseStar'> + <parameter type-id='type-id-2' name='orig' filepath='Objects/exceptions.c' line='1352' column='1'/> + <parameter type-id='type-id-2' name='excs' filepath='Objects/exceptions.c' line='1352' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_GetEncoding' mangled-name='PyUnicodeEncodeError_GetEncoding' filepath='Objects/exceptions.c' line='2641' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_GetEncoding'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2641' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_GetEncoding' mangled-name='PyUnicodeDecodeError_GetEncoding' filepath='Objects/exceptions.c' line='2647' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_GetEncoding'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2647' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_GetObject' mangled-name='PyUnicodeEncodeError_GetObject' filepath='Objects/exceptions.c' line='2653' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_GetObject'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2653' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_GetObject' mangled-name='PyUnicodeDecodeError_GetObject' filepath='Objects/exceptions.c' line='2659' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_GetObject'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2659' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_GetObject' mangled-name='PyUnicodeTranslateError_GetObject' filepath='Objects/exceptions.c' line='2665' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_GetObject'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2665' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_GetStart' mangled-name='PyUnicodeEncodeError_GetStart' filepath='Objects/exceptions.c' line='2671' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_GetStart'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2671' column='1'/> + <parameter type-id='type-id-13' name='start' filepath='Objects/exceptions.c' line='2671' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_GetStart' mangled-name='PyUnicodeDecodeError_GetStart' filepath='Objects/exceptions.c' line='2690' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_GetStart'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2690' column='1'/> + <parameter type-id='type-id-13' name='start' filepath='Objects/exceptions.c' line='2690' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_GetStart' mangled-name='PyUnicodeTranslateError_GetStart' filepath='Objects/exceptions.c' line='2708' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_GetStart'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2708' column='1'/> + <parameter type-id='type-id-13' name='start' filepath='Objects/exceptions.c' line='2708' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_SetStart' mangled-name='PyUnicodeEncodeError_SetStart' filepath='Objects/exceptions.c' line='2715' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_SetStart'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2715' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/exceptions.c' line='2715' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_SetStart' mangled-name='PyUnicodeDecodeError_SetStart' filepath='Objects/exceptions.c' line='2723' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_SetStart'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2723' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/exceptions.c' line='2723' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_SetStart' mangled-name='PyUnicodeTranslateError_SetStart' filepath='Objects/exceptions.c' line='2731' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_SetStart'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2731' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/exceptions.c' line='2731' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_GetEnd' mangled-name='PyUnicodeEncodeError_GetEnd' filepath='Objects/exceptions.c' line='2739' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_GetEnd'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2739' column='1'/> + <parameter type-id='type-id-13' name='end' filepath='Objects/exceptions.c' line='2739' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_GetEnd' mangled-name='PyUnicodeDecodeError_GetEnd' filepath='Objects/exceptions.c' line='2758' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_GetEnd'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2758' column='1'/> + <parameter type-id='type-id-13' name='end' filepath='Objects/exceptions.c' line='2758' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_GetEnd' mangled-name='PyUnicodeTranslateError_GetEnd' filepath='Objects/exceptions.c' line='2776' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_GetEnd'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2776' column='1'/> + <parameter type-id='type-id-13' name='end' filepath='Objects/exceptions.c' line='2776' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_SetEnd' mangled-name='PyUnicodeEncodeError_SetEnd' filepath='Objects/exceptions.c' line='2783' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_SetEnd'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2783' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/exceptions.c' line='2783' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_SetEnd' mangled-name='PyUnicodeDecodeError_SetEnd' filepath='Objects/exceptions.c' line='2791' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_SetEnd'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2791' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/exceptions.c' line='2791' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_SetEnd' mangled-name='PyUnicodeTranslateError_SetEnd' filepath='Objects/exceptions.c' line='2799' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_SetEnd'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2799' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/exceptions.c' line='2799' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_GetReason' mangled-name='PyUnicodeEncodeError_GetReason' filepath='Objects/exceptions.c' line='2806' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_GetReason'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2806' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_GetReason' mangled-name='PyUnicodeDecodeError_GetReason' filepath='Objects/exceptions.c' line='2813' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_GetReason'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2813' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_GetReason' mangled-name='PyUnicodeTranslateError_GetReason' filepath='Objects/exceptions.c' line='2820' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_GetReason'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2820' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicodeEncodeError_SetReason' mangled-name='PyUnicodeEncodeError_SetReason' filepath='Objects/exceptions.c' line='2827' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeEncodeError_SetReason'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2827' column='1'/> + <parameter type-id='type-id-12' name='reason' filepath='Objects/exceptions.c' line='2827' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_SetReason' mangled-name='PyUnicodeDecodeError_SetReason' filepath='Objects/exceptions.c' line='2835' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_SetReason'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2835' column='1'/> + <parameter type-id='type-id-12' name='reason' filepath='Objects/exceptions.c' line='2835' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeTranslateError_SetReason' mangled-name='PyUnicodeTranslateError_SetReason' filepath='Objects/exceptions.c' line='2843' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeTranslateError_SetReason'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='2843' column='1'/> + <parameter type-id='type-id-12' name='reason' filepath='Objects/exceptions.c' line='2843' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicodeDecodeError_Create' mangled-name='PyUnicodeDecodeError_Create' filepath='Objects/exceptions.c' line='3096' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicodeDecodeError_Create'> + <parameter type-id='type-id-12' name='encoding' filepath='Objects/exceptions.c' line='3097' column='1'/> + <parameter type-id='type-id-12' name='object' filepath='Objects/exceptions.c' line='3097' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Objects/exceptions.c' line='3097' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/exceptions.c' line='3098' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/exceptions.c' line='3098' column='1'/> + <parameter type-id='type-id-12' name='reason' filepath='Objects/exceptions.c' line='3098' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicodeTranslateError_Create' mangled-name='_PyUnicodeTranslateError_Create' filepath='Objects/exceptions.c' line='3193' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeTranslateError_Create'> + <parameter type-id='type-id-2' name='object' filepath='Objects/exceptions.c' line='3194' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/exceptions.c' line='3195' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/exceptions.c' line='3195' column='1'/> + <parameter type-id='type-id-12' name='reason' filepath='Objects/exceptions.c' line='3195' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyException_AddNote' mangled-name='_PyException_AddNote' filepath='Objects/exceptions.c' line='3794' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyException_AddNote'> + <parameter type-id='type-id-2' name='exc' filepath='Objects/exceptions.c' line='3794' column='1'/> + <parameter type-id='type-id-2' name='note' filepath='Objects/exceptions.c' line='3794' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/fileobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyStdPrinter_Type' type-id='type-id-256' mangled-name='PyStdPrinter_Type' visibility='default' filepath='./Include/cpython/fileobject.h' line='11' column='1' elf-symbol-id='PyStdPrinter_Type'/> + <function-decl name='_PyUnicode_AsUTF8String' mangled-name='_PyUnicode_AsUTF8String' filepath='./Include/cpython/unicodeobject.h' line='640' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_AsUTF8String'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_write' mangled-name='_Py_write' filepath='./Include/internal/pycore_fileutils.h' line='122' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_write'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='Py_IsInitialized' mangled-name='Py_IsInitialized' filepath='./Include/pylifecycle.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_IsInitialized'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='getc_unlocked' filepath='/usr/include/stdio.h' line='527' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='flockfile' filepath='/usr/include/stdio.h' line='867' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='funlockfile' filepath='/usr/include/stdio.h' line='874' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyFile_FromFd' mangled-name='PyFile_FromFd' filepath='Objects/fileobject.c' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_FromFd'> + <parameter type-id='type-id-8' name='fd' filepath='Objects/fileobject.c' line='32' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/fileobject.c' line='32' column='1'/> + <parameter type-id='type-id-12' name='mode' filepath='Objects/fileobject.c' line='32' column='1'/> + <parameter type-id='type-id-8' name='buffering' filepath='Objects/fileobject.c' line='32' column='1'/> + <parameter type-id='type-id-12' name='encoding' filepath='Objects/fileobject.c' line='32' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/fileobject.c' line='33' column='1'/> + <parameter type-id='type-id-12' name='newline' filepath='Objects/fileobject.c' line='33' column='1'/> + <parameter type-id='type-id-8' name='closefd' filepath='Objects/fileobject.c' line='33' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFile_GetLine' mangled-name='PyFile_GetLine' filepath='Objects/fileobject.c' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_GetLine'> + <parameter type-id='type-id-2' name='f' filepath='Objects/fileobject.c' line='53' column='1'/> + <parameter type-id='type-id-8' name='n' filepath='Objects/fileobject.c' line='53' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFile_WriteObject' mangled-name='PyFile_WriteObject' filepath='Objects/fileobject.c' line='112' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_WriteObject'> + <parameter type-id='type-id-2' name='v' filepath='Objects/fileobject.c' line='112' column='1'/> + <parameter type-id='type-id-2' name='f' filepath='Objects/fileobject.c' line='112' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/fileobject.c' line='112' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFile_WriteString' mangled-name='PyFile_WriteString' filepath='Objects/fileobject.c' line='142' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_WriteString'> + <parameter type-id='type-id-12' name='s' filepath='Objects/fileobject.c' line='142' column='1'/> + <parameter type-id='type-id-2' name='f' filepath='Objects/fileobject.c' line='142' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_AsFileDescriptor' mangled-name='PyObject_AsFileDescriptor' filepath='Objects/fileobject.c' line='172' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_AsFileDescriptor'> + <parameter type-id='type-id-2' name='o' filepath='Objects/fileobject.c' line='172' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_FileDescriptor_Converter' mangled-name='_PyLong_FileDescriptor_Converter' filepath='Objects/fileobject.c' line='218' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FileDescriptor_Converter'> + <parameter type-id='type-id-2' name='o' filepath='Objects/fileobject.c' line='218' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/fileobject.c' line='218' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_UniversalNewlineFgets' mangled-name='Py_UniversalNewlineFgets' filepath='Objects/fileobject.c' line='272' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_UniversalNewlineFgets'> + <parameter type-id='type-id-15' name='buf' filepath='Objects/fileobject.c' line='272' column='1'/> + <parameter type-id='type-id-8' name='n' filepath='Objects/fileobject.c' line='272' column='1'/> + <parameter type-id='type-id-229' name='stream' filepath='Objects/fileobject.c' line='272' column='1'/> + <parameter type-id='type-id-2' name='fobj' filepath='Objects/fileobject.c' line='272' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyFile_NewStdPrinter' mangled-name='PyFile_NewStdPrinter' filepath='Objects/fileobject.c' line='288' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_NewStdPrinter'> + <parameter type-id='type-id-8' name='fd' filepath='Objects/fileobject.c' line='288' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFile_SetOpenCodeHook' mangled-name='PyFile_SetOpenCodeHook' filepath='Objects/fileobject.c' line='475' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_SetOpenCodeHook'> + <parameter type-id='type-id-355' name='hook' filepath='Objects/fileobject.c' line='475' column='1'/> + <parameter type-id='type-id-22' name='userData' filepath='Objects/fileobject.c' line='475' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFile_OpenCodeObject' mangled-name='PyFile_OpenCodeObject' filepath='Objects/fileobject.c' line='495' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_OpenCodeObject'> + <parameter type-id='type-id-2' name='path' filepath='Objects/fileobject.c' line='495' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFile_OpenCode' mangled-name='PyFile_OpenCode' filepath='Objects/fileobject.c' line='520' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFile_OpenCode'> + <parameter type-id='type-id-12' name='utf8path' filepath='Objects/fileobject.c' line='520' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/floatobject.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyStructSequence_Field' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/structseq.h' line='10' column='1' id='type-id-356'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/structseq.h' line='11' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='doc' type-id='type-id-12' visibility='default' filepath='./Include/structseq.h' line='12' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyStructSequence_Field' type-id='type-id-356' filepath='./Include/structseq.h' line='13' column='1' id='type-id-357'/> + <class-decl name='PyStructSequence_Desc' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/structseq.h' line='15' column='1' id='type-id-358'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/structseq.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='doc' type-id='type-id-12' visibility='default' filepath='./Include/structseq.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='fields' type-id='type-id-359' visibility='default' filepath='./Include/structseq.h' line='18' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='n_in_sequence' type-id='type-id-8' visibility='default' filepath='./Include/structseq.h' line='19' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyStructSequence_Desc' type-id='type-id-358' filepath='./Include/structseq.h' line='20' column='1' id='type-id-360'/> + <pointer-type-def type-id='type-id-360' size-in-bits='64' id='type-id-361'/> + <pointer-type-def type-id='type-id-357' size-in-bits='64' id='type-id-359'/> + <qualified-type-def type-id='type-id-239' restrict='yes' id='type-id-184'/> + <qualified-type-def type-id='type-id-12' restrict='yes' id='type-id-181'/> + <function-decl name='_PyLong_Sign' mangled-name='_PyLong_Sign' filepath='./Include/cpython/longobject.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Sign'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_NumBits' mangled-name='_PyLong_NumBits' filepath='./Include/cpython/longobject.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_NumBits'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='_PyLong_Lshift' mangled-name='_PyLong_Lshift' filepath='./Include/cpython/longobject.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Lshift'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDebugAllocatorStats' mangled-name='_PyDebugAllocatorStats' filepath='./Include/cpython/object.h' line='398' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDebugAllocatorStats'> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-46'/> + </function-decl> + <var-decl name='PyFloat_Type' type-id='type-id-256' mangled-name='PyFloat_Type' visibility='default' filepath='./Include/floatobject.h' line='14' column='1' elf-symbol-id='PyFloat_Type'/> + <function-decl name='_Py_dg_strtod' mangled-name='_Py_dg_strtod' filepath='./Include/internal/pycore_dtoa.h' line='63' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_dg_strtod'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='_Py_dg_dtoa' mangled-name='_Py_dg_dtoa' filepath='./Include/internal/pycore_dtoa.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_dg_dtoa'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-239'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_Py_dg_freedtoa' mangled-name='_Py_dg_freedtoa' filepath='./Include/internal/pycore_dtoa.h' line='66' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_dg_freedtoa'> + <parameter type-id='type-id-15'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFloat_FormatAdvancedWriter' mangled-name='_PyFloat_FormatAdvancedWriter' filepath='./Include/internal/pycore_floatobject.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyFloat_FormatAdvancedWriter'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_get_387controlword' filepath='./Include/internal/pycore_pymath.h' line='90' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-84'/> + </function-decl> + <function-decl name='_Py_set_387controlword' filepath='./Include/internal/pycore_pymath.h' line='91' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-84'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyStructSequence_InitBuiltinWithFlags' filepath='./Include/internal/pycore_structseq.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-361'/> + <parameter type-id='type-id-28'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyStructSequence_FiniBuiltin' filepath='./Include/internal/pycore_structseq.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyLong_FromDouble' mangled-name='PyLong_FromDouble' filepath='./Include/longobject.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromDouble'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SetFromErrno' mangled-name='PyErr_SetFromErrno' filepath='./Include/pyerrors.h' line='170' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetFromErrno'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_parse_inf_or_nan' mangled-name='_Py_parse_inf_or_nan' filepath='./Include/pystrtod.h' line='26' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_parse_inf_or_nan'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyStructSequence_New' mangled-name='PyStructSequence_New' filepath='./Include/structseq.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStructSequence_New'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='strtol' filepath='/usr/include/stdlib.h' line='177' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-184'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='frexp' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='98' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='ldexp' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='101' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='modf' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='110' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-182'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='ceil' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='159' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='fmod' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='168' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='round' filepath='/usr/include/x86_64-linux-gnu/bits/mathcalls.h' line='301' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyFloat_GetMax' mangled-name='PyFloat_GetMax' filepath='Objects/floatobject.c' line='44' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_GetMax'> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyFloat_GetMin' mangled-name='PyFloat_GetMin' filepath='Objects/floatobject.c' line='50' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_GetMin'> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyFloat_GetInfo' mangled-name='PyFloat_GetInfo' filepath='Objects/floatobject.c' line='94' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_GetInfo'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyFloat_DebugMallocStats' mangled-name='_PyFloat_DebugMallocStats' filepath='Objects/floatobject.c' line='2037' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyFloat_DebugMallocStats'> + <parameter type-id='type-id-229' name='out' filepath='Objects/floatobject.c' line='2037' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyFloat_Pack2' mangled-name='PyFloat_Pack2' filepath='Objects/floatobject.c' line='2060' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_Pack2'> + <parameter type-id='type-id-251' name='x' filepath='Objects/floatobject.c' line='2060' column='1'/> + <parameter type-id='type-id-15' name='data' filepath='Objects/floatobject.c' line='2060' column='1'/> + <parameter type-id='type-id-8' name='le' filepath='Objects/floatobject.c' line='2060' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFloat_Pack4' mangled-name='PyFloat_Pack4' filepath='Objects/floatobject.c' line='2165' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_Pack4'> + <parameter type-id='type-id-251' name='x' filepath='Objects/floatobject.c' line='2165' column='1'/> + <parameter type-id='type-id-15' name='data' filepath='Objects/floatobject.c' line='2165' column='1'/> + <parameter type-id='type-id-8' name='le' filepath='Objects/floatobject.c' line='2165' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFloat_Pack8' mangled-name='PyFloat_Pack8' filepath='Objects/floatobject.c' line='2273' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_Pack8'> + <parameter type-id='type-id-251' name='x' filepath='Objects/floatobject.c' line='2273' column='1'/> + <parameter type-id='type-id-15' name='data' filepath='Objects/floatobject.c' line='2273' column='1'/> + <parameter type-id='type-id-8' name='le' filepath='Objects/floatobject.c' line='2273' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFloat_Unpack2' mangled-name='PyFloat_Unpack2' filepath='Objects/floatobject.c' line='2403' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_Unpack2'> + <parameter type-id='type-id-12' name='data' filepath='Objects/floatobject.c' line='2403' column='1'/> + <parameter type-id='type-id-8' name='le' filepath='Objects/floatobject.c' line='2403' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyFloat_Unpack4' mangled-name='PyFloat_Unpack4' filepath='Objects/floatobject.c' line='2455' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_Unpack4'> + <parameter type-id='type-id-12' name='data' filepath='Objects/floatobject.c' line='2455' column='1'/> + <parameter type-id='type-id-8' name='le' filepath='Objects/floatobject.c' line='2455' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyFloat_Unpack8' mangled-name='PyFloat_Unpack8' filepath='Objects/floatobject.c' line='2534' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_Unpack8'> + <parameter type-id='type-id-12' name='data' filepath='Objects/floatobject.c' line='2534' column='1'/> + <parameter type-id='type-id-8' name='le' filepath='Objects/floatobject.c' line='2534' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/frameobject.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyFrameConstructor' size-in-bits='512' is-struct='yes' naming-typedef-id='type-id-362' visibility='default' filepath='./Include/cpython/funcobject.h' line='21' column='1' id='type-id-363'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='fc_globals' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='fc_builtins' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='fc_name' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='fc_qualname' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='fc_code' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='fc_defaults' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='fc_kwdefaults' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='fc_closure' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='22' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyFrameConstructor' type-id='type-id-363' filepath='./Include/cpython/funcobject.h' line='23' column='1' id='type-id-362'/> + <pointer-type-def type-id='type-id-362' size-in-bits='64' id='type-id-364'/> + <function-decl name='PyCompile_OpcodeStackEffect' mangled-name='PyCompile_OpcodeStackEffect' filepath='./Include/cpython/compile.h' line='68' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCompile_OpcodeStackEffect'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyFrame_Type' type-id='type-id-256' mangled-name='PyFrame_Type' visibility='default' filepath='./Include/cpython/pyframe.h' line='5' column='1' elf-symbol-id='PyFrame_Type'/> + <function-decl name='_PyUnicode_Equal' mangled-name='_PyUnicode_Equal' filepath='./Include/cpython/unicodeobject.h' line='956' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_Equal'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_GetBuiltins' filepath='./Include/internal/pycore_ceval.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCode_GetCode' filepath='./Include/internal/pycore_code.h' line='209' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCode_InitAddressRange' filepath='./Include/internal/pycore_code.h' line='212' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <parameter type-id='type-id-320'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLineTable_NextAddressRange' filepath='./Include/internal/pycore_code.h' line='222' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-320'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyFunction_FromConstructor' filepath='./Include/internal/pycore_function.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-364'/> + <return type-id='type-id-310'/> + </function-decl> + <function-decl name='PyThreadState_Get' mangled-name='PyThreadState_Get' filepath='./Include/pystate.h' line='60' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_Get'> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='PyFrame_GetLineNumber' mangled-name='PyFrame_GetLineNumber' filepath='Objects/frameobject.c' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetLineNumber'> + <parameter type-id='type-id-365' name='f' filepath='Objects/frameobject.c' line='34' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFrame_New' mangled-name='PyFrame_New' filepath='Objects/frameobject.c' line='1062' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_New'> + <parameter type-id='type-id-177' name='tstate' filepath='Objects/frameobject.c' line='1062' column='1'/> + <parameter type-id='type-id-328' name='code' filepath='Objects/frameobject.c' line='1062' column='1'/> + <parameter type-id='type-id-2' name='globals' filepath='Objects/frameobject.c' line='1063' column='1'/> + <parameter type-id='type-id-2' name='locals' filepath='Objects/frameobject.c' line='1063' column='1'/> + <return type-id='type-id-365'/> + </function-decl> + <function-decl name='PyFrame_GetVar' mangled-name='PyFrame_GetVar' filepath='Objects/frameobject.c' line='1249' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetVar'> + <parameter type-id='type-id-365' name='frame_obj' filepath='Objects/frameobject.c' line='1249' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/frameobject.c' line='1249' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFrame_GetVarString' mangled-name='PyFrame_GetVarString' filepath='Objects/frameobject.c' line='1283' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetVarString'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1283' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/frameobject.c' line='1283' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFrame_FastToLocalsWithError' mangled-name='PyFrame_FastToLocalsWithError' filepath='Objects/frameobject.c' line='1296' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_FastToLocalsWithError'> + <parameter type-id='type-id-365' name='f' filepath='Objects/frameobject.c' line='1296' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFrame_FastToLocals' mangled-name='PyFrame_FastToLocals' filepath='Objects/frameobject.c' line='1311' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_FastToLocals'> + <parameter type-id='type-id-365' name='f' filepath='Objects/frameobject.c' line='1311' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyFrame_LocalsToFast' mangled-name='PyFrame_LocalsToFast' filepath='Objects/frameobject.c' line='1397' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_LocalsToFast'> + <parameter type-id='type-id-365' name='f' filepath='Objects/frameobject.c' line='1397' column='1'/> + <parameter type-id='type-id-8' name='clear' filepath='Objects/frameobject.c' line='1397' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFrame_IsEntryFrame' mangled-name='_PyFrame_IsEntryFrame' filepath='Objects/frameobject.c' line='1407' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyFrame_IsEntryFrame'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1407' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFrame_GetCode' mangled-name='PyFrame_GetCode' filepath='Objects/frameobject.c' line='1416' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetCode'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1416' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='PyFrame_GetBack' mangled-name='PyFrame_GetBack' filepath='Objects/frameobject.c' line='1427' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetBack'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1427' column='1'/> + <return type-id='type-id-365'/> + </function-decl> + <function-decl name='PyFrame_GetLocals' mangled-name='PyFrame_GetLocals' filepath='Objects/frameobject.c' line='1443' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetLocals'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1443' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFrame_GetGlobals' mangled-name='PyFrame_GetGlobals' filepath='Objects/frameobject.c' line='1450' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetGlobals'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1450' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFrame_GetBuiltins' mangled-name='PyFrame_GetBuiltins' filepath='Objects/frameobject.c' line='1457' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetBuiltins'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1457' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFrame_GetLasti' mangled-name='PyFrame_GetLasti' filepath='Objects/frameobject.c' line='1464' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetLasti'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1464' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFrame_GetGenerator' mangled-name='PyFrame_GetGenerator' filepath='Objects/frameobject.c' line='1475' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFrame_GetGenerator'> + <parameter type-id='type-id-365' name='frame' filepath='Objects/frameobject.c' line='1475' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/funcobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyFunction_Type' type-id='type-id-256' mangled-name='PyFunction_Type' visibility='default' filepath='./Include/cpython/funcobject.h' line='63' column='1' elf-symbol-id='PyFunction_Type'/> + <var-decl name='PyClassMethod_Type' type-id='type-id-256' mangled-name='PyClassMethod_Type' visibility='default' filepath='./Include/cpython/funcobject.h' line='129' column='1' elf-symbol-id='PyClassMethod_Type'/> + <var-decl name='PyStaticMethod_Type' type-id='type-id-256' mangled-name='PyStaticMethod_Type' visibility='default' filepath='./Include/cpython/funcobject.h' line='130' column='1' elf-symbol-id='PyStaticMethod_Type'/> + <function-decl name='PyDict_GetItem' mangled-name='PyDict_GetItem' filepath='./Include/dictobject.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyDict_GetItem'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyEval_BuiltinsFromGlobals' filepath='./Include/internal/pycore_ceval.h' line='56' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_AddWatcher' mangled-name='PyFunction_AddWatcher' filepath='Objects/funcobject.c' line='73' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_AddWatcher'> + <parameter type-id='type-id-366' name='callback' filepath='Objects/funcobject.c' line='73' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFunction_ClearWatcher' mangled-name='PyFunction_ClearWatcher' filepath='Objects/funcobject.c' line='89' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_ClearWatcher'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/funcobject.c' line='89' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFunction_NewWithQualName' mangled-name='PyFunction_NewWithQualName' filepath='Objects/funcobject.c' line='139' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_NewWithQualName'> + <parameter type-id='type-id-2' name='code' filepath='Objects/funcobject.c' line='139' column='1'/> + <parameter type-id='type-id-2' name='globals' filepath='Objects/funcobject.c' line='139' column='1'/> + <parameter type-id='type-id-2' name='qualname' filepath='Objects/funcobject.c' line='139' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_New' mangled-name='PyFunction_New' filepath='Objects/funcobject.c' line='242' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_New'> + <parameter type-id='type-id-2' name='code' filepath='Objects/funcobject.c' line='242' column='1'/> + <parameter type-id='type-id-2' name='globals' filepath='Objects/funcobject.c' line='242' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_GetCode' mangled-name='PyFunction_GetCode' filepath='Objects/funcobject.c' line='248' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetCode'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='248' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_GetGlobals' mangled-name='PyFunction_GetGlobals' filepath='Objects/funcobject.c' line='258' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetGlobals'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='258' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_GetModule' mangled-name='PyFunction_GetModule' filepath='Objects/funcobject.c' line='268' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetModule'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='268' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_GetDefaults' mangled-name='PyFunction_GetDefaults' filepath='Objects/funcobject.c' line='278' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetDefaults'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='278' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_SetDefaults' mangled-name='PyFunction_SetDefaults' filepath='Objects/funcobject.c' line='288' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_SetDefaults'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='288' column='1'/> + <parameter type-id='type-id-2' name='defaults' filepath='Objects/funcobject.c' line='288' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFunction_SetVectorcall' mangled-name='PyFunction_SetVectorcall' filepath='Objects/funcobject.c' line='311' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_SetVectorcall'> + <parameter type-id='type-id-310' name='func' filepath='Objects/funcobject.c' line='311' column='1'/> + <parameter type-id='type-id-311' name='vectorcall' filepath='Objects/funcobject.c' line='311' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyFunction_GetKwDefaults' mangled-name='PyFunction_GetKwDefaults' filepath='Objects/funcobject.c' line='319' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetKwDefaults'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='319' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_SetKwDefaults' mangled-name='PyFunction_SetKwDefaults' filepath='Objects/funcobject.c' line='329' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_SetKwDefaults'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='329' column='1'/> + <parameter type-id='type-id-2' name='defaults' filepath='Objects/funcobject.c' line='329' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFunction_GetClosure' mangled-name='PyFunction_GetClosure' filepath='Objects/funcobject.c' line='353' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetClosure'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='353' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_SetClosure' mangled-name='PyFunction_SetClosure' filepath='Objects/funcobject.c' line='363' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_SetClosure'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='363' column='1'/> + <parameter type-id='type-id-2' name='closure' filepath='Objects/funcobject.c' line='363' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyFunction_GetAnnotations' mangled-name='PyFunction_GetAnnotations' filepath='Objects/funcobject.c' line='416' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_GetAnnotations'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='416' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyFunction_SetAnnotations' mangled-name='PyFunction_SetAnnotations' filepath='Objects/funcobject.c' line='426' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFunction_SetAnnotations'> + <parameter type-id='type-id-2' name='op' filepath='Objects/funcobject.c' line='426' column='1'/> + <parameter type-id='type-id-2' name='annotations' filepath='Objects/funcobject.c' line='426' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyClassMethod_New' mangled-name='PyClassMethod_New' filepath='Objects/funcobject.c' line='1165' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyClassMethod_New'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/funcobject.c' line='1165' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyStaticMethod_New' mangled-name='PyStaticMethod_New' filepath='Objects/funcobject.c' line='1358' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStaticMethod_New'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/funcobject.c' line='1358' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/genericaliasobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyUnicodeWriter_WriteASCIIString' mangled-name='_PyUnicodeWriter_WriteASCIIString' filepath='./Include/cpython/unicodeobject.h' line='577' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_WriteASCIIString'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='Py_GenericAliasType' type-id='type-id-256' mangled-name='Py_GenericAliasType' visibility='default' filepath='./Include/genericaliasobject.h' line='9' column='1' elf-symbol-id='Py_GenericAliasType'/> + <function-decl name='_Py_union_type_or' filepath='./Include/internal/pycore_unionobject.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyList_SetSlice' mangled-name='PyList_SetSlice' filepath='./Include/listobject.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_SetSlice'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_Dir' mangled-name='PyObject_Dir' filepath='./Include/object.h' line='416' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Dir'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GC_Track' mangled-name='PyObject_GC_Track' filepath='./Include/objimpl.h' line='194' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GC_Track'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/genobject.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyGenObject' size-in-bits='640' is-struct='yes' naming-typedef-id='type-id-367' visibility='default' filepath='./Include/cpython/genobject.h' line='31' column='1' id='type-id-368'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='gi_weakreflist' type-id='type-id-2' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='gi_name' type-id='type-id-2' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='gi_qualname' type-id='type-id-2' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='gi_exc_state' type-id='type-id-369' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='gi_origin_or_finalizer' type-id='type-id-2' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='gi_hooks_inited' type-id='type-id-48' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='520'> + <var-decl name='gi_closed' type-id='type-id-48' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='528'> + <var-decl name='gi_running_async' type-id='type-id-48' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='536'> + <var-decl name='gi_frame_state' type-id='type-id-370' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='gi_iframe' type-id='type-id-353' visibility='default' filepath='./Include/cpython/genobject.h' line='33' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyGenObject' type-id='type-id-368' filepath='./Include/cpython/genobject.h' line='34' column='1' id='type-id-367'/> + <typedef-decl name='_PyInterpreterFrame' type-id='type-id-371' filepath='./Include/internal/pycore_frame.h' line='73' column='1' id='type-id-372'/> + <pointer-type-def type-id='type-id-367' size-in-bits='64' id='type-id-373'/> + <pointer-type-def type-id='type-id-372' size-in-bits='64' id='type-id-374'/> + <function-decl name='_PyEval_EvalFrameDefault' mangled-name='_PyEval_EvalFrameDefault' filepath='./Include/cpython/ceval.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_EvalFrameDefault'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-375'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnstable_InterpreterFrame_GetLine' mangled-name='PyUnstable_InterpreterFrame_GetLine' filepath='./Include/cpython/frameobject.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_InterpreterFrame_GetLine'> + <parameter type-id='type-id-375'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyGen_Type' type-id='type-id-256' mangled-name='PyGen_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='36' column='1' elf-symbol-id='PyGen_Type'/> + <var-decl name='PyCoro_Type' type-id='type-id-256' mangled-name='PyCoro_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='56' column='1' elf-symbol-id='PyCoro_Type'/> + <var-decl name='_PyCoroWrapper_Type' type-id='type-id-256' mangled-name='_PyCoroWrapper_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='57' column='1' elf-symbol-id='_PyCoroWrapper_Type'/> + <var-decl name='PyAsyncGen_Type' type-id='type-id-256' mangled-name='PyAsyncGen_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='70' column='1' elf-symbol-id='PyAsyncGen_Type'/> + <var-decl name='_PyAsyncGenASend_Type' type-id='type-id-256' mangled-name='_PyAsyncGenASend_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='71' column='1' elf-symbol-id='_PyAsyncGenASend_Type'/> + <var-decl name='_PyAsyncGenWrappedValue_Type' type-id='type-id-256' mangled-name='_PyAsyncGenWrappedValue_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='72' column='1' elf-symbol-id='_PyAsyncGenWrappedValue_Type'/> + <var-decl name='_PyAsyncGenAThrow_Type' type-id='type-id-256' mangled-name='_PyAsyncGenAThrow_Type' visibility='default' filepath='./Include/cpython/genobject.h' line='73' column='1' elf-symbol-id='_PyAsyncGenAThrow_Type'/> + <function-decl name='PyObject_CallFinalizerFromDealloc' mangled-name='PyObject_CallFinalizerFromDealloc' filepath='./Include/cpython/object.h' line='312' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallFinalizerFromDealloc'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_GetFrame' filepath='./Include/internal/pycore_ceval.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-375'/> + </function-decl> + <function-decl name='_PyFrame_Copy' filepath='./Include/internal/pycore_frame.h' line='110' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-374'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFrame_MakeAndSetFrameObject' filepath='./Include/internal/pycore_frame.h' line='197' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-374'/> + <return type-id='type-id-365'/> + </function-decl> + <function-decl name='_PyFrame_ClearExceptCode' filepath='./Include/internal/pycore_frame.h' line='224' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-374'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFrame_Traverse' filepath='./Include/internal/pycore_frame.h' line='227' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-341'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_ChainStackItem' mangled-name='_PyErr_ChainStackItem' filepath='./Include/internal/pycore_pyerrors.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_ChainStackItem'> + <parameter type-id='type-id-376'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_WarnUnawaitedCoroutine' filepath='./Include/internal/pycore_warnings.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_GC_NewVar' mangled-name='_PyObject_GC_NewVar' filepath='./Include/objimpl.h' line='189' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GC_NewVar'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-322'/> + </function-decl> + <function-decl name='PyErr_SetRaisedException' mangled-name='PyErr_SetRaisedException' filepath='./Include/pyerrors.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetRaisedException'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_NormalizeException' mangled-name='PyErr_NormalizeException' filepath='./Include/pyerrors.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_NormalizeException'> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyGen_GetCode' mangled-name='PyGen_GetCode' filepath='Objects/genobject.c' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGen_GetCode'> + <parameter type-id='type-id-373' name='gen' filepath='Objects/genobject.c' line='36' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='_PyGen_Finalize' mangled-name='_PyGen_Finalize' filepath='Objects/genobject.c' line='70' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyGen_Finalize'> + <parameter type-id='type-id-2' name='self' filepath='Objects/genobject.c' line='70' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGen_SetStopIterationValue' mangled-name='_PyGen_SetStopIterationValue' filepath='Objects/genobject.c' line='607' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyGen_SetStopIterationValue'> + <parameter type-id='type-id-2' name='value' filepath='Objects/genobject.c' line='607' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyGen_NewWithQualName' mangled-name='PyGen_NewWithQualName' filepath='Objects/genobject.c' line='977' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGen_NewWithQualName'> + <parameter type-id='type-id-365' name='f' filepath='Objects/genobject.c' line='977' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/genobject.c' line='977' column='1'/> + <parameter type-id='type-id-2' name='qualname' filepath='Objects/genobject.c' line='977' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyGen_New' mangled-name='PyGen_New' filepath='Objects/genobject.c' line='983' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGen_New'> + <parameter type-id='type-id-365' name='f' filepath='Objects/genobject.c' line='983' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCoro_New' mangled-name='PyCoro_New' filepath='Objects/genobject.c' line='1341' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCoro_New'> + <parameter type-id='type-id-365' name='f' filepath='Objects/genobject.c' line='1341' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/genobject.c' line='1341' column='1'/> + <parameter type-id='type-id-2' name='qualname' filepath='Objects/genobject.c' line='1341' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyAsyncGen_New' mangled-name='PyAsyncGen_New' filepath='Objects/genobject.c' line='1647' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyAsyncGen_New'> + <parameter type-id='type-id-365' name='f' filepath='Objects/genobject.c' line='1647' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/genobject.c' line='1647' column='1'/> + <parameter type-id='type-id-2' name='qualname' filepath='Objects/genobject.c' line='1647' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/interpreteridobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyInterpreterState_LookUpID' mangled-name='_PyInterpreterState_LookUpID' filepath='./Include/internal/pycore_interp.h' line='227' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_LookUpID'> + <parameter type-id='type-id-377'/> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='_PyInterpreterState_IDInitref' mangled-name='_PyInterpreterState_IDInitref' filepath='./Include/internal/pycore_interp.h' line='229' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDInitref'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyInterpreterState_IDIncref' mangled-name='_PyInterpreterState_IDIncref' filepath='./Include/internal/pycore_interp.h' line='230' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDIncref'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyInterpreterState_IDDecref' mangled-name='_PyInterpreterState_IDDecref' filepath='./Include/internal/pycore_interp.h' line='231' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDDecref'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <var-decl name='_PyInterpreterID_Type' type-id='type-id-256' mangled-name='_PyInterpreterID_Type' visibility='default' filepath='./Include/internal/pycore_interpreteridobject.h' line='13' column='1' elf-symbol-id='_PyInterpreterID_Type'/> + <function-decl name='PyLong_FromLongLong' mangled-name='PyLong_FromLongLong' filepath='./Include/longobject.h' line='67' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromLongLong'> + <parameter type-id='type-id-378'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_AsLongLong' mangled-name='PyLong_AsLongLong' filepath='./Include/longobject.h' line='69' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsLongLong'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-378'/> + </function-decl> + <function-decl name='PyLong_AsLongLongAndOverflow' mangled-name='PyLong_AsLongLongAndOverflow' filepath='./Include/longobject.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsLongLongAndOverflow'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-378'/> + </function-decl> + <function-decl name='PyArg_ParseTupleAndKeywords' mangled-name='PyArg_ParseTupleAndKeywords' filepath='./Include/modsupport.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_ParseTupleAndKeywords'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyInterpreterState_GetID' mangled-name='PyInterpreterState_GetID' filepath='./Include/pystate.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_GetID'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-377'/> + </function-decl> + <function-decl name='_PyInterpreterID_New' mangled-name='_PyInterpreterID_New' filepath='Objects/interpreteridobject.c' line='268' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterID_New'> + <parameter type-id='type-id-377' name='id' filepath='Objects/interpreteridobject.c' line='268' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyInterpreterState_GetIDObject' mangled-name='_PyInterpreterState_GetIDObject' filepath='Objects/interpreteridobject.c' line='274' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetIDObject'> + <parameter type-id='type-id-20' name='interp' filepath='Objects/interpreteridobject.c' line='274' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyInterpreterID_LookUp' mangled-name='_PyInterpreterID_LookUp' filepath='Objects/interpreteridobject.c' line='287' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterID_LookUp'> + <parameter type-id='type-id-2' name='requested_id' filepath='Objects/interpreteridobject.c' line='287' column='1'/> + <return type-id='type-id-20'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/iterobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyCoro_GetAwaitableIter' filepath='./Include/internal/pycore_genobject.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='PySeqIter_Type' type-id='type-id-256' mangled-name='PySeqIter_Type' visibility='default' filepath='./Include/iterobject.h' line='8' column='1' elf-symbol-id='PySeqIter_Type'/> + <var-decl name='PyCallIter_Type' type-id='type-id-256' mangled-name='PyCallIter_Type' visibility='default' filepath='./Include/iterobject.h' line='9' column='1' elf-symbol-id='PyCallIter_Type'/> + <var-decl name='_PyAnextAwaitable_Type' type-id='type-id-256' visibility='default' filepath='./Include/iterobject.h' line='11' column='1'/> + <function-decl name='PyCallIter_New' mangled-name='PyCallIter_New' filepath='Objects/iterobject.c' line='184' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCallIter_New'> + <parameter type-id='type-id-2' name='callable' filepath='Objects/iterobject.c' line='184' column='1'/> + <parameter type-id='type-id-2' name='sentinel' filepath='Objects/iterobject.c' line='184' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/listobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyEval_SliceIndexNotNone' mangled-name='_PyEval_SliceIndexNotNone' filepath='./Include/cpython/ceval.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SliceIndexNotNone'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_WriteChar' mangled-name='_PyUnicodeWriter_WriteChar' filepath='./Include/cpython/unicodeobject.h' line='554' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_WriteChar'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyList_Type' type-id='type-id-256' mangled-name='PyList_Type' visibility='default' filepath='./Include/listobject.h' line='20' column='1' elf-symbol-id='PyList_Type'/> + <var-decl name='PyListIter_Type' type-id='type-id-256' mangled-name='PyListIter_Type' visibility='default' filepath='./Include/listobject.h' line='21' column='1' elf-symbol-id='PyListIter_Type'/> + <var-decl name='PyListRevIter_Type' type-id='type-id-256' mangled-name='PyListRevIter_Type' visibility='default' filepath='./Include/listobject.h' line='22' column='1' elf-symbol-id='PyListRevIter_Type'/> + <function-decl name='PyObject_HashNotImplemented' mangled-name='PyObject_HashNotImplemented' filepath='./Include/object.h' line='405' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_HashNotImplemented'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-305'/> + </function-decl> + <function-decl name='Py_ReprEnter' mangled-name='Py_ReprEnter' filepath='./Include/object.h' line='425' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_ReprEnter'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_ReprLeave' mangled-name='Py_ReprLeave' filepath='./Include/object.h' line='426' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_ReprLeave'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyList_DebugMallocStats' mangled-name='_PyList_DebugMallocStats' filepath='Objects/listobject.c' line='145' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyList_DebugMallocStats'> + <parameter type-id='type-id-229' name='out' filepath='Objects/listobject.c' line='145' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyList_Size' mangled-name='PyList_Size' filepath='Objects/listobject.c' line='220' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_Size'> + <parameter type-id='type-id-2' name='op' filepath='Objects/listobject.c' line='220' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyList_SetItem' mangled-name='PyList_SetItem' filepath='Objects/listobject.c' line='259' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_SetItem'> + <parameter type-id='type-id-2' name='op' filepath='Objects/listobject.c' line='259' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/listobject.c' line='259' column='1'/> + <parameter type-id='type-id-2' name='newitem' filepath='Objects/listobject.c' line='260' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyList_Insert' mangled-name='PyList_Insert' filepath='Objects/listobject.c' line='308' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_Insert'> + <parameter type-id='type-id-2' name='op' filepath='Objects/listobject.c' line='308' column='1'/> + <parameter type-id='type-id-14' name='where' filepath='Objects/listobject.c' line='308' column='1'/> + <parameter type-id='type-id-2' name='newitem' filepath='Objects/listobject.c' line='308' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyList_GetSlice' mangled-name='PyList_GetSlice' filepath='Objects/listobject.c' line='491' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_GetSlice'> + <parameter type-id='type-id-2' name='a' filepath='Objects/listobject.c' line='491' column='1'/> + <parameter type-id='type-id-14' name='ilow' filepath='Objects/listobject.c' line='491' column='1'/> + <parameter type-id='type-id-14' name='ihigh' filepath='Objects/listobject.c' line='491' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyList_Sort' mangled-name='PyList_Sort' filepath='Objects/listobject.c' line='2514' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyList_Sort'> + <parameter type-id='type-id-2' name='v' filepath='Objects/listobject.c' line='2514' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/longobject.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-85' size-in-bits='2048' id='type-id-379'> + <subrange length='256' type-id='type-id-28' id='type-id-62'/> + </array-type-def> + <qualified-type-def type-id='type-id-240' const='yes' id='type-id-380'/> + <pointer-type-def type-id='type-id-380' size-in-bits='64' id='type-id-381'/> + <qualified-type-def type-id='type-id-85' const='yes' id='type-id-382'/> + <pointer-type-def type-id='type-id-382' size-in-bits='64' id='type-id-383'/> + <pointer-type-def type-id='type-id-384' size-in-bits='64' id='type-id-385'/> + <pointer-type-def type-id='type-id-85' size-in-bits='64' id='type-id-386'/> + <function-decl name='_PyUnicodeWriter_PrepareInternal' mangled-name='_PyUnicodeWriter_PrepareInternal' filepath='./Include/cpython/unicodeobject.h' line='532' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_PrepareInternal'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='_PyLong_DigitValue' type-id='type-id-379' mangled-name='_PyLong_DigitValue' visibility='default' filepath='./Include/internal/pycore_long.h' line='87' column='1' elf-symbol-id='_PyLong_DigitValue'/> + <function-decl name='_PyLong_FormatAdvancedWriter' mangled-name='_PyLong_FormatAdvancedWriter' filepath='./Include/internal/pycore_long.h' line='91' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FormatAdvancedWriter'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyLong_Type' type-id='type-id-256' mangled-name='PyLong_Type' visibility='default' filepath='./Include/object.h' line='210' column='1' elf-symbol-id='PyLong_Type'/> + <function-decl name='PyObject_Bytes' mangled-name='PyObject_Bytes' filepath='./Include/object.h' line='389' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Bytes'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_New' mangled-name='_PyLong_New' filepath='Objects/longobject.c' line='141' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_New'> + <parameter type-id='type-id-14' name='size' filepath='Objects/longobject.c' line='141' column='1'/> + <return type-id='type-id-241'/> + </function-decl> + <function-decl name='_PyLong_FromDigits' mangled-name='_PyLong_FromDigits' filepath='Objects/longobject.c' line='170' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FromDigits'> + <parameter type-id='type-id-8' name='negative' filepath='Objects/longobject.c' line='170' column='1'/> + <parameter type-id='type-id-14' name='digit_count' filepath='Objects/longobject.c' line='170' column='1'/> + <parameter type-id='type-id-385' name='digits' filepath='Objects/longobject.c' line='170' column='1'/> + <return type-id='type-id-241'/> + </function-decl> + <function-decl name='PyLong_FromUnsignedLong' mangled-name='PyLong_FromUnsignedLong' filepath='Objects/longobject.c' line='357' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromUnsignedLong'> + <parameter type-id='type-id-28' name='ival' filepath='Objects/longobject.c' line='357' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_FromUnsignedLongLong' mangled-name='PyLong_FromUnsignedLongLong' filepath='Objects/longobject.c' line='365' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromUnsignedLongLong'> + <parameter type-id='type-id-387' name='ival' filepath='Objects/longobject.c' line='365' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_AsLong' mangled-name='PyLong_AsLong' filepath='Objects/longobject.c' line='532' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsLong'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='532' column='1'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='PyLong_AsUnsignedLong' mangled-name='PyLong_AsUnsignedLong' filepath='Objects/longobject.c' line='616' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsUnsignedLong'> + <parameter type-id='type-id-2' name='vv' filepath='Objects/longobject.c' line='616' column='1'/> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyLong_AsSize_t' mangled-name='PyLong_AsSize_t' filepath='Objects/longobject.c' line='669' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsSize_t'> + <parameter type-id='type-id-2' name='vv' filepath='Objects/longobject.c' line='669' column='1'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='PyLong_AsUnsignedLongMask' mangled-name='PyLong_AsUnsignedLongMask' filepath='Objects/longobject.c' line='735' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsUnsignedLongMask'> + <parameter type-id='type-id-2' name='op' filepath='Objects/longobject.c' line='735' column='1'/> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='_PyLong_FromByteArray' mangled-name='_PyLong_FromByteArray' filepath='Objects/longobject.c' line='812' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FromByteArray'> + <parameter type-id='type-id-383' name='bytes' filepath='Objects/longobject.c' line='812' column='1'/> + <parameter type-id='type-id-19' name='n' filepath='Objects/longobject.c' line='812' column='1'/> + <parameter type-id='type-id-8' name='little_endian' filepath='Objects/longobject.c' line='813' column='1'/> + <parameter type-id='type-id-8' name='is_signed' filepath='Objects/longobject.c' line='813' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_AsByteArray' mangled-name='_PyLong_AsByteArray' filepath='Objects/longobject.c' line='927' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_AsByteArray'> + <parameter type-id='type-id-241' name='v' filepath='Objects/longobject.c' line='927' column='1'/> + <parameter type-id='type-id-386' name='bytes' filepath='Objects/longobject.c' line='928' column='1'/> + <parameter type-id='type-id-19' name='n' filepath='Objects/longobject.c' line='928' column='1'/> + <parameter type-id='type-id-8' name='little_endian' filepath='Objects/longobject.c' line='929' column='1'/> + <parameter type-id='type-id-8' name='is_signed' filepath='Objects/longobject.c' line='929' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyLong_AsVoidPtr' mangled-name='PyLong_AsVoidPtr' filepath='Objects/longobject.c' line='1078' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsVoidPtr'> + <parameter type-id='type-id-2' name='vv' filepath='Objects/longobject.c' line='1078' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyLong_AsUnsignedLongLong' mangled-name='PyLong_AsUnsignedLongLong' filepath='Objects/longobject.c' line='1249' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsUnsignedLongLong'> + <parameter type-id='type-id-2' name='vv' filepath='Objects/longobject.c' line='1249' column='1'/> + <return type-id='type-id-387'/> + </function-decl> + <function-decl name='PyLong_AsUnsignedLongLongMask' mangled-name='PyLong_AsUnsignedLongLongMask' filepath='Objects/longobject.c' line='1310' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_AsUnsignedLongLongMask'> + <parameter type-id='type-id-2' name='op' filepath='Objects/longobject.c' line='1310' column='1'/> + <return type-id='type-id-387'/> + </function-decl> + <function-decl name='_PyLong_UnsignedShort_Converter' mangled-name='_PyLong_UnsignedShort_Converter' filepath='Objects/longobject.c' line='1407' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_UnsignedShort_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='1407' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/longobject.c' line='1407' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_UnsignedInt_Converter' mangled-name='_PyLong_UnsignedInt_Converter' filepath='Objects/longobject.c' line='1429' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_UnsignedInt_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='1429' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/longobject.c' line='1429' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_UnsignedLong_Converter' mangled-name='_PyLong_UnsignedLong_Converter' filepath='Objects/longobject.c' line='1451' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_UnsignedLong_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='1451' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/longobject.c' line='1451' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_UnsignedLongLong_Converter' mangled-name='_PyLong_UnsignedLongLong_Converter' filepath='Objects/longobject.c' line='1468' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_UnsignedLongLong_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='1468' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/longobject.c' line='1468' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_Size_t_Converter' mangled-name='_PyLong_Size_t_Converter' filepath='Objects/longobject.c' line='1485' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Size_t_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='1485' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/longobject.c' line='1485' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_FormatWriter' mangled-name='_PyLong_FormatWriter' filepath='Objects/longobject.c' line='2163' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FormatWriter'> + <parameter type-id='type-id-332' name='writer' filepath='Objects/longobject.c' line='2163' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Objects/longobject.c' line='2164' column='1'/> + <parameter type-id='type-id-8' name='base' filepath='Objects/longobject.c' line='2165' column='1'/> + <parameter type-id='type-id-8' name='alternate' filepath='Objects/longobject.c' line='2165' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyLong_Frexp' mangled-name='_PyLong_Frexp' filepath='Objects/longobject.c' line='3092' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Frexp'> + <parameter type-id='type-id-241' name='a' filepath='Objects/longobject.c' line='3092' column='1'/> + <parameter type-id='type-id-13' name='e' filepath='Objects/longobject.c' line='3092' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='_PyLong_Rshift' mangled-name='_PyLong_Rshift' filepath='Objects/longobject.c' line='5039' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_Rshift'> + <parameter type-id='type-id-2' name='a' filepath='Objects/longobject.c' line='5039' column='1'/> + <parameter type-id='type-id-19' name='shiftby' filepath='Objects/longobject.c' line='5039' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_GCD' mangled-name='_PyLong_GCD' filepath='Objects/longobject.c' line='5318' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_GCD'> + <parameter type-id='type-id-2' name='aarg' filepath='Objects/longobject.c' line='5318' column='1'/> + <parameter type-id='type-id-2' name='barg' filepath='Objects/longobject.c' line='5318' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_DivmodNear' mangled-name='_PyLong_DivmodNear' filepath='Objects/longobject.c' line='5684' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_DivmodNear'> + <parameter type-id='type-id-2' name='a' filepath='Objects/longobject.c' line='5684' column='1'/> + <parameter type-id='type-id-2' name='b' filepath='Objects/longobject.c' line='5684' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_GetInfo' mangled-name='PyLong_GetInfo' filepath='Objects/longobject.c' line='6318' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_GetInfo'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnstable_Long_IsCompact' mangled-name='PyUnstable_Long_IsCompact' filepath='Objects/longobject.c' line='6373' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Long_IsCompact'> + <parameter type-id='type-id-381' name='op' filepath='Objects/longobject.c' line='6373' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_Long_CompactValue' mangled-name='PyUnstable_Long_CompactValue' filepath='Objects/longobject.c' line='6380' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Long_CompactValue'> + <parameter type-id='type-id-381' name='op' filepath='Objects/longobject.c' line='6380' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/memoryobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyManagedBuffer_Type' type-id='type-id-256' mangled-name='_PyManagedBuffer_Type' visibility='default' filepath='./Include/cpython/memoryobject.h' line='5' column='1' elf-symbol-id='_PyManagedBuffer_Type'/> + <var-decl name='PyMemoryView_Type' type-id='type-id-256' mangled-name='PyMemoryView_Type' visibility='default' filepath='./Include/memoryobject.h' line='9' column='1' elf-symbol-id='PyMemoryView_Type'/> + <function-decl name='PyUnicode_AsASCIIString' mangled-name='PyUnicode_AsASCIIString' filepath='./Include/unicodeobject.h' line='639' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsASCIIString'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMemoryView_FromMemory' mangled-name='PyMemoryView_FromMemory' filepath='Objects/memoryobject.c' line='739' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMemoryView_FromMemory'> + <parameter type-id='type-id-15' name='mem' filepath='Objects/memoryobject.c' line='739' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/memoryobject.c' line='739' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/memoryobject.c' line='739' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMemoryView_FromBuffer' mangled-name='PyMemoryView_FromBuffer' filepath='Objects/memoryobject.c' line='768' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMemoryView_FromBuffer'> + <parameter type-id='type-id-245' name='info' filepath='Objects/memoryobject.c' line='768' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMemoryView_FromObject' mangled-name='PyMemoryView_FromObject' filepath='Objects/memoryobject.c' line='852' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMemoryView_FromObject'> + <parameter type-id='type-id-2' name='v' filepath='Objects/memoryobject.c' line='852' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMemoryView_GetContiguous' mangled-name='PyMemoryView_GetContiguous' filepath='Objects/memoryobject.c' line='964' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMemoryView_GetContiguous'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/memoryobject.c' line='964' column='1'/> + <parameter type-id='type-id-8' name='buffertype' filepath='Objects/memoryobject.c' line='964' column='1'/> + <parameter type-id='type-id-48' name='order' filepath='Objects/memoryobject.c' line='964' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/methodobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyCMethod_Type' type-id='type-id-256' mangled-name='PyCMethod_Type' visibility='default' filepath='./Include/cpython/methodobject.h' line='32' column='1' elf-symbol-id='PyCMethod_Type'/> + <var-decl name='PyCFunction_Type' type-id='type-id-256' mangled-name='PyCFunction_Type' visibility='default' filepath='./Include/methodobject.h' line='14' column='1' elf-symbol-id='PyCFunction_Type'/> + <function-decl name='PyCFunction_New' mangled-name='PyCFunction_New' filepath='Objects/methodobject.c' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCFunction_New'> + <parameter type-id='type-id-337' name='ml' filepath='Objects/methodobject.c' line='32' column='1'/> + <parameter type-id='type-id-2' name='self' filepath='Objects/methodobject.c' line='32' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCFunction_NewEx' mangled-name='PyCFunction_NewEx' filepath='Objects/methodobject.c' line='38' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCFunction_NewEx'> + <parameter type-id='type-id-337' name='ml' filepath='Objects/methodobject.c' line='38' column='1'/> + <parameter type-id='type-id-2' name='self' filepath='Objects/methodobject.c' line='38' column='1'/> + <parameter type-id='type-id-2' name='module' filepath='Objects/methodobject.c' line='38' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCFunction_GetFunction' mangled-name='PyCFunction_GetFunction' filepath='Objects/methodobject.c' line='116' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCFunction_GetFunction'> + <parameter type-id='type-id-2' name='op' filepath='Objects/methodobject.c' line='116' column='1'/> + <return type-id='type-id-388'/> + </function-decl> + <function-decl name='PyCFunction_GetSelf' mangled-name='PyCFunction_GetSelf' filepath='Objects/methodobject.c' line='126' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCFunction_GetSelf'> + <parameter type-id='type-id-2' name='op' filepath='Objects/methodobject.c' line='126' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCFunction_GetFlags' mangled-name='PyCFunction_GetFlags' filepath='Objects/methodobject.c' line='136' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCFunction_GetFlags'> + <parameter type-id='type-id-2' name='op' filepath='Objects/methodobject.c' line='136' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/moduleobject.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyModuleDef_Base' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/moduleobject.h' line='44' column='1' id='type-id-389'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/moduleobject.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='m_init' type-id='type-id-390' visibility='default' filepath='./Include/moduleobject.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='m_index' type-id='type-id-14' visibility='default' filepath='./Include/moduleobject.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='m_copy' type-id='type-id-2' visibility='default' filepath='./Include/moduleobject.h' line='62' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyModuleDef_Base' type-id='type-id-389' filepath='./Include/moduleobject.h' line='63' column='1' id='type-id-391'/> + <class-decl name='PyModuleDef_Slot' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/moduleobject.h' line='74' column='1' id='type-id-392'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='slot' type-id='type-id-8' visibility='default' filepath='./Include/moduleobject.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-22' visibility='default' filepath='./Include/moduleobject.h' line='76' column='1'/> + </data-member> + </class-decl> + <class-decl name='PyModuleDef' size-in-bits='832' is-struct='yes' visibility='default' filepath='./Include/moduleobject.h' line='94' column='1' id='type-id-393'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='m_base' type-id='type-id-391' visibility='default' filepath='./Include/moduleobject.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='m_name' type-id='type-id-12' visibility='default' filepath='./Include/moduleobject.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='m_doc' type-id='type-id-12' visibility='default' filepath='./Include/moduleobject.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='m_size' type-id='type-id-14' visibility='default' filepath='./Include/moduleobject.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='m_methods' type-id='type-id-337' visibility='default' filepath='./Include/moduleobject.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='m_slots' type-id='type-id-394' visibility='default' filepath='./Include/moduleobject.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='m_traverse' type-id='type-id-395' visibility='default' filepath='./Include/moduleobject.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='m_clear' type-id='type-id-396' visibility='default' filepath='./Include/moduleobject.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='m_free' type-id='type-id-397' visibility='default' filepath='./Include/moduleobject.h' line='103' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyModuleDef' type-id='type-id-393' filepath='./Include/pytypedefs.h' line='12' column='1' id='type-id-3'/> + <typedef-decl name='PyModuleDef_Slot' type-id='type-id-392' filepath='./Include/pytypedefs.h' line='13' column='1' id='type-id-398'/> + <pointer-type-def type-id='type-id-3' size-in-bits='64' id='type-id-399'/> + <pointer-type-def type-id='type-id-398' size-in-bits='64' id='type-id-394'/> + <function-decl name='_PyImport_IsInitialized' mangled-name='_PyImport_IsInitialized' filepath='./Include/cpython/import.h' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_IsInitialized'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_GenericGetAttrWithDict' mangled-name='_PyObject_GenericGetAttrWithDict' filepath='./Include/cpython/object.h' line='317' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GenericGetAttrWithDict'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_FormatFromCause' mangled-name='_PyErr_FormatFromCause' filepath='./Include/cpython/pyerrors.h' line='107' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_FormatFromCause'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_GetNextModuleIndex' filepath='./Include/internal/pycore_import.h' line='111' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyImport_ResolveNameWithPackageContext' filepath='./Include/internal/pycore_import.h' line='112' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_PyImport_ImportlibModuleRepr' filepath='./Include/internal/pycore_import.h' line='138' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_CheckSubinterpIncompatibleExtensionAllowed' mangled-name='_PyImport_CheckSubinterpIncompatibleExtensionAllowed' filepath='./Include/internal/pycore_import.h' line='173' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_CheckSubinterpIncompatibleExtensionAllowed'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyModule_Type' type-id='type-id-256' mangled-name='PyModule_Type' visibility='default' filepath='./Include/moduleobject.h' line='10' column='1' elf-symbol-id='PyModule_Type'/> + <var-decl name='PyModuleDef_Type' type-id='type-id-256' mangled-name='PyModuleDef_Type' visibility='default' filepath='./Include/moduleobject.h' line='41' column='1' elf-symbol-id='PyModuleDef_Type'/> + <function-decl name='PyObject_SetAttrString' mangled-name='PyObject_SetAttrString' filepath='./Include/object.h' line='393' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_SetAttrString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySys_FormatStderr' mangled-name='PySys_FormatStderr' filepath='./Include/sysmodule.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_FormatStderr'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyModuleDef_Init' mangled-name='PyModuleDef_Init' filepath='Objects/moduleobject.c' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModuleDef_Init'> + <parameter type-id='type-id-399' name='def' filepath='Objects/moduleobject.c' line='41' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_NewObject' mangled-name='PyModule_NewObject' filepath='Objects/moduleobject.c' line='107' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_NewObject'> + <parameter type-id='type-id-2' name='name' filepath='Objects/moduleobject.c' line='107' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_New' mangled-name='PyModule_New' filepath='Objects/moduleobject.c' line='123' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_New'> + <parameter type-id='type-id-12' name='name' filepath='Objects/moduleobject.c' line='123' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_Create2' mangled-name='PyModule_Create2' filepath='Objects/moduleobject.c' line='183' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_Create2'> + <parameter type-id='type-id-399' name='module' filepath='Objects/moduleobject.c' line='183' column='1'/> + <parameter type-id='type-id-8' name='module_api_version' filepath='Objects/moduleobject.c' line='183' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyModule_CreateInitialized' mangled-name='_PyModule_CreateInitialized' filepath='Objects/moduleobject.c' line='194' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyModule_CreateInitialized'> + <parameter type-id='type-id-399' name='module' filepath='Objects/moduleobject.c' line='194' column='1'/> + <parameter type-id='type-id-8' name='module_api_version' filepath='Objects/moduleobject.c' line='194' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_FromDefAndSpec2' mangled-name='PyModule_FromDefAndSpec2' filepath='Objects/moduleobject.c' line='242' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_FromDefAndSpec2'> + <parameter type-id='type-id-399' name='def' filepath='Objects/moduleobject.c' line='242' column='1'/> + <parameter type-id='type-id-2' name='spec' filepath='Objects/moduleobject.c' line='242' column='1'/> + <parameter type-id='type-id-8' name='module_api_version' filepath='Objects/moduleobject.c' line='242' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_ExecDef' mangled-name='PyModule_ExecDef' filepath='Objects/moduleobject.c' line='405' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_ExecDef'> + <parameter type-id='type-id-2' name='module' filepath='Objects/moduleobject.c' line='405' column='1'/> + <parameter type-id='type-id-399' name='def' filepath='Objects/moduleobject.c' line='405' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyModule_AddFunctions' mangled-name='PyModule_AddFunctions' filepath='Objects/moduleobject.c' line='473' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_AddFunctions'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='473' column='1'/> + <parameter type-id='type-id-337' name='functions' filepath='Objects/moduleobject.c' line='473' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyModule_SetDocString' mangled-name='PyModule_SetDocString' filepath='Objects/moduleobject.c' line='487' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_SetDocString'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='487' column='1'/> + <parameter type-id='type-id-12' name='doc' filepath='Objects/moduleobject.c' line='487' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyModule_GetName' mangled-name='PyModule_GetName' filepath='Objects/moduleobject.c' line='533' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetName'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='533' column='1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyModule_GetFilenameObject' mangled-name='PyModule_GetFilenameObject' filepath='Objects/moduleobject.c' line='545' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetFilenameObject'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='545' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_GetFilename' mangled-name='PyModule_GetFilename' filepath='Objects/moduleobject.c' line='567' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetFilename'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='567' column='1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyModule_GetDef' mangled-name='PyModule_GetDef' filepath='Objects/moduleobject.c' line='580' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetDef'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='580' column='1'/> + <return type-id='type-id-399'/> + </function-decl> + <function-decl name='PyModule_GetState' mangled-name='PyModule_GetState' filepath='Objects/moduleobject.c' line='590' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_GetState'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='590' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyModule_Clear' mangled-name='_PyModule_Clear' filepath='Objects/moduleobject.c' line='600' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyModule_Clear'> + <parameter type-id='type-id-2' name='m' filepath='Objects/moduleobject.c' line='600' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyModule_ClearDict' mangled-name='_PyModule_ClearDict' filepath='Objects/moduleobject.c' line='608' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyModule_ClearDict'> + <parameter type-id='type-id-2' name='d' filepath='Objects/moduleobject.c' line='608' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyModuleSpec_IsInitializing' mangled-name='_PyModuleSpec_IsInitializing' filepath='Objects/moduleobject.c' line='739' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyModuleSpec_IsInitializing'> + <parameter type-id='type-id-2' name='spec' filepath='Objects/moduleobject.c' line='739' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-400'> + <return type-id='type-id-2'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Objects/namespaceobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyNamespace_Type' type-id='type-id-256' mangled-name='_PyNamespace_Type' visibility='default' filepath='./Include/internal/pycore_namespace.h' line='13' column='1' elf-symbol-id='_PyNamespace_Type'/> + <function-decl name='PyUnicode_Join' mangled-name='PyUnicode_Join' filepath='./Include/unicodeobject.h' line='889' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Join'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyNamespace_New' mangled-name='_PyNamespace_New' filepath='Objects/namespaceobject.c' line='247' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyNamespace_New'> + <parameter type-id='type-id-2' name='kwds' filepath='Objects/namespaceobject.c' line='247' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/object.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='192' id='type-id-91'> + <subrange length='6' type-id='type-id-28' id='type-id-401'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='infinite' id='type-id-402'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <class-decl name='PyModuleObject' size-in-bits='448' is-struct='yes' naming-typedef-id='type-id-403' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='11' column='1' id='type-id-404'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='md_dict' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='13' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='md_def' type-id='type-id-399' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='md_state' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='md_weaklist' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='md_name' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_moduleobject.h' line='18' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyModuleObject' type-id='type-id-404' filepath='./Include/internal/pycore_moduleobject.h' line='19' column='1' id='type-id-403'/> + <enum-decl name='PyGILState_STATE' naming-typedef-id='type-id-405' filepath='./Include/pystate.h' line='77' column='1' id='type-id-406'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PyGILState_LOCKED' value='0'/> + <enumerator name='PyGILState_UNLOCKED' value='1'/> + </enum-decl> + <typedef-decl name='PyGILState_STATE' type-id='type-id-406' filepath='./Include/pystate.h' line='78' column='1' id='type-id-405'/> + <pointer-type-def type-id='type-id-403' size-in-bits='64' id='type-id-407'/> + <pointer-type-def type-id='type-id-408' size-in-bits='64' id='type-id-409'/> + <pointer-type-def type-id='type-id-410' size-in-bits='64' id='type-id-411'/> + <qualified-type-def type-id='type-id-22' restrict='yes' id='type-id-226'/> + <function-decl name='PyEval_GetLocals' mangled-name='PyEval_GetLocals' filepath='./Include/ceval.h' line='43' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_GetLocals'> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='_PyNone_Type' type-id='type-id-256' mangled-name='_PyNone_Type' visibility='default' filepath='./Include/cpython/object.h' line='389' column='1' elf-symbol-id='_PyNone_Type'/> + <var-decl name='_PyNotImplemented_Type' type-id='type-id-256' mangled-name='_PyNotImplemented_Type' visibility='default' filepath='./Include/cpython/object.h' line='390' column='1' elf-symbol-id='_PyNotImplemented_Type'/> + <var-decl name='_Py_SwappedOp' type-id='type-id-402' mangled-name='_Py_SwappedOp' visibility='default' filepath='./Include/cpython/object.h' line='395' column='1' elf-symbol-id='_Py_SwappedOp'/> + <function-decl name='PyMem_RawMalloc' mangled-name='PyMem_RawMalloc' filepath='./Include/cpython/pymem.h' line='5' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_RawMalloc'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyTuple_DebugMallocStats' mangled-name='_PyTuple_DebugMallocStats' filepath='./Include/cpython/tupleobject.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTuple_DebugMallocStats'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_CheckConsistency' mangled-name='_PyUnicode_CheckConsistency' filepath='./Include/cpython/unicodeobject.h' line='170' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_CheckConsistency'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_AsASCIIString' mangled-name='_PyUnicode_AsASCIIString' filepath='./Include/cpython/unicodeobject.h' line='713' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_AsASCIIString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObjectDict_SetItem' filepath='./Include/internal/pycore_dict.h' line='56' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_MakeDictFromInstanceAttributes' filepath='./Include/internal/pycore_dict.h' line='178' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-347'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_module_getattro_impl' filepath='./Include/internal/pycore_moduleobject.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-407'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_module_getattro' filepath='./Include/internal/pycore_moduleobject.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-407'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyType_CheckConsistency' mangled-name='_PyType_CheckConsistency' filepath='./Include/internal/pycore_object.h' line='123' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_CheckConsistency'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTraceMalloc_NewReference' filepath='./Include/internal/pycore_object.h' line='130' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_StoreInstanceAttribute' filepath='./Include/internal/pycore_object.h' line='345' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-347'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_GetInstanceAttribute' filepath='./Include/internal/pycore_object.h' line='347' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-347'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyStaticType_GetState' filepath='./Include/internal/pycore_typeobject.h' line='115' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-411'/> + </function-decl> + <function-decl name='_Py_type_getattro_impl' filepath='./Include/internal/pycore_typeobject.h' line='134' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_type_getattro' filepath='./Include/internal/pycore_typeobject.h' line='136' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_initialize_generic' filepath='./Include/internal/pycore_typevarobject.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='_Py_NoneStruct' type-id='type-id-345' mangled-name='_Py_NoneStruct' visibility='default' filepath='./Include/object.h' line='826' column='1' elf-symbol-id='_Py_NoneStruct'/> + <var-decl name='_Py_NotImplementedStruct' type-id='type-id-345' mangled-name='_Py_NotImplementedStruct' visibility='default' filepath='./Include/object.h' line='840' column='1' elf-symbol-id='_Py_NotImplementedStruct'/> + <function-decl name='PyThreadState_GetDict' mangled-name='PyThreadState_GetDict' filepath='./Include/pystate.h' line='66' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetDict'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyGILState_Ensure' mangled-name='PyGILState_Ensure' filepath='./Include/pystate.h' line='102' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGILState_Ensure'> + <return type-id='type-id-405'/> + </function-decl> + <function-decl name='PyGILState_Release' mangled-name='PyGILState_Release' filepath='./Include/pystate.h' line='112' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGILState_Release'> + <parameter type-id='type-id-405'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThread_tss_is_created' mangled-name='PyThread_tss_is_created' filepath='./Include/pythread.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_is_created'> + <parameter type-id='type-id-409'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_tss_set' mangled-name='PyThread_tss_set' filepath='./Include/pythread.h' line='122' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_set'> + <parameter type-id='type-id-409'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_tss_get' mangled-name='PyThread_tss_get' filepath='./Include/pythread.h' line='123' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_get'> + <parameter type-id='type-id-409'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyUnicode_DecodeASCII' mangled-name='PyUnicode_DecodeASCII' filepath='./Include/unicodeobject.h' line='633' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeASCII'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='fprintf' filepath='/usr/include/stdio.h' line='350' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-412'/> + <parameter type-id='type-id-181'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fwrite' filepath='/usr/include/stdio.h' line='681' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-226'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-412'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='ferror' filepath='/usr/include/stdio.h' line='790' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyMem_DumpTraceback' filepath='Objects/object.c' line='32' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_CheckConsistency' mangled-name='_PyObject_CheckConsistency' filepath='Objects/object.c' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CheckConsistency'> + <parameter type-id='type-id-2' name='op' filepath='Objects/object.c' line='36' column='1'/> + <parameter type-id='type-id-8' name='check_content' filepath='Objects/object.c' line='36' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_IncRef' mangled-name='Py_IncRef' filepath='Objects/object.c' line='262' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_IncRef'> + <parameter type-id='type-id-2' name='o' filepath='Objects/object.c' line='262' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_DecRef' mangled-name='Py_DecRef' filepath='Objects/object.c' line='268' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_DecRef'> + <parameter type-id='type-id-2' name='o' filepath='Objects/object.c' line='268' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_IncRef' mangled-name='_Py_IncRef' filepath='Objects/object.c' line='274' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_IncRef'> + <parameter type-id='type-id-2' name='o' filepath='Objects/object.c' line='274' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_DecRef' mangled-name='_Py_DecRef' filepath='Objects/object.c' line='280' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DecRef'> + <parameter type-id='type-id-2' name='o' filepath='Objects/object.c' line='280' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_Init' mangled-name='PyObject_Init' filepath='Objects/object.c' line='289' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Init'> + <parameter type-id='type-id-2' name='op' filepath='Objects/object.c' line='289' column='1'/> + <parameter type-id='type-id-1' name='tp' filepath='Objects/object.c' line='289' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_InitVar' mangled-name='PyObject_InitVar' filepath='Objects/object.c' line='300' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_InitVar'> + <parameter type-id='type-id-322' name='op' filepath='Objects/object.c' line='300' column='1'/> + <parameter type-id='type-id-1' name='tp' filepath='Objects/object.c' line='300' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/object.c' line='300' column='1'/> + <return type-id='type-id-322'/> + </function-decl> + <function-decl name='PyObject_CallFinalizer' mangled-name='PyObject_CallFinalizer' filepath='Objects/object.c' line='335' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallFinalizer'> + <parameter type-id='type-id-2' name='self' filepath='Objects/object.c' line='335' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_Print' mangled-name='PyObject_Print' filepath='Objects/object.c' line='389' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Print'> + <parameter type-id='type-id-2' name='op' filepath='Objects/object.c' line='389' column='1'/> + <parameter type-id='type-id-229' name='fp' filepath='Objects/object.c' line='389' column='1'/> + <parameter type-id='type-id-8' name='flags' filepath='Objects/object.c' line='389' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_BreakPoint' mangled-name='_Py_BreakPoint' filepath='Objects/object.c' line='448' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_BreakPoint'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_IsFreed' mangled-name='_PyObject_IsFreed' filepath='Objects/object.c' line='460' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_IsFreed'> + <parameter type-id='type-id-2' name='op' filepath='Objects/object.c' line='460' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_Dump' mangled-name='_PyObject_Dump' filepath='Objects/object.c' line='481' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_Dump'> + <parameter type-id='type-id-2' name='op' filepath='Objects/object.c' line='481' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_HasAttrString' mangled-name='PyObject_HasAttrString' filepath='Objects/object.c' line='921' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_HasAttrString'> + <parameter type-id='type-id-2' name='v' filepath='Objects/object.c' line='921' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Objects/object.c' line='921' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_SetAttrId' mangled-name='_PyObject_SetAttrId' filepath='Objects/object.c' line='988' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_SetAttrId'> + <parameter type-id='type-id-2' name='v' filepath='Objects/object.c' line='988' column='1'/> + <parameter type-id='type-id-309' name='name' filepath='Objects/object.c' line='988' column='1'/> + <parameter type-id='type-id-2' name='w' filepath='Objects/object.c' line='988' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_LookupAttrId' mangled-name='_PyObject_LookupAttrId' filepath='Objects/object.c' line='1128' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_LookupAttrId'> + <parameter type-id='type-id-2' name='v' filepath='Objects/object.c' line='1128' column='1'/> + <parameter type-id='type-id-309' name='name' filepath='Objects/object.c' line='1128' column='1'/> + <parameter type-id='type-id-233' name='result' filepath='Objects/object.c' line='1128' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_GetDictPtr' mangled-name='_PyObject_GetDictPtr' filepath='Objects/object.c' line='1238' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetDictPtr'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/object.c' line='1238' column='1'/> + <return type-id='type-id-233'/> + </function-decl> + <function-decl name='_PyObject_GenericSetAttrWithDict' mangled-name='_PyObject_GenericSetAttrWithDict' filepath='Objects/object.c' line='1519' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GenericSetAttrWithDict'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/object.c' line='1519' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Objects/object.c' line='1519' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Objects/object.c' line='1520' column='1'/> + <parameter type-id='type-id-2' name='dict' filepath='Objects/object.c' line='1520' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyObject_Not' mangled-name='PyObject_Not' filepath='Objects/object.c' line='1680' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Not'> + <parameter type-id='type-id-2' name='v' filepath='Objects/object.c' line='1680' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_DebugTypeStats' mangled-name='_PyObject_DebugTypeStats' filepath='Objects/object.c' line='2300' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_DebugTypeStats'> + <parameter type-id='type-id-229' name='out' filepath='Objects/object.c' line='2300' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_GET_WEAKREFS_LISTPTR' mangled-name='PyObject_GET_WEAKREFS_LISTPTR' filepath='Objects/object.c' line='2619' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GET_WEAKREFS_LISTPTR'> + <parameter type-id='type-id-2' name='op' filepath='Objects/object.c' line='2619' column='1'/> + <return type-id='type-id-233'/> + </function-decl> + <function-decl name='Py_NewRef' mangled-name='Py_NewRef' filepath='Objects/object.c' line='2630' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_NewRef'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/object.c' line='2630' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_XNewRef' mangled-name='Py_XNewRef' filepath='Objects/object.c' line='2636' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_XNewRef'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/object.c' line='2636' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_Is' mangled-name='Py_Is' filepath='Objects/object.c' line='2648' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Is'> + <parameter type-id='type-id-2' name='x' filepath='Objects/object.c' line='2648' column='1'/> + <parameter type-id='type-id-2' name='y' filepath='Objects/object.c' line='2648' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_IsNone' mangled-name='Py_IsNone' filepath='Objects/object.c' line='2653' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_IsNone'> + <parameter type-id='type-id-2' name='x' filepath='Objects/object.c' line='2653' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_IsTrue' mangled-name='Py_IsTrue' filepath='Objects/object.c' line='2658' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_IsTrue'> + <parameter type-id='type-id-2' name='x' filepath='Objects/object.c' line='2658' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_IsFalse' mangled-name='Py_IsFalse' filepath='Objects/object.c' line='2663' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_IsFalse'> + <parameter type-id='type-id-2' name='x' filepath='Objects/object.c' line='2663' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/obmalloc.c' comp-dir-path='/src' language='LANG_C11'> + <enum-decl name='PyMemAllocatorDomain' naming-typedef-id='type-id-413' filepath='./Include/cpython/pymem.h' line='23' column='1' id='type-id-414'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PYMEM_DOMAIN_RAW' value='0'/> + <enumerator name='PYMEM_DOMAIN_MEM' value='1'/> + <enumerator name='PYMEM_DOMAIN_OBJ' value='2'/> + </enum-decl> + <typedef-decl name='PyMemAllocatorDomain' type-id='type-id-414' filepath='./Include/cpython/pymem.h' line='32' column='1' id='type-id-413'/> + <enum-decl name='PyMemAllocatorName' naming-typedef-id='type-id-415' filepath='./Include/cpython/pymem.h' line='34' column='1' id='type-id-416'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PYMEM_ALLOCATOR_NOT_SET' value='0'/> + <enumerator name='PYMEM_ALLOCATOR_DEFAULT' value='1'/> + <enumerator name='PYMEM_ALLOCATOR_DEBUG' value='2'/> + <enumerator name='PYMEM_ALLOCATOR_MALLOC' value='3'/> + <enumerator name='PYMEM_ALLOCATOR_MALLOC_DEBUG' value='4'/> + <enumerator name='PYMEM_ALLOCATOR_PYMALLOC' value='5'/> + <enumerator name='PYMEM_ALLOCATOR_PYMALLOC_DEBUG' value='6'/> + </enum-decl> + <typedef-decl name='PyMemAllocatorName' type-id='type-id-416' filepath='./Include/cpython/pymem.h' line='44' column='1' id='type-id-415'/> + <pointer-type-def type-id='type-id-417' size-in-bits='64' id='type-id-418'/> + <pointer-type-def type-id='type-id-415' size-in-bits='64' id='type-id-419'/> + <pointer-type-def type-id='type-id-420' size-in-bits='64' id='type-id-421'/> + <qualified-type-def type-id='type-id-422' const='yes' id='type-id-423'/> + <pointer-type-def type-id='type-id-423' size-in-bits='64' id='type-id-16'/> + <function-decl name='Py_GETENV' mangled-name='Py_GETENV' filepath='./Include/cpython/pydebug.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GETENV'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyGILState_Check' mangled-name='PyGILState_Check' filepath='./Include/cpython/pystate.h' line='290' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGILState_Check'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyInterpreterState_Head' mangled-name='PyInterpreterState_Head' filepath='./Include/cpython/pystate.h' line='314' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Head'> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='PyInterpreterState_Next' mangled-name='PyInterpreterState_Next' filepath='./Include/cpython/pystate.h' line='315' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Next'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='fputc' filepath='/usr/include/stdio.h' line='549' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fputs' filepath='/usr/include/stdio.h' line='655' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-412'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='malloc' filepath='/usr/include/stdlib.h' line='540' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='calloc' filepath='/usr/include/stdlib.h' line='543' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='realloc' filepath='/usr/include/stdlib.h' line='551' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='free' filepath='/usr/include/stdlib.h' line='555' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='wcslen' filepath='/usr/include/wchar.h' line='223' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='munmap' filepath='/usr/include/x86_64-linux-gnu/sys/mman.h' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyMem_SetDefaultAllocator' mangled-name='_PyMem_SetDefaultAllocator' filepath='Objects/obmalloc.c' line='244' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_SetDefaultAllocator'> + <parameter type-id='type-id-413' name='domain' filepath='Objects/obmalloc.c' line='244' column='1'/> + <parameter type-id='type-id-418' name='old_alloc' filepath='Objects/obmalloc.c' line='245' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyMem_GetAllocatorName' mangled-name='_PyMem_GetAllocatorName' filepath='Objects/obmalloc.c' line='257' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_GetAllocatorName'> + <parameter type-id='type-id-12' name='name' filepath='Objects/obmalloc.c' line='257' column='1'/> + <parameter type-id='type-id-419' name='allocator' filepath='Objects/obmalloc.c' line='257' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyMem_SetupAllocators' mangled-name='_PyMem_SetupAllocators' filepath='Objects/obmalloc.c' line='293' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_SetupAllocators'> + <parameter type-id='type-id-415' name='allocator' filepath='Objects/obmalloc.c' line='293' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyMem_GetCurrentAllocatorName' mangled-name='_PyMem_GetCurrentAllocatorName' filepath='Objects/obmalloc.c' line='360' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_GetCurrentAllocatorName'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyMem_SetupDebugHooks' mangled-name='PyMem_SetupDebugHooks' filepath='Objects/obmalloc.c' line='478' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_SetupDebugHooks'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyMem_GetAllocator' mangled-name='PyMem_GetAllocator' filepath='Objects/obmalloc.c' line='486' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_GetAllocator'> + <parameter type-id='type-id-413' name='domain' filepath='Objects/obmalloc.c' line='486' column='1'/> + <parameter type-id='type-id-418' name='allocator' filepath='Objects/obmalloc.c' line='486' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyMem_SetAllocator' mangled-name='PyMem_SetAllocator' filepath='Objects/obmalloc.c' line='504' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_SetAllocator'> + <parameter type-id='type-id-413' name='domain' filepath='Objects/obmalloc.c' line='504' column='1'/> + <parameter type-id='type-id-418' name='allocator' filepath='Objects/obmalloc.c' line='504' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_GetArenaAllocator' mangled-name='PyObject_GetArenaAllocator' filepath='Objects/obmalloc.c' line='516' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetArenaAllocator'> + <parameter type-id='type-id-421' name='allocator' filepath='Objects/obmalloc.c' line='516' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyObject_SetArenaAllocator' mangled-name='PyObject_SetArenaAllocator' filepath='Objects/obmalloc.c' line='534' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_SetArenaAllocator'> + <parameter type-id='type-id-421' name='allocator' filepath='Objects/obmalloc.c' line='534' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyMem_RawCalloc' mangled-name='PyMem_RawCalloc' filepath='Objects/obmalloc.c' line='554' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_RawCalloc'> + <parameter type-id='type-id-19' name='nelem' filepath='Objects/obmalloc.c' line='554' column='1'/> + <parameter type-id='type-id-19' name='elsize' filepath='Objects/obmalloc.c' line='554' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyMem_RawWcsdup' mangled-name='_PyMem_RawWcsdup' filepath='Objects/obmalloc.c' line='621' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_RawWcsdup'> + <parameter type-id='type-id-16' name='str' filepath='Objects/obmalloc.c' line='621' column='1'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_PyMem_RawStrdup' mangled-name='_PyMem_RawStrdup' filepath='Objects/obmalloc.c' line='641' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_RawStrdup'> + <parameter type-id='type-id-12' name='str' filepath='Objects/obmalloc.c' line='641' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_PyMem_Strdup' mangled-name='_PyMem_Strdup' filepath='Objects/obmalloc.c' line='654' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyMem_Strdup'> + <parameter type-id='type-id-12' name='str' filepath='Objects/obmalloc.c' line='654' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_PyObject_DebugMallocStats' mangled-name='_PyObject_DebugMallocStats' filepath='Objects/obmalloc.c' line='2421' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_DebugMallocStats'> + <parameter type-id='type-id-229' name='out' filepath='Objects/obmalloc.c' line='2421' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/odictobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyODict_Type' type-id='type-id-256' mangled-name='PyODict_Type' visibility='default' filepath='./Include/cpython/odictobject.h' line='15' column='1' elf-symbol-id='PyODict_Type'/> + <var-decl name='PyODictIter_Type' type-id='type-id-256' mangled-name='PyODictIter_Type' visibility='default' filepath='./Include/cpython/odictobject.h' line='16' column='1' elf-symbol-id='PyODictIter_Type'/> + <var-decl name='PyODictKeys_Type' type-id='type-id-256' mangled-name='PyODictKeys_Type' visibility='default' filepath='./Include/cpython/odictobject.h' line='17' column='1' elf-symbol-id='PyODictKeys_Type'/> + <var-decl name='PyODictItems_Type' type-id='type-id-256' mangled-name='PyODictItems_Type' visibility='default' filepath='./Include/cpython/odictobject.h' line='18' column='1' elf-symbol-id='PyODictItems_Type'/> + <var-decl name='PyODictValues_Type' type-id='type-id-256' mangled-name='PyODictValues_Type' visibility='default' filepath='./Include/cpython/odictobject.h' line='19' column='1' elf-symbol-id='PyODictValues_Type'/> + <function-decl name='_PyErr_ChainExceptions1' mangled-name='_PyErr_ChainExceptions1' filepath='./Include/cpython/pyerrors.h' line='102' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_ChainExceptions1'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyDict_FromKeys' filepath='./Include/internal/pycore_dict.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_dict_lookup' filepath='./Include/internal/pycore_dict.h' line='48' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-340'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-305'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyDict_Pop_KnownHash' filepath='./Include/internal/pycore_dict.h' line='58' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-305'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyODict_New' mangled-name='PyODict_New' filepath='Objects/odictobject.c' line='1545' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyODict_New'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyODict_SetItem' mangled-name='PyODict_SetItem' filepath='Objects/odictobject.c' line='1568' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyODict_SetItem'> + <parameter type-id='type-id-2' name='od' filepath='Objects/odictobject.c' line='1568' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/odictobject.c' line='1568' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Objects/odictobject.c' line='1568' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyODict_DelItem' mangled-name='PyODict_DelItem' filepath='Objects/odictobject.c' line='1577' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyODict_DelItem'> + <parameter type-id='type-id-2' name='od' filepath='Objects/odictobject.c' line='1577' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/odictobject.c' line='1577' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/picklebufobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyPickleBuffer_Type' type-id='type-id-256' mangled-name='PyPickleBuffer_Type' visibility='default' filepath='./Include/cpython/picklebufobject.h' line='13' column='1' elf-symbol-id='PyPickleBuffer_Type'/> + <function-decl name='PyPickleBuffer_FromObject' mangled-name='PyPickleBuffer_FromObject' filepath='Objects/picklebufobject.c' line='17' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyPickleBuffer_FromObject'> + <parameter type-id='type-id-2' name='base' filepath='Objects/picklebufobject.c' line='17' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyPickleBuffer_GetBuffer' mangled-name='PyPickleBuffer_GetBuffer' filepath='Objects/picklebufobject.c' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyPickleBuffer_GetBuffer'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/picklebufobject.c' line='36' column='1'/> + <return type-id='type-id-245'/> + </function-decl> + <function-decl name='PyPickleBuffer_Release' mangled-name='PyPickleBuffer_Release' filepath='Objects/picklebufobject.c' line='55' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyPickleBuffer_Release'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/picklebufobject.c' line='55' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/rangeobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyRange_Type' type-id='type-id-256' mangled-name='PyRange_Type' visibility='default' filepath='./Include/rangeobject.h' line='18' column='1' elf-symbol-id='PyRange_Type'/> + <var-decl name='PyRangeIter_Type' type-id='type-id-256' mangled-name='PyRangeIter_Type' visibility='default' filepath='./Include/rangeobject.h' line='19' column='1' elf-symbol-id='PyRangeIter_Type'/> + <var-decl name='PyLongRangeIter_Type' type-id='type-id-256' mangled-name='PyLongRangeIter_Type' visibility='default' filepath='./Include/rangeobject.h' line='20' column='1' elf-symbol-id='PyLongRangeIter_Type'/> + <function-decl name='_PySlice_GetLongIndices' mangled-name='_PySlice_GetLongIndices' filepath='./Include/sliceobject.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySlice_GetLongIndices'> + <parameter type-id='type-id-424'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/setobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PySet_Dummy' type-id='type-id-2' mangled-name='_PySet_Dummy' visibility='default' filepath='./Include/cpython/setobject.h' line='69' column='1' elf-symbol-id='_PySet_Dummy'/> + <function-decl name='_PyUnicode_EQ' mangled-name='_PyUnicode_EQ' filepath='./Include/cpython/unicodeobject.h' line='953' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EQ'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PySet_Type' type-id='type-id-256' mangled-name='PySet_Type' visibility='default' filepath='./Include/setobject.h' line='9' column='1' elf-symbol-id='PySet_Type'/> + <var-decl name='PyFrozenSet_Type' type-id='type-id-256' mangled-name='PyFrozenSet_Type' visibility='default' filepath='./Include/setobject.h' line='10' column='1' elf-symbol-id='PyFrozenSet_Type'/> + <var-decl name='PySetIter_Type' type-id='type-id-256' mangled-name='PySetIter_Type' visibility='default' filepath='./Include/setobject.h' line='11' column='1' elf-symbol-id='PySetIter_Type'/> + <function-decl name='PySet_Size' mangled-name='PySet_Size' filepath='Objects/setobject.c' line='2277' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_Size'> + <parameter type-id='type-id-2' name='anyset' filepath='Objects/setobject.c' line='2277' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PySet_Clear' mangled-name='PySet_Clear' filepath='Objects/setobject.c' line='2287' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_Clear'> + <parameter type-id='type-id-2' name='set' filepath='Objects/setobject.c' line='2287' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySet_Discard' mangled-name='PySet_Discard' filepath='Objects/setobject.c' line='2307' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_Discard'> + <parameter type-id='type-id-2' name='set' filepath='Objects/setobject.c' line='2307' column='1'/> + <parameter type-id='type-id-2' name='key' filepath='Objects/setobject.c' line='2307' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySet_Pop' mangled-name='PySet_Pop' filepath='Objects/setobject.c' line='2344' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySet_Pop'> + <parameter type-id='type-id-2' name='set' filepath='Objects/setobject.c' line='2344' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/sliceobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_Py_EllipsisObject' type-id='type-id-345' mangled-name='_Py_EllipsisObject' visibility='default' filepath='./Include/sliceobject.h' line='9' column='1' elf-symbol-id='_Py_EllipsisObject'/> + <var-decl name='PySlice_Type' type-id='type-id-256' mangled-name='PySlice_Type' visibility='default' filepath='./Include/sliceobject.h' line='28' column='1' elf-symbol-id='PySlice_Type'/> + <var-decl name='PyEllipsis_Type' type-id='type-id-256' mangled-name='PyEllipsis_Type' visibility='default' filepath='./Include/sliceobject.h' line='29' column='1' elf-symbol-id='PyEllipsis_Type'/> + <function-decl name='PySlice_New' mangled-name='PySlice_New' filepath='Objects/sliceobject.c' line='155' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySlice_New'> + <parameter type-id='type-id-2' name='start' filepath='Objects/sliceobject.c' line='155' column='1'/> + <parameter type-id='type-id-2' name='stop' filepath='Objects/sliceobject.c' line='155' column='1'/> + <parameter type-id='type-id-2' name='step' filepath='Objects/sliceobject.c' line='155' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySlice_GetIndices' mangled-name='PySlice_GetIndices' filepath='Objects/sliceobject.c' line='197' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySlice_GetIndices'> + <parameter type-id='type-id-2' name='_r' filepath='Objects/sliceobject.c' line='197' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Objects/sliceobject.c' line='197' column='1'/> + <parameter type-id='type-id-13' name='start' filepath='Objects/sliceobject.c' line='198' column='1'/> + <parameter type-id='type-id-13' name='stop' filepath='Objects/sliceobject.c' line='198' column='1'/> + <parameter type-id='type-id-13' name='step' filepath='Objects/sliceobject.c' line='198' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PySlice_GetIndicesEx' mangled-name='PySlice_GetIndicesEx' filepath='Objects/sliceobject.c' line='319' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySlice_GetIndicesEx'> + <parameter type-id='type-id-2' name='_r' filepath='Objects/sliceobject.c' line='319' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Objects/sliceobject.c' line='319' column='1'/> + <parameter type-id='type-id-13' name='start' filepath='Objects/sliceobject.c' line='320' column='1'/> + <parameter type-id='type-id-13' name='stop' filepath='Objects/sliceobject.c' line='320' column='1'/> + <parameter type-id='type-id-13' name='step' filepath='Objects/sliceobject.c' line='320' column='1'/> + <parameter type-id='type-id-13' name='slicelength' filepath='Objects/sliceobject.c' line='321' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/structseq.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyType_Slot' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-425' visibility='default' filepath='./Include/object.h' line='327' column='1' id='type-id-426'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='slot' type-id='type-id-8' visibility='default' filepath='./Include/object.h' line='328' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='pfunc' type-id='type-id-22' visibility='default' filepath='./Include/object.h' line='329' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyType_Slot' type-id='type-id-426' filepath='./Include/object.h' line='330' column='1' id='type-id-425'/> + <class-decl name='PyType_Spec' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-11' visibility='default' filepath='./Include/object.h' line='332' column='1' id='type-id-427'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/object.h' line='333' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='basicsize' type-id='type-id-8' visibility='default' filepath='./Include/object.h' line='334' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='itemsize' type-id='type-id-8' visibility='default' filepath='./Include/object.h' line='335' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='flags' type-id='type-id-95' visibility='default' filepath='./Include/object.h' line='336' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='slots' type-id='type-id-428' visibility='default' filepath='./Include/object.h' line='337' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyType_Spec' type-id='type-id-427' filepath='./Include/object.h' line='338' column='1' id='type-id-11'/> + <pointer-type-def type-id='type-id-425' size-in-bits='64' id='type-id-428'/> + <pointer-type-def type-id='type-id-11' size-in-bits='64' id='type-id-429'/> + <function-decl name='_PyType_HasSubclasses' filepath='./Include/internal/pycore_typeobject.h' line='123' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyType_FromSpecWithBases' mangled-name='PyType_FromSpecWithBases' filepath='./Include/object.h' line='342' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_FromSpecWithBases'> + <parameter type-id='type-id-429'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='PyStructSequence_UnnamedField' type-id='type-id-430' mangled-name='PyStructSequence_UnnamedField' visibility='default' filepath='./Include/structseq.h' line='22' column='1' elf-symbol-id='PyStructSequence_UnnamedField'/> + <function-decl name='PyStructSequence_SetItem' mangled-name='PyStructSequence_SetItem' filepath='Objects/structseq.c' line='77' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStructSequence_SetItem'> + <parameter type-id='type-id-2' name='op' filepath='Objects/structseq.c' line='77' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/structseq.c' line='77' column='1'/> + <parameter type-id='type-id-2' name='v' filepath='Objects/structseq.c' line='77' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyStructSequence_GetItem' mangled-name='PyStructSequence_GetItem' filepath='Objects/structseq.c' line='83' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStructSequence_GetItem'> + <parameter type-id='type-id-2' name='op' filepath='Objects/structseq.c' line='83' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/structseq.c' line='83' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyStructSequence_InitType2' mangled-name='PyStructSequence_InitType2' filepath='Objects/structseq.c' line='561' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStructSequence_InitType2'> + <parameter type-id='type-id-1' name='type' filepath='Objects/structseq.c' line='561' column='1'/> + <parameter type-id='type-id-361' name='desc' filepath='Objects/structseq.c' line='561' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyStructSequence_InitType' mangled-name='PyStructSequence_InitType' filepath='Objects/structseq.c' line='594' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStructSequence_InitType'> + <parameter type-id='type-id-1' name='type' filepath='Objects/structseq.c' line='594' column='1'/> + <parameter type-id='type-id-361' name='desc' filepath='Objects/structseq.c' line='594' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyStructSequence_NewType' mangled-name='_PyStructSequence_NewType' filepath='Objects/structseq.c' line='632' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyStructSequence_NewType'> + <parameter type-id='type-id-361' name='desc' filepath='Objects/structseq.c' line='632' column='1'/> + <parameter type-id='type-id-28' name='tp_flags' filepath='Objects/structseq.c' line='632' column='1'/> + <return type-id='type-id-1'/> + </function-decl> + <function-decl name='PyStructSequence_NewType' mangled-name='PyStructSequence_NewType' filepath='Objects/structseq.c' line='683' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStructSequence_NewType'> + <parameter type-id='type-id-361' name='desc' filepath='Objects/structseq.c' line='683' column='1'/> + <return type-id='type-id-1'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/tupleobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyObject_GC_Resize' mangled-name='_PyObject_GC_Resize' filepath='./Include/objimpl.h' line='182' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GC_Resize'> + <parameter type-id='type-id-322'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-322'/> + </function-decl> + <var-decl name='PyTuple_Type' type-id='type-id-256' mangled-name='PyTuple_Type' visibility='default' filepath='./Include/tupleobject.h' line='23' column='1' elf-symbol-id='PyTuple_Type'/> + <var-decl name='PyTupleIter_Type' type-id='type-id-256' mangled-name='PyTupleIter_Type' visibility='default' filepath='./Include/tupleobject.h' line='24' column='1' elf-symbol-id='PyTupleIter_Type'/> + <function-decl name='PyTuple_SetItem' mangled-name='PyTuple_SetItem' filepath='Objects/tupleobject.c' line='111' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTuple_SetItem'> + <parameter type-id='type-id-2' name='op' filepath='Objects/tupleobject.c' line='111' column='1'/> + <parameter type-id='type-id-14' name='i' filepath='Objects/tupleobject.c' line='111' column='1'/> + <parameter type-id='type-id-2' name='newitem' filepath='Objects/tupleobject.c' line='111' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTuple_MaybeUntrack' mangled-name='_PyTuple_MaybeUntrack' filepath='Objects/tupleobject.c' line='131' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTuple_MaybeUntrack'> + <parameter type-id='type-id-2' name='op' filepath='Objects/tupleobject.c' line='131' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/typeobject.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='_PyWeakReference' size-in-bits='512' is-struct='yes' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='8' column='1' id='type-id-431'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='9' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='wr_object' type-id='type-id-2' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='wr_callback' type-id='type-id-2' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='18' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='hash' type-id='type-id-305' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='wr_prev' type-id='type-id-432' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='wr_next' type-id='type-id-432' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='vectorcall' type-id='type-id-311' visibility='default' filepath='./Include/cpython/weakrefobject.h' line='32' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyWeakReference' type-id='type-id-431' filepath='./Include/weakrefobject.h' line='9' column='1' id='type-id-433'/> + <pointer-type-def type-id='type-id-433' size-in-bits='64' id='type-id-432'/> + <function-decl name='PyEval_GetGlobals' mangled-name='PyEval_GetGlobals' filepath='./Include/ceval.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_GetGlobals'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyWeakref_ClearRef' mangled-name='_PyWeakref_ClearRef' filepath='./Include/cpython/weakrefobject.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWeakref_ClearRef'> + <parameter type-id='type-id-432'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyImport_GetModule' mangled-name='PyImport_GetModule' filepath='./Include/import.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_GetModule'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_Import' mangled-name='PyImport_Import' filepath='./Include/import.h' line='73' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_Import'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_NewKeysForClass' filepath='./Include/internal/pycore_dict.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-346'/> + </function-decl> + <function-decl name='_PyDict_KeysSize' filepath='./Include/internal/pycore_dict.h' line='43' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-346'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='_PyMemoryView_FromBufferProc' filepath='./Include/internal/pycore_memoryobject.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-434'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_GC_Link' filepath='./Include/internal/pycore_object.h' line='329' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_InitializeDict' filepath='./Include/internal/pycore_object.h' line='344' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_FreeInstanceAttributes' filepath='./Include/internal/pycore_object.h' line='392' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_IsInstanceDictEmpty' filepath='./Include/internal/pycore_object.h' line='393' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_FormatNote' filepath='./Include/internal/pycore_pyerrors.h' line='112' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Mangle' filepath='./Include/internal/pycore_symtable.h' line='108' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyStaticType_ClearWeakRefs' filepath='./Include/internal/pycore_typeobject.h' line='116' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-46'/> + </function-decl> + <var-decl name='_PyBufferWrapper_Type' type-id='type-id-256' mangled-name='_PyBufferWrapper_Type' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='141' column='1' elf-symbol-id='_PyBufferWrapper_Type'/> + <function-decl name='PyArg_ParseTuple' mangled-name='PyArg_ParseTuple' filepath='./Include/modsupport.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_ParseTuple'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyType_Type' type-id='type-id-256' mangled-name='PyType_Type' visibility='default' filepath='./Include/object.h' line='372' column='1' elf-symbol-id='PyType_Type'/> + <var-decl name='PyBaseObject_Type' type-id='type-id-256' mangled-name='PyBaseObject_Type' visibility='default' filepath='./Include/object.h' line='373' column='1' elf-symbol-id='PyBaseObject_Type'/> + <var-decl name='PySuper_Type' type-id='type-id-256' mangled-name='PySuper_Type' visibility='default' filepath='./Include/object.h' line='374' column='1' elf-symbol-id='PySuper_Type'/> + <function-decl name='PyInterpreterState_Get' mangled-name='PyInterpreterState_Get' filepath='./Include/pystate.h' line='26' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Get'> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='PyUnicode_IsIdentifier' mangled-name='PyUnicode_IsIdentifier' filepath='./Include/unicodeobject.h' line='1007' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_IsIdentifier'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyWeakref_NewRef' mangled-name='PyWeakref_NewRef' filepath='./Include/weakrefobject.h' line='26' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyWeakref_NewRef'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='strrchr' filepath='/usr/include/string.h' line='273' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyType_ClearCache' mangled-name='PyType_ClearCache' filepath='Objects/typeobject.c' line='640' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_ClearCache'> + <return type-id='type-id-95'/> + </function-decl> + <function-decl name='PyType_AddWatcher' mangled-name='PyType_AddWatcher' filepath='Objects/typeobject.c' line='662' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_AddWatcher'> + <parameter type-id='type-id-435' name='callback' filepath='Objects/typeobject.c' line='662' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyType_ClearWatcher' mangled-name='PyType_ClearWatcher' filepath='Objects/typeobject.c' line='692' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_ClearWatcher'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/typeobject.c' line='692' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyType_Watch' mangled-name='PyType_Watch' filepath='Objects/typeobject.c' line='705' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_Watch'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/typeobject.c' line='705' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Objects/typeobject.c' line='705' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyType_Unwatch' mangled-name='PyType_Unwatch' filepath='Objects/typeobject.c' line='723' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_Unwatch'> + <parameter type-id='type-id-8' name='watcher_id' filepath='Objects/typeobject.c' line='723' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Objects/typeobject.c' line='723' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyType_Modified' mangled-name='PyType_Modified' filepath='Objects/typeobject.c' line='739' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_Modified'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='739' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnstable_Type_AssignVersionTag' mangled-name='PyUnstable_Type_AssignVersionTag' filepath='Objects/typeobject.c' line='907' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Type_AssignVersionTag'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='907' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_LookupSpecialId' mangled-name='_PyObject_LookupSpecialId' filepath='Objects/typeobject.c' line='2157' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_LookupSpecialId'> + <parameter type-id='type-id-2' name='self' filepath='Objects/typeobject.c' line='2157' column='1'/> + <parameter type-id='type-id-309' name='attrid' filepath='Objects/typeobject.c' line='2157' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_GetFlags' mangled-name='PyType_GetFlags' filepath='Objects/typeobject.c' line='3020' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetFlags'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='3020' column='1'/> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyType_SUPPORTS_WEAKREFS' mangled-name='PyType_SUPPORTS_WEAKREFS' filepath='Objects/typeobject.c' line='3027' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_SUPPORTS_WEAKREFS'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='3027' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyType_CalculateMetaclass' mangled-name='_PyType_CalculateMetaclass' filepath='Objects/typeobject.c' line='3035' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_CalculateMetaclass'> + <parameter type-id='type-id-1' name='metatype' filepath='Objects/typeobject.c' line='3035' column='1'/> + <parameter type-id='type-id-2' name='bases' filepath='Objects/typeobject.c' line='3035' column='1'/> + <return type-id='type-id-1'/> + </function-decl> + <function-decl name='PyType_FromMetaclass' mangled-name='PyType_FromMetaclass' filepath='Objects/typeobject.c' line='4465' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_FromMetaclass'> + <parameter type-id='type-id-1' name='metaclass' filepath='Objects/typeobject.c' line='4465' column='1'/> + <parameter type-id='type-id-2' name='module' filepath='Objects/typeobject.c' line='4465' column='1'/> + <parameter type-id='type-id-429' name='spec' filepath='Objects/typeobject.c' line='4466' column='1'/> + <parameter type-id='type-id-2' name='bases_in' filepath='Objects/typeobject.c' line='4466' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_FromModuleAndSpec' mangled-name='PyType_FromModuleAndSpec' filepath='Objects/typeobject.c' line='4472' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_FromModuleAndSpec'> + <parameter type-id='type-id-2' name='module' filepath='Objects/typeobject.c' line='4472' column='1'/> + <parameter type-id='type-id-429' name='spec' filepath='Objects/typeobject.c' line='4472' column='1'/> + <parameter type-id='type-id-2' name='bases' filepath='Objects/typeobject.c' line='4472' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_FromSpec' mangled-name='PyType_FromSpec' filepath='Objects/typeobject.c' line='4484' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_FromSpec'> + <parameter type-id='type-id-429' name='spec' filepath='Objects/typeobject.c' line='4484' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_GetName' mangled-name='PyType_GetName' filepath='Objects/typeobject.c' line='4490' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetName'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='4490' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_GetSlot' mangled-name='PyType_GetSlot' filepath='Objects/typeobject.c' line='4502' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetSlot'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='4502' column='1'/> + <parameter type-id='type-id-8' name='slot' filepath='Objects/typeobject.c' line='4502' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyType_GetModule' mangled-name='PyType_GetModule' filepath='Objects/typeobject.c' line='4524' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetModule'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='4524' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyType_GetModuleState' mangled-name='PyType_GetModuleState' filepath='Objects/typeobject.c' line='4548' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetModuleState'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='4548' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyType_GetModuleByDef' mangled-name='PyType_GetModuleByDef' filepath='Objects/typeobject.c' line='4562' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetModuleByDef'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='4562' column='1'/> + <parameter type-id='type-id-399' name='def' filepath='Objects/typeobject.c' line='4562' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GetTypeData' mangled-name='PyObject_GetTypeData' filepath='Objects/typeobject.c' line='4597' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetTypeData'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/typeobject.c' line='4597' column='1'/> + <parameter type-id='type-id-1' name='cls' filepath='Objects/typeobject.c' line='4597' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyType_GetTypeDataSize' mangled-name='PyType_GetTypeDataSize' filepath='Objects/typeobject.c' line='4604' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyType_GetTypeDataSize'> + <parameter type-id='type-id-1' name='cls' filepath='Objects/typeobject.c' line='4604' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyObject_GetItemData' mangled-name='PyObject_GetItemData' filepath='Objects/typeobject.c' line='4614' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetItemData'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/typeobject.c' line='4614' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyType_LookupId' mangled-name='_PyType_LookupId' filepath='Objects/typeobject.c' line='4756' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_LookupId'> + <parameter type-id='type-id-1' name='type' filepath='Objects/typeobject.c' line='4756' column='1'/> + <parameter type-id='type-id-309' name='name' filepath='Objects/typeobject.c' line='4756' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDictKeys_DecRef' filepath='Objects/typeobject.c' line='4933' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-346'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/typevarobject.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyArg_UnpackKeywordsWithVararg' mangled-name='_PyArg_UnpackKeywordsWithVararg' filepath='./Include/cpython/modsupport.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_UnpackKeywordsWithVararg'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-262'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-248'/> + </function-decl> + <var-decl name='_PyTypeAlias_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_typevarobject.h' line='19' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='Objects/unicodectype.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyUnicode_ToTitlecase' mangled-name='_PyUnicode_ToTitlecase' filepath='Objects/unicodectype.c' line='62' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToTitlecase'> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodectype.c' line='62' column='1'/> + <return type-id='type-id-250'/> + </function-decl> + <function-decl name='_PyUnicode_ToDigit' mangled-name='_PyUnicode_ToDigit' filepath='Objects/unicodectype.c' line='121' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToDigit'> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodectype.c' line='121' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ToUppercase' mangled-name='_PyUnicode_ToUppercase' filepath='Objects/unicodectype.c' line='188' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToUppercase'> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodectype.c' line='188' column='1'/> + <return type-id='type-id-250'/> + </function-decl> + <function-decl name='_PyUnicode_ToLowercase' mangled-name='_PyUnicode_ToLowercase' filepath='Objects/unicodectype.c' line='200' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToLowercase'> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodectype.c' line='200' column='1'/> + <return type-id='type-id-250'/> + </function-decl> + <function-decl name='_PyUnicode_ToNumeric' mangled-name='_PyUnicode_ToNumeric' filepath='Objects/unicodetype_db.h' line='4243' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToNumeric'> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodetype_db.h' line='4243' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/unicodeobject.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-382' size-in-bits='1024' id='type-id-436'> + <subrange length='128' type-id='type-id-28' id='type-id-437'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-382' size-in-bits='infinite' id='type-id-438'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <qualified-type-def type-id='type-id-250' const='yes' id='type-id-439'/> + <function-decl name='_PyCodec_Lookup' mangled-name='_PyCodec_Lookup' filepath='./Include/codecs.h' line='57' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCodec_Lookup'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_Encode' mangled-name='PyCodec_Encode' filepath='./Include/codecs.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_Encode'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_Decode' mangled-name='PyCodec_Decode' filepath='./Include/codecs.h' line='103' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_Decode'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCodec_EncodeText' mangled-name='_PyCodec_EncodeText' filepath='./Include/codecs.h' line='128' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCodec_EncodeText'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCodec_DecodeText' mangled-name='_PyCodec_DecodeText' filepath='./Include/codecs.h' line='134' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCodec_DecodeText'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_LookupError' mangled-name='PyCodec_LookupError' filepath='./Include/codecs.h' line='219' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_LookupError'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_StrictErrors' mangled-name='PyCodec_StrictErrors' filepath='./Include/codecs.h' line='222' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_StrictErrors'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyInterpreterState_GetConfig' mangled-name='_PyInterpreterState_GetConfig' filepath='./Include/cpython/pystate.h' line='330' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetConfig'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-260'/> + </function-decl> + <function-decl name='_PyUnicode_FormatAdvancedWriter' mangled-name='_PyUnicode_FormatAdvancedWriter' filepath='./Include/cpython/unicodeobject.h' line='603' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FormatAdvancedWriter'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsLowercase' mangled-name='_PyUnicode_IsLowercase' filepath='./Include/cpython/unicodeobject.h' line='802' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsLowercase'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsUppercase' mangled-name='_PyUnicode_IsUppercase' filepath='./Include/cpython/unicodeobject.h' line='806' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsUppercase'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsTitlecase' mangled-name='_PyUnicode_IsTitlecase' filepath='./Include/cpython/unicodeobject.h' line='810' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsTitlecase'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsXidStart' mangled-name='_PyUnicode_IsXidStart' filepath='./Include/cpython/unicodeobject.h' line='814' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsXidStart'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsXidContinue' mangled-name='_PyUnicode_IsXidContinue' filepath='./Include/cpython/unicodeobject.h' line='818' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsXidContinue'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsWhitespace' mangled-name='_PyUnicode_IsWhitespace' filepath='./Include/cpython/unicodeobject.h' line='822' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsWhitespace'> + <parameter type-id='type-id-439'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsLinebreak' mangled-name='_PyUnicode_IsLinebreak' filepath='./Include/cpython/unicodeobject.h' line='826' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsLinebreak'> + <parameter type-id='type-id-439'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ToLowerFull' mangled-name='_PyUnicode_ToLowerFull' filepath='./Include/cpython/unicodeobject.h' line='842' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToLowerFull'> + <parameter type-id='type-id-250'/> + <parameter type-id='type-id-440'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ToTitleFull' mangled-name='_PyUnicode_ToTitleFull' filepath='./Include/cpython/unicodeobject.h' line='847' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToTitleFull'> + <parameter type-id='type-id-250'/> + <parameter type-id='type-id-440'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ToUpperFull' mangled-name='_PyUnicode_ToUpperFull' filepath='./Include/cpython/unicodeobject.h' line='852' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToUpperFull'> + <parameter type-id='type-id-250'/> + <parameter type-id='type-id-440'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ToFoldedFull' mangled-name='_PyUnicode_ToFoldedFull' filepath='./Include/cpython/unicodeobject.h' line='857' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToFoldedFull'> + <parameter type-id='type-id-250'/> + <parameter type-id='type-id-440'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsCaseIgnorable' mangled-name='_PyUnicode_IsCaseIgnorable' filepath='./Include/cpython/unicodeobject.h' line='862' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsCaseIgnorable'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsCased' mangled-name='_PyUnicode_IsCased' filepath='./Include/cpython/unicodeobject.h' line='866' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsCased'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ToDecimalDigit' mangled-name='_PyUnicode_ToDecimalDigit' filepath='./Include/cpython/unicodeobject.h' line='870' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ToDecimalDigit'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsDecimalDigit' mangled-name='_PyUnicode_IsDecimalDigit' filepath='./Include/cpython/unicodeobject.h' line='882' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsDecimalDigit'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsDigit' mangled-name='_PyUnicode_IsDigit' filepath='./Include/cpython/unicodeobject.h' line='886' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsDigit'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsNumeric' mangled-name='_PyUnicode_IsNumeric' filepath='./Include/cpython/unicodeobject.h' line='890' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsNumeric'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_IsAlpha' mangled-name='_PyUnicode_IsAlpha' filepath='./Include/cpython/unicodeobject.h' line='898' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsAlpha'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='_Py_ascii_whitespace' type-id='type-id-438' mangled-name='_Py_ascii_whitespace' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='903' column='1' elf-symbol-id='_Py_ascii_whitespace'/> + <function-decl name='_Py_DecodeLocaleEx' mangled-name='_Py_DecodeLocaleEx' filepath='./Include/internal/pycore_fileutils.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DecodeLocaleEx'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-235'/> + <parameter type-id='type-id-441'/> + <parameter type-id='type-id-252'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-442'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_EncodeLocaleEx' mangled-name='_Py_EncodeLocaleEx' filepath='./Include/internal/pycore_fileutils.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_EncodeLocaleEx'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-239'/> + <parameter type-id='type-id-441'/> + <parameter type-id='type-id-252'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-442'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_DumpPathConfig' filepath='./Include/internal/pycore_initconfig.h' line='167' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_SetFileSystemEncoding' filepath='./Include/internal/pycore_pylifecycle.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='_PyUnicodeASCIIIter_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='25' column='1'/> + <function-decl name='PyOS_FSPath' mangled-name='PyOS_FSPath' filepath='./Include/osmodule.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_FSPath'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='PyUnicode_Type' type-id='type-id-256' mangled-name='PyUnicode_Type' visibility='default' filepath='./Include/unicodeobject.h' line='111' column='1' elf-symbol-id='PyUnicode_Type'/> + <var-decl name='PyUnicodeIter_Type' type-id='type-id-256' mangled-name='PyUnicodeIter_Type' visibility='default' filepath='./Include/unicodeobject.h' line='112' column='1' elf-symbol-id='PyUnicodeIter_Type'/> + <function-decl name='wcscmp' filepath='/usr/include/wchar.h' line='106' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-16'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='wmemchr' filepath='/usr/include/wchar.h' line='254' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-422'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='wmemcmp' filepath='/usr/include/wchar.h' line='259' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_GetErrorHandler' mangled-name='_Py_GetErrorHandler' filepath='Objects/unicodeobject.c' line='396' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetErrorHandler'> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='396' column='1'/> + <return type-id='type-id-442'/> + </function-decl> + <function-decl name='_PyUnicode_FastCopyCharacters' mangled-name='_PyUnicode_FastCopyCharacters' filepath='Objects/unicodeobject.c' line='1440' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FastCopyCharacters'> + <parameter type-id='type-id-2' name='to' filepath='Objects/unicodeobject.c' line='1441' column='1'/> + <parameter type-id='type-id-14' name='to_start' filepath='Objects/unicodeobject.c' line='1441' column='1'/> + <parameter type-id='type-id-2' name='from' filepath='Objects/unicodeobject.c' line='1442' column='1'/> + <parameter type-id='type-id-14' name='from_start' filepath='Objects/unicodeobject.c' line='1442' column='1'/> + <parameter type-id='type-id-14' name='how_many' filepath='Objects/unicodeobject.c' line='1442' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnicode_CopyCharacters' mangled-name='PyUnicode_CopyCharacters' filepath='Objects/unicodeobject.c' line='1448' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_CopyCharacters'> + <parameter type-id='type-id-2' name='to' filepath='Objects/unicodeobject.c' line='1448' column='1'/> + <parameter type-id='type-id-14' name='to_start' filepath='Objects/unicodeobject.c' line='1448' column='1'/> + <parameter type-id='type-id-2' name='from' filepath='Objects/unicodeobject.c' line='1449' column='1'/> + <parameter type-id='type-id-14' name='from_start' filepath='Objects/unicodeobject.c' line='1449' column='1'/> + <parameter type-id='type-id-14' name='how_many' filepath='Objects/unicodeobject.c' line='1450' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_Resize' mangled-name='PyUnicode_Resize' filepath='Objects/unicodeobject.c' line='1649' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Resize'> + <parameter type-id='type-id-233' name='p_unicode' filepath='Objects/unicodeobject.c' line='1649' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Objects/unicodeobject.c' line='1649' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_FromWideChar' mangled-name='PyUnicode_FromWideChar' filepath='Objects/unicodeobject.c' line='1750' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromWideChar'> + <parameter type-id='type-id-16' name='u' filepath='Objects/unicodeobject.c' line='1750' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='1750' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_FromKindAndData' mangled-name='PyUnicode_FromKindAndData' filepath='Objects/unicodeobject.c' line='2053' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromKindAndData'> + <parameter type-id='type-id-8' name='kind' filepath='Objects/unicodeobject.c' line='2053' column='1'/> + <parameter type-id='type-id-22' name='buffer' filepath='Objects/unicodeobject.c' line='2053' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='2053' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_FindMaxChar' mangled-name='_PyUnicode_FindMaxChar' filepath='Objects/unicodeobject.c' line='2073' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FindMaxChar'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='2073' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='2073' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/unicodeobject.c' line='2073' column='1'/> + <return type-id='type-id-250'/> + </function-decl> + <function-decl name='PyUnicode_AsUCS4' mangled-name='PyUnicode_AsUCS4' filepath='Objects/unicodeobject.c' line='2273' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUCS4'> + <parameter type-id='type-id-2' name='string' filepath='Objects/unicodeobject.c' line='2273' column='1'/> + <parameter type-id='type-id-440' name='target' filepath='Objects/unicodeobject.c' line='2273' column='1'/> + <parameter type-id='type-id-14' name='targetsize' filepath='Objects/unicodeobject.c' line='2273' column='1'/> + <parameter type-id='type-id-8' name='copy_null' filepath='Objects/unicodeobject.c' line='2274' column='1'/> + <return type-id='type-id-440'/> + </function-decl> + <function-decl name='PyUnicode_AsUCS4Copy' mangled-name='PyUnicode_AsUCS4Copy' filepath='Objects/unicodeobject.c' line='2284' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUCS4Copy'> + <parameter type-id='type-id-2' name='string' filepath='Objects/unicodeobject.c' line='2284' column='1'/> + <return type-id='type-id-440'/> + </function-decl> + <function-decl name='PyUnicode_AsWideChar' mangled-name='PyUnicode_AsWideChar' filepath='Objects/unicodeobject.c' line='2913' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsWideChar'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='2913' column='1'/> + <parameter type-id='type-id-52' name='w' filepath='Objects/unicodeobject.c' line='2914' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='2915' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_AsWideCharString' mangled-name='PyUnicode_AsWideCharString' filepath='Objects/unicodeobject.c' line='2955' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsWideCharString'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='2955' column='1'/> + <parameter type-id='type-id-13' name='size' filepath='Objects/unicodeobject.c' line='2956' column='1'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_PyUnicode_WideCharString_Converter' mangled-name='_PyUnicode_WideCharString_Converter' filepath='Objects/unicodeobject.c' line='3003' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_WideCharString_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/unicodeobject.c' line='3003' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/unicodeobject.c' line='3003' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_WideCharString_Opt_Converter' mangled-name='_PyUnicode_WideCharString_Opt_Converter' filepath='Objects/unicodeobject.c' line='3025' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_WideCharString_Opt_Converter'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/unicodeobject.c' line='3025' column='1'/> + <parameter type-id='type-id-22' name='ptr' filepath='Objects/unicodeobject.c' line='3025' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_FromOrdinal' mangled-name='PyUnicode_FromOrdinal' filepath='Objects/unicodeobject.c' line='3051' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromOrdinal'> + <parameter type-id='type-id-8' name='ordinal' filepath='Objects/unicodeobject.c' line='3051' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_FromObject' mangled-name='PyUnicode_FromObject' filepath='Objects/unicodeobject.c' line='3063' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromObject'> + <parameter type-id='type-id-2' name='obj' filepath='Objects/unicodeobject.c' line='3063' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsDecodedObject' mangled-name='PyUnicode_AsDecodedObject' filepath='Objects/unicodeobject.c' line='3274' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsDecodedObject'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3274' column='1'/> + <parameter type-id='type-id-12' name='encoding' filepath='Objects/unicodeobject.c' line='3275' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3276' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsDecodedUnicode' mangled-name='PyUnicode_AsDecodedUnicode' filepath='Objects/unicodeobject.c' line='3296' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsDecodedUnicode'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3296' column='1'/> + <parameter type-id='type-id-12' name='encoding' filepath='Objects/unicodeobject.c' line='3297' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3298' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsEncodedObject' mangled-name='PyUnicode_AsEncodedObject' filepath='Objects/unicodeobject.c' line='3335' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsEncodedObject'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3335' column='1'/> + <parameter type-id='type-id-12' name='encoding' filepath='Objects/unicodeobject.c' line='3336' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3337' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_EncodeLocale' mangled-name='PyUnicode_EncodeLocale' filepath='Objects/unicodeobject.c' line='3417' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_EncodeLocale'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3417' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3417' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_EncodeFSDefault' mangled-name='PyUnicode_EncodeFSDefault' filepath='Objects/unicodeobject.c' line='3424' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_EncodeFSDefault'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3424' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsEncodedUnicode' mangled-name='PyUnicode_AsEncodedUnicode' filepath='Objects/unicodeobject.c' line='3558' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsEncodedUnicode'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3558' column='1'/> + <parameter type-id='type-id-12' name='encoding' filepath='Objects/unicodeobject.c' line='3559' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3560' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeLocaleAndSize' mangled-name='PyUnicode_DecodeLocaleAndSize' filepath='Objects/unicodeobject.c' line='3638' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeLocaleAndSize'> + <parameter type-id='type-id-12' name='str' filepath='Objects/unicodeobject.c' line='3638' column='1'/> + <parameter type-id='type-id-14' name='len' filepath='Objects/unicodeobject.c' line='3638' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3639' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeLocale' mangled-name='PyUnicode_DecodeLocale' filepath='Objects/unicodeobject.c' line='3646' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeLocale'> + <parameter type-id='type-id-12' name='str' filepath='Objects/unicodeobject.c' line='3646' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='3646' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeFSDefaultAndSize' mangled-name='PyUnicode_DecodeFSDefaultAndSize' filepath='Objects/unicodeobject.c' line='3661' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeFSDefaultAndSize'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='3661' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='3661' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_FSConverter' mangled-name='PyUnicode_FSConverter' filepath='Objects/unicodeobject.c' line='3697' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FSConverter'> + <parameter type-id='type-id-2' name='arg' filepath='Objects/unicodeobject.c' line='3697' column='1'/> + <parameter type-id='type-id-22' name='addr' filepath='Objects/unicodeobject.c' line='3697' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_FSDecoder' mangled-name='PyUnicode_FSDecoder' filepath='Objects/unicodeobject.c' line='3737' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FSDecoder'> + <parameter type-id='type-id-2' name='arg' filepath='Objects/unicodeobject.c' line='3737' column='1'/> + <parameter type-id='type-id-22' name='addr' filepath='Objects/unicodeobject.c' line='3737' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_GetSize' mangled-name='PyUnicode_GetSize' filepath='Objects/unicodeobject.c' line='3817' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_GetSize'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3817' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_GetLength' mangled-name='PyUnicode_GetLength' filepath='Objects/unicodeobject.c' line='3825' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_GetLength'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3825' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_WriteChar' mangled-name='PyUnicode_WriteChar' filepath='Objects/unicodeobject.c' line='3854' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_WriteChar'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='3854' column='1'/> + <parameter type-id='type-id-14' name='index' filepath='Objects/unicodeobject.c' line='3854' column='1'/> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodeobject.c' line='3854' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF7' mangled-name='PyUnicode_DecodeUTF7' filepath='Objects/unicodeobject.c' line='4216' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF7'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='4216' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='4217' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='4218' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF7Stateful' mangled-name='PyUnicode_DecodeUTF7Stateful' filepath='Objects/unicodeobject.c' line='4231' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF7Stateful'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='4231' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='4232' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='4233' column='1'/> + <parameter type-id='type-id-13' name='consumed' filepath='Objects/unicodeobject.c' line='4234' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_EncodeUTF7' mangled-name='_PyUnicode_EncodeUTF7' filepath='Objects/unicodeobject.c' line='4429' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EncodeUTF7'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='4429' column='1'/> + <parameter type-id='type-id-8' name='base64SetO' filepath='Objects/unicodeobject.c' line='4430' column='1'/> + <parameter type-id='type-id-8' name='base64WhiteSpace' filepath='Objects/unicodeobject.c' line='4431' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='4432' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_DecodeUTF8Ex' mangled-name='_Py_DecodeUTF8Ex' filepath='Objects/unicodeobject.c' line='4797' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DecodeUTF8Ex'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='4797' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='4797' column='1'/> + <parameter type-id='type-id-235' name='wstr' filepath='Objects/unicodeobject.c' line='4797' column='1'/> + <parameter type-id='type-id-441' name='wlen' filepath='Objects/unicodeobject.c' line='4797' column='1'/> + <parameter type-id='type-id-252' name='reason' filepath='Objects/unicodeobject.c' line='4798' column='1'/> + <parameter type-id='type-id-442' name='errors' filepath='Objects/unicodeobject.c' line='4798' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_DecodeUTF8_surrogateescape' mangled-name='_Py_DecodeUTF8_surrogateescape' filepath='Objects/unicodeobject.c' line='4906' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DecodeUTF8_surrogateescape'> + <parameter type-id='type-id-12' name='arg' filepath='Objects/unicodeobject.c' line='4906' column='1'/> + <parameter type-id='type-id-14' name='arglen' filepath='Objects/unicodeobject.c' line='4906' column='1'/> + <parameter type-id='type-id-441' name='wlen' filepath='Objects/unicodeobject.c' line='4907' column='1'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_Py_EncodeUTF8Ex' mangled-name='_Py_EncodeUTF8Ex' filepath='Objects/unicodeobject.c' line='4936' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_EncodeUTF8Ex'> + <parameter type-id='type-id-16' name='text' filepath='Objects/unicodeobject.c' line='4936' column='1'/> + <parameter type-id='type-id-239' name='str' filepath='Objects/unicodeobject.c' line='4936' column='1'/> + <parameter type-id='type-id-441' name='error_pos' filepath='Objects/unicodeobject.c' line='4936' column='1'/> + <parameter type-id='type-id-252' name='reason' filepath='Objects/unicodeobject.c' line='4937' column='1'/> + <parameter type-id='type-id-8' name='raw_malloc' filepath='Objects/unicodeobject.c' line='4937' column='1'/> + <parameter type-id='type-id-442' name='errors' filepath='Objects/unicodeobject.c' line='4937' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF32' mangled-name='PyUnicode_DecodeUTF32' filepath='Objects/unicodeobject.c' line='5178' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF32'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='5178' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='5179' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='5180' column='1'/> + <parameter type-id='type-id-179' name='byteorder' filepath='Objects/unicodeobject.c' line='5181' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF32Stateful' mangled-name='PyUnicode_DecodeUTF32Stateful' filepath='Objects/unicodeobject.c' line='5187' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF32Stateful'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='5187' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='5188' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='5189' column='1'/> + <parameter type-id='type-id-179' name='byteorder' filepath='Objects/unicodeobject.c' line='5190' column='1'/> + <parameter type-id='type-id-13' name='consumed' filepath='Objects/unicodeobject.c' line='5191' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_EncodeUTF32' mangled-name='_PyUnicode_EncodeUTF32' filepath='Objects/unicodeobject.c' line='5332' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EncodeUTF32'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='5332' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='5333' column='1'/> + <parameter type-id='type-id-8' name='byteorder' filepath='Objects/unicodeobject.c' line='5334' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsUTF32String' mangled-name='PyUnicode_AsUTF32String' filepath='Objects/unicodeobject.c' line='5477' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUTF32String'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='5477' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF16' mangled-name='PyUnicode_DecodeUTF16' filepath='Objects/unicodeobject.c' line='5485' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF16'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='5485' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='5486' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='5487' column='1'/> + <parameter type-id='type-id-179' name='byteorder' filepath='Objects/unicodeobject.c' line='5488' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF16Stateful' mangled-name='PyUnicode_DecodeUTF16Stateful' filepath='Objects/unicodeobject.c' line='5494' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF16Stateful'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='5494' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='5495' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='5496' column='1'/> + <parameter type-id='type-id-179' name='byteorder' filepath='Objects/unicodeobject.c' line='5497' column='1'/> + <parameter type-id='type-id-13' name='consumed' filepath='Objects/unicodeobject.c' line='5498' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_EncodeUTF16' mangled-name='_PyUnicode_EncodeUTF16' filepath='Objects/unicodeobject.c' line='5649' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EncodeUTF16'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='5649' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='5650' column='1'/> + <parameter type-id='type-id-8' name='byteorder' filepath='Objects/unicodeobject.c' line='5651' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsUTF16String' mangled-name='PyUnicode_AsUTF16String' filepath='Objects/unicodeobject.c' line='5813' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUTF16String'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='5813' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_DecodeUnicodeEscapeStateful' mangled-name='_PyUnicode_DecodeUnicodeEscapeStateful' filepath='Objects/unicodeobject.c' line='6069' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_DecodeUnicodeEscapeStateful'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='6069' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='6070' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='6071' column='1'/> + <parameter type-id='type-id-13' name='consumed' filepath='Objects/unicodeobject.c' line='6072' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUnicodeEscape' mangled-name='PyUnicode_DecodeUnicodeEscape' filepath='Objects/unicodeobject.c' line='6105' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUnicodeEscape'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='6105' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='6106' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='6107' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsUnicodeEscapeString' mangled-name='PyUnicode_AsUnicodeEscapeString' filepath='Objects/unicodeobject.c' line='6115' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUnicodeEscapeString'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='6115' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_DecodeRawUnicodeEscapeStateful' mangled-name='_PyUnicode_DecodeRawUnicodeEscapeStateful' filepath='Objects/unicodeobject.c' line='6232' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_DecodeRawUnicodeEscapeStateful'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='6232' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='6233' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='6234' column='1'/> + <parameter type-id='type-id-13' name='consumed' filepath='Objects/unicodeobject.c' line='6235' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeRawUnicodeEscape' mangled-name='PyUnicode_DecodeRawUnicodeEscape' filepath='Objects/unicodeobject.c' line='6368' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeRawUnicodeEscape'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='6368' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='6369' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='6370' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsRawUnicodeEscapeString' mangled-name='PyUnicode_AsRawUnicodeEscapeString' filepath='Objects/unicodeobject.c' line='6377' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsRawUnicodeEscapeString'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='6377' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_AsLatin1String' mangled-name='_PyUnicode_AsLatin1String' filepath='Objects/unicodeobject.c' line='6741' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_AsLatin1String'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='6741' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='6741' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsLatin1String' mangled-name='PyUnicode_AsLatin1String' filepath='Objects/unicodeobject.c' line='6758' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsLatin1String'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='6758' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeCharmap' mangled-name='PyUnicode_DecodeCharmap' filepath='Objects/unicodeobject.c' line='7807' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeCharmap'> + <parameter type-id='type-id-12' name='s' filepath='Objects/unicodeobject.c' line='7807' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Objects/unicodeobject.c' line='7808' column='1'/> + <parameter type-id='type-id-2' name='mapping' filepath='Objects/unicodeobject.c' line='7809' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='7810' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_BuildEncodingMap' mangled-name='PyUnicode_BuildEncodingMap' filepath='Objects/unicodeobject.c' line='7883' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_BuildEncodingMap'> + <parameter type-id='type-id-2' name='string' filepath='Objects/unicodeobject.c' line='7883' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_EncodeCharmap' mangled-name='_PyUnicode_EncodeCharmap' filepath='Objects/unicodeobject.c' line='8290' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EncodeCharmap'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='8290' column='1'/> + <parameter type-id='type-id-2' name='mapping' filepath='Objects/unicodeobject.c' line='8291' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='8292' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsCharmapString' mangled-name='PyUnicode_AsCharmapString' filepath='Objects/unicodeobject.c' line='8359' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsCharmapString'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='8359' column='1'/> + <parameter type-id='type-id-2' name='mapping' filepath='Objects/unicodeobject.c' line='8360' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Translate' mangled-name='PyUnicode_Translate' filepath='Objects/unicodeobject.c' line='8775' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Translate'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='8775' column='1'/> + <parameter type-id='type-id-2' name='mapping' filepath='Objects/unicodeobject.c' line='8776' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Objects/unicodeobject.c' line='8777' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_InsertThousandsGrouping' mangled-name='_PyUnicode_InsertThousandsGrouping' filepath='Objects/unicodeobject.c' line='8957' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_InsertThousandsGrouping'> + <parameter type-id='type-id-332' name='writer' filepath='Objects/unicodeobject.c' line='8958' column='1'/> + <parameter type-id='type-id-14' name='n_buffer' filepath='Objects/unicodeobject.c' line='8959' column='1'/> + <parameter type-id='type-id-2' name='digits' filepath='Objects/unicodeobject.c' line='8960' column='1'/> + <parameter type-id='type-id-14' name='d_pos' filepath='Objects/unicodeobject.c' line='8961' column='1'/> + <parameter type-id='type-id-14' name='n_digits' filepath='Objects/unicodeobject.c' line='8962' column='1'/> + <parameter type-id='type-id-14' name='min_width' filepath='Objects/unicodeobject.c' line='8963' column='1'/> + <parameter type-id='type-id-12' name='grouping' filepath='Objects/unicodeobject.c' line='8964' column='1'/> + <parameter type-id='type-id-2' name='thousands_sep' filepath='Objects/unicodeobject.c' line='8965' column='1'/> + <parameter type-id='type-id-440' name='maxchar' filepath='Objects/unicodeobject.c' line='8966' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_Count' mangled-name='PyUnicode_Count' filepath='Objects/unicodeobject.c' line='9136' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Count'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='9136' column='1'/> + <parameter type-id='type-id-2' name='substr' filepath='Objects/unicodeobject.c' line='9137' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='9138' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/unicodeobject.c' line='9139' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_Find' mangled-name='PyUnicode_Find' filepath='Objects/unicodeobject.c' line='9148' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Find'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='9148' column='1'/> + <parameter type-id='type-id-2' name='substr' filepath='Objects/unicodeobject.c' line='9149' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='9150' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/unicodeobject.c' line='9151' column='1'/> + <parameter type-id='type-id-8' name='direction' filepath='Objects/unicodeobject.c' line='9152' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_FindChar' mangled-name='PyUnicode_FindChar' filepath='Objects/unicodeobject.c' line='9161' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FindChar'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='9161' column='1'/> + <parameter type-id='type-id-250' name='ch' filepath='Objects/unicodeobject.c' line='9161' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='9162' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/unicodeobject.c' line='9162' column='1'/> + <parameter type-id='type-id-8' name='direction' filepath='Objects/unicodeobject.c' line='9163' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_Tailmatch' mangled-name='PyUnicode_Tailmatch' filepath='Objects/unicodeobject.c' line='9244' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Tailmatch'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='9244' column='1'/> + <parameter type-id='type-id-2' name='substr' filepath='Objects/unicodeobject.c' line='9245' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='9246' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/unicodeobject.c' line='9247' column='1'/> + <parameter type-id='type-id-8' name='direction' filepath='Objects/unicodeobject.c' line='9248' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyUnicode_JoinArray' mangled-name='_PyUnicode_JoinArray' filepath='Objects/unicodeobject.c' line='9513' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_JoinArray'> + <parameter type-id='type-id-2' name='separator' filepath='Objects/unicodeobject.c' line='9513' column='1'/> + <parameter type-id='type-id-248' name='items' filepath='Objects/unicodeobject.c' line='9513' column='1'/> + <parameter type-id='type-id-14' name='seqlen' filepath='Objects/unicodeobject.c' line='9513' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_FastFill' mangled-name='_PyUnicode_FastFill' filepath='Objects/unicodeobject.c' line='9680' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_FastFill'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='9680' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='9680' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Objects/unicodeobject.c' line='9680' column='1'/> + <parameter type-id='type-id-250' name='fill_char' filepath='Objects/unicodeobject.c' line='9681' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnicode_Fill' mangled-name='PyUnicode_Fill' filepath='Objects/unicodeobject.c' line='9693' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Fill'> + <parameter type-id='type-id-2' name='unicode' filepath='Objects/unicodeobject.c' line='9693' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='9693' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Objects/unicodeobject.c' line='9693' column='1'/> + <parameter type-id='type-id-250' name='fill_char' filepath='Objects/unicodeobject.c' line='9694' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyUnicode_Splitlines' mangled-name='PyUnicode_Splitlines' filepath='Objects/unicodeobject.c' line='9767' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Splitlines'> + <parameter type-id='type-id-2' name='string' filepath='Objects/unicodeobject.c' line='9767' column='1'/> + <parameter type-id='type-id-8' name='keepends' filepath='Objects/unicodeobject.c' line='9767' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_EqualToASCIIId' mangled-name='_PyUnicode_EqualToASCIIId' filepath='Objects/unicodeobject.c' line='10655' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_EqualToASCIIId'> + <parameter type-id='type-id-2' name='left' filepath='Objects/unicodeobject.c' line='10655' column='1'/> + <parameter type-id='type-id-309' name='right' filepath='Objects/unicodeobject.c' line='10655' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_RichCompare' mangled-name='PyUnicode_RichCompare' filepath='Objects/unicodeobject.c' line='10693' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_RichCompare'> + <parameter type-id='type-id-2' name='left' filepath='Objects/unicodeobject.c' line='10693' column='1'/> + <parameter type-id='type-id-2' name='right' filepath='Objects/unicodeobject.c' line='10693' column='1'/> + <parameter type-id='type-id-8' name='op' filepath='Objects/unicodeobject.c' line='10693' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Contains' mangled-name='PyUnicode_Contains' filepath='Objects/unicodeobject.c' line='10734' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Contains'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='10734' column='1'/> + <parameter type-id='type-id-2' name='substr' filepath='Objects/unicodeobject.c' line='10734' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_Concat' mangled-name='PyUnicode_Concat' filepath='Objects/unicodeobject.c' line='10795' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Concat'> + <parameter type-id='type-id-2' name='left' filepath='Objects/unicodeobject.c' line='10795' column='1'/> + <parameter type-id='type-id-2' name='right' filepath='Objects/unicodeobject.c' line='10795' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Append' mangled-name='PyUnicode_Append' filepath='Objects/unicodeobject.c' line='10844' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Append'> + <parameter type-id='type-id-233' name='p_left' filepath='Objects/unicodeobject.c' line='10844' column='1'/> + <parameter type-id='type-id-2' name='right' filepath='Objects/unicodeobject.c' line='10844' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnicode_AppendAndDel' mangled-name='PyUnicode_AppendAndDel' filepath='Objects/unicodeobject.c' line='10921' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AppendAndDel'> + <parameter type-id='type-id-233' name='pleft' filepath='Objects/unicodeobject.c' line='10921' column='1'/> + <parameter type-id='type-id-2' name='right' filepath='Objects/unicodeobject.c' line='10921' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_XStrip' mangled-name='_PyUnicode_XStrip' filepath='Objects/unicodeobject.c' line='11733' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_XStrip'> + <parameter type-id='type-id-2' name='self' filepath='Objects/unicodeobject.c' line='11733' column='1'/> + <parameter type-id='type-id-8' name='striptype' filepath='Objects/unicodeobject.c' line='11733' column='1'/> + <parameter type-id='type-id-2' name='sepobj' filepath='Objects/unicodeobject.c' line='11733' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Replace' mangled-name='PyUnicode_Replace' filepath='Objects/unicodeobject.c' line='12006' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Replace'> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='12006' column='1'/> + <parameter type-id='type-id-2' name='substr' filepath='Objects/unicodeobject.c' line='12007' column='1'/> + <parameter type-id='type-id-2' name='replstr' filepath='Objects/unicodeobject.c' line='12008' column='1'/> + <parameter type-id='type-id-14' name='maxcount' filepath='Objects/unicodeobject.c' line='12009' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Split' mangled-name='PyUnicode_Split' filepath='Objects/unicodeobject.c' line='12344' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Split'> + <parameter type-id='type-id-2' name='s' filepath='Objects/unicodeobject.c' line='12344' column='1'/> + <parameter type-id='type-id-2' name='sep' filepath='Objects/unicodeobject.c' line='12344' column='1'/> + <parameter type-id='type-id-14' name='maxsplit' filepath='Objects/unicodeobject.c' line='12344' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Partition' mangled-name='PyUnicode_Partition' filepath='Objects/unicodeobject.c' line='12389' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Partition'> + <parameter type-id='type-id-2' name='str_obj' filepath='Objects/unicodeobject.c' line='12389' column='1'/> + <parameter type-id='type-id-2' name='sep_obj' filepath='Objects/unicodeobject.c' line='12389' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_RPartition' mangled-name='PyUnicode_RPartition' filepath='Objects/unicodeobject.c' line='12441' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_RPartition'> + <parameter type-id='type-id-2' name='str_obj' filepath='Objects/unicodeobject.c' line='12441' column='1'/> + <parameter type-id='type-id-2' name='sep_obj' filepath='Objects/unicodeobject.c' line='12441' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_RSplit' mangled-name='PyUnicode_RSplit' filepath='Objects/unicodeobject.c' line='12535' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_RSplit'> + <parameter type-id='type-id-2' name='s' filepath='Objects/unicodeobject.c' line='12535' column='1'/> + <parameter type-id='type-id-2' name='sep' filepath='Objects/unicodeobject.c' line='12535' column='1'/> + <parameter type-id='type-id-14' name='maxsplit' filepath='Objects/unicodeobject.c' line='12535' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_PrepareKindInternal' mangled-name='_PyUnicodeWriter_PrepareKindInternal' filepath='Objects/unicodeobject.c' line='13046' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_PrepareKindInternal'> + <parameter type-id='type-id-332' name='writer' filepath='Objects/unicodeobject.c' line='13046' column='1'/> + <parameter type-id='type-id-8' name='kind' filepath='Objects/unicodeobject.c' line='13047' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_WriteSubstring' mangled-name='_PyUnicodeWriter_WriteSubstring' filepath='Objects/unicodeobject.c' line='13112' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_WriteSubstring'> + <parameter type-id='type-id-332' name='writer' filepath='Objects/unicodeobject.c' line='13112' column='1'/> + <parameter type-id='type-id-2' name='str' filepath='Objects/unicodeobject.c' line='13112' column='1'/> + <parameter type-id='type-id-14' name='start' filepath='Objects/unicodeobject.c' line='13113' column='1'/> + <parameter type-id='type-id-14' name='end' filepath='Objects/unicodeobject.c' line='13113' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_WriteLatin1String' mangled-name='_PyUnicodeWriter_WriteLatin1String' filepath='Objects/unicodeobject.c' line='13204' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_WriteLatin1String'> + <parameter type-id='type-id-332' name='writer' filepath='Objects/unicodeobject.c' line='13204' column='1'/> + <parameter type-id='type-id-12' name='str' filepath='Objects/unicodeobject.c' line='13205' column='1'/> + <parameter type-id='type-id-14' name='len' filepath='Objects/unicodeobject.c' line='13205' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnicode_Format' mangled-name='PyUnicode_Format' filepath='Objects/unicodeobject.c' line='14354' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Format'> + <parameter type-id='type-id-2' name='format' filepath='Objects/unicodeobject.c' line='14354' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Objects/unicodeobject.c' line='14354' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_InternImmortal' mangled-name='PyUnicode_InternImmortal' filepath='Objects/unicodeobject.c' line='14764' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_InternImmortal'> + <parameter type-id='type-id-233' name='p' filepath='Objects/unicodeobject.c' line='14764' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyInit__string' mangled-name='PyInit__string' filepath='Objects/unicodeobject.c' line='15318' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__string'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/unionobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyUnion_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_unionobject.h' line='11' column='1'/> + <function-decl name='_Py_subs_parameters' filepath='./Include/internal/pycore_unionobject.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_make_parameters' filepath='./Include/internal/pycore_unionobject.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Objects/weakrefobject.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyWeakref_RefType' type-id='type-id-256' mangled-name='_PyWeakref_RefType' visibility='default' filepath='./Include/weakrefobject.h' line='11' column='1' elf-symbol-id='_PyWeakref_RefType'/> + <var-decl name='_PyWeakref_ProxyType' type-id='type-id-256' mangled-name='_PyWeakref_ProxyType' visibility='default' filepath='./Include/weakrefobject.h' line='12' column='1' elf-symbol-id='_PyWeakref_ProxyType'/> + <var-decl name='_PyWeakref_CallableProxyType' type-id='type-id-256' mangled-name='_PyWeakref_CallableProxyType' visibility='default' filepath='./Include/weakrefobject.h' line='13' column='1' elf-symbol-id='_PyWeakref_CallableProxyType'/> + <function-decl name='_PyWeakref_GetWeakrefCount' mangled-name='_PyWeakref_GetWeakrefCount' filepath='Objects/weakrefobject.c' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWeakref_GetWeakrefCount'> + <parameter type-id='type-id-432' name='head' filepath='Objects/weakrefobject.c' line='11' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyWeakref_NewProxy' mangled-name='PyWeakref_NewProxy' filepath='Objects/weakrefobject.c' line='843' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyWeakref_NewProxy'> + <parameter type-id='type-id-2' name='ob' filepath='Objects/weakrefobject.c' line='843' column='1'/> + <parameter type-id='type-id-2' name='callback' filepath='Objects/weakrefobject.c' line='843' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyWeakref_GetObject' mangled-name='PyWeakref_GetObject' filepath='Objects/weakrefobject.c' line='908' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyWeakref_GetObject'> + <parameter type-id='type-id-2' name='ref' filepath='Objects/weakrefobject.c' line='908' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Parser/action_helpers.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-2' size-in-bits='64' id='type-id-353'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-444' size-in-bits='64' id='type-id-445'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-446' size-in-bits='64' id='type-id-447'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-448' size-in-bits='64' id='type-id-449'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-450' size-in-bits='64' id='type-id-451'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-452' size-in-bits='64' id='type-id-453'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-454' size-in-bits='64' id='type-id-455'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-456' size-in-bits='64' id='type-id-457'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <type-decl name='unsigned char' size-in-bits='8' id='type-id-85'/> + <array-type-def dimensions='1' type-id='type-id-22' size-in-bits='64' id='type-id-458'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-459' size-in-bits='64' id='type-id-460'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <class-decl name='_PyUnicodeWriter' size-in-bits='448' is-struct='yes' naming-typedef-id='type-id-461' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='487' column='1' id='type-id-462'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='buffer' type-id='type-id-2' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='488' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='data' type-id='type-id-22' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='489' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='kind' type-id='type-id-8' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='490' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='maxchar' type-id='type-id-250' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='491' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='492' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='pos' type-id='type-id-14' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='493' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='min_length' type-id='type-id-14' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='496' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='min_char' type-id='type-id-250' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='499' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='416'> + <var-decl name='overallocate' type-id='type-id-85' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='502' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='424'> + <var-decl name='readonly' type-id='type-id-85' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='506' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyUnicodeWriter' type-id='type-id-462' filepath='./Include/cpython/unicodeobject.h' line='507' column='1' id='type-id-461'/> + <class-decl name='asdl_generic_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-463' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='32' column='1' id='type-id-464'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-458' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='34' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_generic_seq' type-id='type-id-464' filepath='./Include/internal/pycore_asdl.h' line='35' column='1' id='type-id-463'/> + <class-decl name='asdl_identifier_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-465' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='37' column='1' id='type-id-466'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-353' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='39' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_identifier_seq' type-id='type-id-466' filepath='./Include/internal/pycore_asdl.h' line='40' column='1' id='type-id-465'/> + <typedef-decl name='mod_ty' type-id='type-id-467' filepath='./Include/internal/pycore_ast.h' line='15' column='1' id='type-id-468'/> + <typedef-decl name='stmt_ty' type-id='type-id-469' filepath='./Include/internal/pycore_ast.h' line='17' column='1' id='type-id-452'/> + <typedef-decl name='excepthandler_ty' type-id='type-id-470' filepath='./Include/internal/pycore_ast.h' line='36' column='1' id='type-id-446'/> + <typedef-decl name='alias_ty' type-id='type-id-471' filepath='./Include/internal/pycore_ast.h' line='44' column='1' id='type-id-444'/> + <typedef-decl name='withitem_ty' type-id='type-id-472' filepath='./Include/internal/pycore_ast.h' line='46' column='1' id='type-id-459'/> + <typedef-decl name='match_case_ty' type-id='type-id-473' filepath='./Include/internal/pycore_ast.h' line='48' column='1' id='type-id-448'/> + <typedef-decl name='pattern_ty' type-id='type-id-474' filepath='./Include/internal/pycore_ast.h' line='50' column='1' id='type-id-450'/> + <typedef-decl name='type_ignore_ty' type-id='type-id-475' filepath='./Include/internal/pycore_ast.h' line='52' column='1' id='type-id-454'/> + <typedef-decl name='type_param_ty' type-id='type-id-476' filepath='./Include/internal/pycore_ast.h' line='54' column='1' id='type-id-456'/> + <class-decl name='asdl_stmt_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-477' visibility='default' filepath='./Include/internal/pycore_ast.h' line='64' column='1' id='type-id-478'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-453' visibility='default' filepath='./Include/internal/pycore_ast.h' line='66' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_stmt_seq' type-id='type-id-478' filepath='./Include/internal/pycore_ast.h' line='67' column='1' id='type-id-477'/> + <class-decl name='asdl_excepthandler_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-479' visibility='default' filepath='./Include/internal/pycore_ast.h' line='86' column='1' id='type-id-480'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-447' visibility='default' filepath='./Include/internal/pycore_ast.h' line='88' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_excepthandler_seq' type-id='type-id-480' filepath='./Include/internal/pycore_ast.h' line='89' column='1' id='type-id-479'/> + <class-decl name='asdl_alias_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-481' visibility='default' filepath='./Include/internal/pycore_ast.h' line='115' column='1' id='type-id-482'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-445' visibility='default' filepath='./Include/internal/pycore_ast.h' line='117' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_alias_seq' type-id='type-id-482' filepath='./Include/internal/pycore_ast.h' line='118' column='1' id='type-id-481'/> + <class-decl name='asdl_withitem_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-483' visibility='default' filepath='./Include/internal/pycore_ast.h' line='122' column='1' id='type-id-484'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='123' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='123' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-460' visibility='default' filepath='./Include/internal/pycore_ast.h' line='124' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_withitem_seq' type-id='type-id-484' filepath='./Include/internal/pycore_ast.h' line='125' column='1' id='type-id-483'/> + <class-decl name='asdl_match_case_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-485' visibility='default' filepath='./Include/internal/pycore_ast.h' line='129' column='1' id='type-id-486'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-449' visibility='default' filepath='./Include/internal/pycore_ast.h' line='131' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_match_case_seq' type-id='type-id-486' filepath='./Include/internal/pycore_ast.h' line='132' column='1' id='type-id-485'/> + <class-decl name='asdl_pattern_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-487' visibility='default' filepath='./Include/internal/pycore_ast.h' line='137' column='1' id='type-id-488'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-451' visibility='default' filepath='./Include/internal/pycore_ast.h' line='139' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_pattern_seq' type-id='type-id-488' filepath='./Include/internal/pycore_ast.h' line='140' column='1' id='type-id-487'/> + <class-decl name='asdl_type_ignore_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-489' visibility='default' filepath='./Include/internal/pycore_ast.h' line='144' column='1' id='type-id-490'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-455' visibility='default' filepath='./Include/internal/pycore_ast.h' line='146' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_type_ignore_seq' type-id='type-id-490' filepath='./Include/internal/pycore_ast.h' line='147' column='1' id='type-id-489'/> + <class-decl name='asdl_type_param_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-491' visibility='default' filepath='./Include/internal/pycore_ast.h' line='152' column='1' id='type-id-492'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-457' visibility='default' filepath='./Include/internal/pycore_ast.h' line='154' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_type_param_seq' type-id='type-id-492' filepath='./Include/internal/pycore_ast.h' line='155' column='1' id='type-id-491'/> + <enum-decl name='_mod_kind' filepath='./Include/internal/pycore_ast.h' line='161' column='1' id='type-id-493'> + <underlying-type type-id='type-id-24'/> + <enumerator name='Module_kind' value='1'/> + <enumerator name='Interactive_kind' value='2'/> + <enumerator name='Expression_kind' value='3'/> + <enumerator name='FunctionType_kind' value='4'/> + </enum-decl> + <class-decl name='_mod' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='163' column='1' id='type-id-494'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-493' visibility='default' filepath='./Include/internal/pycore_ast.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-495' visibility='default' filepath='./Include/internal/pycore_ast.h' line='184' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__' size-in-bits='128' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='165' column='1' id='type-id-495'> + <data-member access='public'> + <var-decl name='Module' type-id='type-id-496' visibility='default' filepath='./Include/internal/pycore_ast.h' line='169' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Interactive' type-id='type-id-497' visibility='default' filepath='./Include/internal/pycore_ast.h' line='173' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Expression' type-id='type-id-498' visibility='default' filepath='./Include/internal/pycore_ast.h' line='177' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='FunctionType' type-id='type-id-499' visibility='default' filepath='./Include/internal/pycore_ast.h' line='182' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='166' column='1' id='type-id-496'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='167' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type_ignores' type-id='type-id-501' visibility='default' filepath='./Include/internal/pycore_ast.h' line='168' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__39' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='171' column='1' id='type-id-497'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='172' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__40' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='175' column='1' id='type-id-498'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='body' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='176' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__41' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='179' column='1' id='type-id-499'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='argtypes' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='180' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='returns' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='181' column='1'/> + </data-member> + </class-decl> + <enum-decl name='_stmt_kind' filepath='./Include/internal/pycore_ast.h' line='187' column='1' id='type-id-504'> + <underlying-type type-id='type-id-24'/> + <enumerator name='FunctionDef_kind' value='1'/> + <enumerator name='AsyncFunctionDef_kind' value='2'/> + <enumerator name='ClassDef_kind' value='3'/> + <enumerator name='Return_kind' value='4'/> + <enumerator name='Delete_kind' value='5'/> + <enumerator name='Assign_kind' value='6'/> + <enumerator name='TypeAlias_kind' value='7'/> + <enumerator name='AugAssign_kind' value='8'/> + <enumerator name='AnnAssign_kind' value='9'/> + <enumerator name='For_kind' value='10'/> + <enumerator name='AsyncFor_kind' value='11'/> + <enumerator name='While_kind' value='12'/> + <enumerator name='If_kind' value='13'/> + <enumerator name='With_kind' value='14'/> + <enumerator name='AsyncWith_kind' value='15'/> + <enumerator name='Match_kind' value='16'/> + <enumerator name='Raise_kind' value='17'/> + <enumerator name='Try_kind' value='18'/> + <enumerator name='TryStar_kind' value='19'/> + <enumerator name='Assert_kind' value='20'/> + <enumerator name='Import_kind' value='21'/> + <enumerator name='ImportFrom_kind' value='22'/> + <enumerator name='Global_kind' value='23'/> + <enumerator name='Nonlocal_kind' value='24'/> + <enumerator name='Expr_kind' value='25'/> + <enumerator name='Pass_kind' value='26'/> + <enumerator name='Break_kind' value='27'/> + <enumerator name='Continue_kind' value='28'/> + </enum-decl> + <class-decl name='_stmt' size-in-bits='640' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='196' column='1' id='type-id-505'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-504' visibility='default' filepath='./Include/internal/pycore_ast.h' line='197' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-506' visibility='default' filepath='./Include/internal/pycore_ast.h' line='352' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='353' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='544'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='354' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='355' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='608'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='356' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__1' size-in-bits='448' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='198' column='1' id='type-id-506'> + <data-member access='public'> + <var-decl name='FunctionDef' type-id='type-id-507' visibility='default' filepath='./Include/internal/pycore_ast.h' line='207' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='AsyncFunctionDef' type-id='type-id-507' visibility='default' filepath='./Include/internal/pycore_ast.h' line='217' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='ClassDef' type-id='type-id-508' visibility='default' filepath='./Include/internal/pycore_ast.h' line='226' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Return' type-id='type-id-509' visibility='default' filepath='./Include/internal/pycore_ast.h' line='230' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Delete' type-id='type-id-510' visibility='default' filepath='./Include/internal/pycore_ast.h' line='234' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Assign' type-id='type-id-511' visibility='default' filepath='./Include/internal/pycore_ast.h' line='240' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='TypeAlias' type-id='type-id-512' visibility='default' filepath='./Include/internal/pycore_ast.h' line='246' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='AugAssign' type-id='type-id-513' visibility='default' filepath='./Include/internal/pycore_ast.h' line='252' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='AnnAssign' type-id='type-id-514' visibility='default' filepath='./Include/internal/pycore_ast.h' line='259' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='For' type-id='type-id-515' visibility='default' filepath='./Include/internal/pycore_ast.h' line='267' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='AsyncFor' type-id='type-id-515' visibility='default' filepath='./Include/internal/pycore_ast.h' line='275' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='While' type-id='type-id-516' visibility='default' filepath='./Include/internal/pycore_ast.h' line='281' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='If' type-id='type-id-516' visibility='default' filepath='./Include/internal/pycore_ast.h' line='287' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='With' type-id='type-id-517' visibility='default' filepath='./Include/internal/pycore_ast.h' line='293' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='AsyncWith' type-id='type-id-517' visibility='default' filepath='./Include/internal/pycore_ast.h' line='299' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Match' type-id='type-id-518' visibility='default' filepath='./Include/internal/pycore_ast.h' line='304' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Raise' type-id='type-id-519' visibility='default' filepath='./Include/internal/pycore_ast.h' line='309' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Try' type-id='type-id-520' visibility='default' filepath='./Include/internal/pycore_ast.h' line='316' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='TryStar' type-id='type-id-520' visibility='default' filepath='./Include/internal/pycore_ast.h' line='323' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Assert' type-id='type-id-521' visibility='default' filepath='./Include/internal/pycore_ast.h' line='328' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Import' type-id='type-id-522' visibility='default' filepath='./Include/internal/pycore_ast.h' line='332' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='ImportFrom' type-id='type-id-523' visibility='default' filepath='./Include/internal/pycore_ast.h' line='338' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Global' type-id='type-id-524' visibility='default' filepath='./Include/internal/pycore_ast.h' line='342' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Nonlocal' type-id='type-id-524' visibility='default' filepath='./Include/internal/pycore_ast.h' line='346' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Expr' type-id='type-id-509' visibility='default' filepath='./Include/internal/pycore_ast.h' line='350' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__2' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='199' column='1' id='type-id-507'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='200' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type_params' type-id='type-id-526' visibility='default' filepath='./Include/internal/pycore_ast.h' line='201' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='args' type-id='type-id-527' visibility='default' filepath='./Include/internal/pycore_ast.h' line='202' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='203' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='decorator_list' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='204' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='returns' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='205' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='type_comment' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='206' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__6' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='219' column='1' id='type-id-508'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='220' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type_params' type-id='type-id-526' visibility='default' filepath='./Include/internal/pycore_ast.h' line='221' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='bases' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='222' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='keywords' type-id='type-id-529' visibility='default' filepath='./Include/internal/pycore_ast.h' line='223' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='224' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='decorator_list' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='225' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__8' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='232' column='1' id='type-id-510'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='targets' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='233' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__9' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='236' column='1' id='type-id-511'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='targets' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='237' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='238' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='type_comment' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='239' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__10' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='242' column='1' id='type-id-512'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='243' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type_params' type-id='type-id-526' visibility='default' filepath='./Include/internal/pycore_ast.h' line='244' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='245' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__11' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='248' column='1' id='type-id-513'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='target' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='249' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='op' type-id='type-id-530' visibility='default' filepath='./Include/internal/pycore_ast.h' line='250' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='251' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__12' size-in-bits='256' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='254' column='1' id='type-id-514'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='target' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='255' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='annotation' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='256' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='257' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='simple' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='258' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__13' size-in-bits='320' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='261' column='1' id='type-id-515'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='target' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='262' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='iter' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='263' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='264' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='orelse' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='265' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='type_comment' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='266' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__15' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='277' column='1' id='type-id-516'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='test' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='278' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='279' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='orelse' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='280' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__17' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='289' column='1' id='type-id-517'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='items' type-id='type-id-531' visibility='default' filepath='./Include/internal/pycore_ast.h' line='290' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='291' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='type_comment' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='292' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__19' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='301' column='1' id='type-id-518'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='subject' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='302' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='cases' type-id='type-id-532' visibility='default' filepath='./Include/internal/pycore_ast.h' line='303' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__28' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='306' column='1' id='type-id-519'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='exc' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='307' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='cause' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='308' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__29' size-in-bits='256' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='311' column='1' id='type-id-520'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='312' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='handlers' type-id='type-id-533' visibility='default' filepath='./Include/internal/pycore_ast.h' line='313' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='orelse' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='314' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='finalbody' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='315' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__32' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='325' column='1' id='type-id-521'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='test' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='326' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='msg' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='327' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__33' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='330' column='1' id='type-id-522'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='names' type-id='type-id-534' visibility='default' filepath='./Include/internal/pycore_ast.h' line='331' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__34' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='334' column='1' id='type-id-523'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='module' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='335' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='names' type-id='type-id-534' visibility='default' filepath='./Include/internal/pycore_ast.h' line='336' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='337' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__35' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='340' column='1' id='type-id-524'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='names' type-id='type-id-535' visibility='default' filepath='./Include/internal/pycore_ast.h' line='341' column='1'/> + </data-member> + </class-decl> + <enum-decl name='_excepthandler_kind' filepath='./Include/internal/pycore_ast.h' line='523' column='1' id='type-id-536'> + <underlying-type type-id='type-id-24'/> + <enumerator name='ExceptHandler_kind' value='1'/> + </enum-decl> + <class-decl name='_excepthandler' size-in-bits='384' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='524' column='1' id='type-id-537'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-536' visibility='default' filepath='./Include/internal/pycore_ast.h' line='525' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-538' visibility='default' filepath='./Include/internal/pycore_ast.h' line='533' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='534' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='535' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='536' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='537' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__4' size-in-bits='192' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='526' column='1' id='type-id-538'> + <data-member access='public'> + <var-decl name='ExceptHandler' type-id='type-id-539' visibility='default' filepath='./Include/internal/pycore_ast.h' line='531' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__31' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='527' column='1' id='type-id-539'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='type' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='528' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='529' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='530' column='1'/> + </data-member> + </class-decl> + <class-decl name='_alias' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='569' column='1' id='type-id-540'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='570' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='asname' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='571' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='572' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='573' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='574' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='575' column='1'/> + </data-member> + </class-decl> + <class-decl name='_withitem' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='578' column='1' id='type-id-541'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='context_expr' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='579' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='optional_vars' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='580' column='1'/> + </data-member> + </class-decl> + <class-decl name='_match_case' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='583' column='1' id='type-id-542'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='pattern' type-id='type-id-450' visibility='default' filepath='./Include/internal/pycore_ast.h' line='584' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='guard' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='585' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='body' type-id='type-id-500' visibility='default' filepath='./Include/internal/pycore_ast.h' line='586' column='1'/> + </data-member> + </class-decl> + <enum-decl name='_pattern_kind' filepath='./Include/internal/pycore_ast.h' line='589' column='1' id='type-id-543'> + <underlying-type type-id='type-id-24'/> + <enumerator name='MatchValue_kind' value='1'/> + <enumerator name='MatchSingleton_kind' value='2'/> + <enumerator name='MatchSequence_kind' value='3'/> + <enumerator name='MatchMapping_kind' value='4'/> + <enumerator name='MatchClass_kind' value='5'/> + <enumerator name='MatchStar_kind' value='6'/> + <enumerator name='MatchAs_kind' value='7'/> + <enumerator name='MatchOr_kind' value='8'/> + </enum-decl> + <class-decl name='_pattern' size-in-bits='448' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='593' column='1' id='type-id-544'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-543' visibility='default' filepath='./Include/internal/pycore_ast.h' line='594' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-545' visibility='default' filepath='./Include/internal/pycore_ast.h' line='634' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='635' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='636' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='637' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='416'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='638' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__3' size-in-bits='256' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='595' column='1' id='type-id-545'> + <data-member access='public'> + <var-decl name='MatchValue' type-id='type-id-509' visibility='default' filepath='./Include/internal/pycore_ast.h' line='598' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchSingleton' type-id='type-id-546' visibility='default' filepath='./Include/internal/pycore_ast.h' line='602' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchSequence' type-id='type-id-547' visibility='default' filepath='./Include/internal/pycore_ast.h' line='606' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchMapping' type-id='type-id-548' visibility='default' filepath='./Include/internal/pycore_ast.h' line='612' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchClass' type-id='type-id-549' visibility='default' filepath='./Include/internal/pycore_ast.h' line='619' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchStar' type-id='type-id-550' visibility='default' filepath='./Include/internal/pycore_ast.h' line='623' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchAs' type-id='type-id-551' visibility='default' filepath='./Include/internal/pycore_ast.h' line='628' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='MatchOr' type-id='type-id-547' visibility='default' filepath='./Include/internal/pycore_ast.h' line='632' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__22' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='600' column='1' id='type-id-546'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-552' visibility='default' filepath='./Include/internal/pycore_ast.h' line='601' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__23' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='604' column='1' id='type-id-547'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='patterns' type-id='type-id-553' visibility='default' filepath='./Include/internal/pycore_ast.h' line='605' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__24' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='608' column='1' id='type-id-548'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='keys' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='609' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='patterns' type-id='type-id-553' visibility='default' filepath='./Include/internal/pycore_ast.h' line='610' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='rest' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='611' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__25' size-in-bits='256' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='614' column='1' id='type-id-549'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='cls' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='615' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='patterns' type-id='type-id-553' visibility='default' filepath='./Include/internal/pycore_ast.h' line='616' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='kwd_attrs' type-id='type-id-535' visibility='default' filepath='./Include/internal/pycore_ast.h' line='617' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='kwd_patterns' type-id='type-id-553' visibility='default' filepath='./Include/internal/pycore_ast.h' line='618' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__27' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='625' column='1' id='type-id-551'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='pattern' type-id='type-id-450' visibility='default' filepath='./Include/internal/pycore_ast.h' line='626' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='627' column='1'/> + </data-member> + </class-decl> + <enum-decl name='_type_ignore_kind' filepath='./Include/internal/pycore_ast.h' line='641' column='1' id='type-id-554'> + <underlying-type type-id='type-id-24'/> + <enumerator name='TypeIgnore_kind' value='1'/> + </enum-decl> + <class-decl name='_type_ignore' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='642' column='1' id='type-id-555'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-554' visibility='default' filepath='./Include/internal/pycore_ast.h' line='643' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-556' visibility='default' filepath='./Include/internal/pycore_ast.h' line='650' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__5' size-in-bits='128' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='644' column='1' id='type-id-556'> + <data-member access='public'> + <var-decl name='TypeIgnore' type-id='type-id-557' visibility='default' filepath='./Include/internal/pycore_ast.h' line='648' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__39' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='645' column='1' id='type-id-557'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='646' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='tag' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='647' column='1'/> + </data-member> + </class-decl> + <enum-decl name='_type_param_kind' filepath='./Include/internal/pycore_ast.h' line='653' column='1' id='type-id-558'> + <underlying-type type-id='type-id-24'/> + <enumerator name='TypeVar_kind' value='1'/> + <enumerator name='ParamSpec_kind' value='2'/> + <enumerator name='TypeVarTuple_kind' value='3'/> + </enum-decl> + <class-decl name='_type_param' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='654' column='1' id='type-id-559'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-558' visibility='default' filepath='./Include/internal/pycore_ast.h' line='655' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-560' visibility='default' filepath='./Include/internal/pycore_ast.h' line='670' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='671' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='672' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='673' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='674' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__2' size-in-bits='128' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='656' column='1' id='type-id-560'> + <data-member access='public'> + <var-decl name='TypeVar' type-id='type-id-561' visibility='default' filepath='./Include/internal/pycore_ast.h' line='660' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='ParamSpec' type-id='type-id-550' visibility='default' filepath='./Include/internal/pycore_ast.h' line='664' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='TypeVarTuple' type-id='type-id-550' visibility='default' filepath='./Include/internal/pycore_ast.h' line='668' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__4' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='657' column='1' id='type-id-561'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='658' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='bound' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='659' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__5' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='662' column='1' id='type-id-550'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='663' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Py_UCS4' type-id='type-id-352' filepath='./Include/unicodeobject.h' line='102' column='1' id='type-id-250'/> + <pointer-type-def type-id='type-id-461' size-in-bits='64' id='type-id-332'/> + <pointer-type-def type-id='type-id-540' size-in-bits='64' id='type-id-471'/> + <pointer-type-def type-id='type-id-537' size-in-bits='64' id='type-id-470'/> + <pointer-type-def type-id='type-id-542' size-in-bits='64' id='type-id-473'/> + <pointer-type-def type-id='type-id-494' size-in-bits='64' id='type-id-467'/> + <pointer-type-def type-id='type-id-544' size-in-bits='64' id='type-id-474'/> + <pointer-type-def type-id='type-id-505' size-in-bits='64' id='type-id-469'/> + <pointer-type-def type-id='type-id-555' size-in-bits='64' id='type-id-475'/> + <pointer-type-def type-id='type-id-559' size-in-bits='64' id='type-id-476'/> + <pointer-type-def type-id='type-id-541' size-in-bits='64' id='type-id-472'/> + <pointer-type-def type-id='type-id-481' size-in-bits='64' id='type-id-534'/> + <pointer-type-def type-id='type-id-479' size-in-bits='64' id='type-id-533'/> + <pointer-type-def type-id='type-id-463' size-in-bits='64' id='type-id-562'/> + <pointer-type-def type-id='type-id-465' size-in-bits='64' id='type-id-535'/> + <pointer-type-def type-id='type-id-485' size-in-bits='64' id='type-id-532'/> + <pointer-type-def type-id='type-id-487' size-in-bits='64' id='type-id-553'/> + <pointer-type-def type-id='type-id-477' size-in-bits='64' id='type-id-500'/> + <pointer-type-def type-id='type-id-489' size-in-bits='64' id='type-id-501'/> + <pointer-type-def type-id='type-id-491' size-in-bits='64' id='type-id-526'/> + <pointer-type-def type-id='type-id-483' size-in-bits='64' id='type-id-531'/> + <function-decl name='PyBytes_FromString' mangled-name='PyBytes_FromString' filepath='./Include/bytesobject.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_FromString'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_Concat' mangled-name='PyBytes_Concat' filepath='./Include/bytesobject.h' line='44' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_Concat'> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_Init' mangled-name='_PyUnicodeWriter_Init' filepath='./Include/cpython/unicodeobject.h' line='515' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_Init'> + <parameter type-id='type-id-332'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_WriteStr' mangled-name='_PyUnicodeWriter_WriteStr' filepath='./Include/cpython/unicodeobject.h' line='561' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_WriteStr'> + <parameter type-id='type-id-332'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_Finish' mangled-name='_PyUnicodeWriter_Finish' filepath='./Include/cpython/unicodeobject.h' line='594' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_Finish'> + <parameter type-id='type-id-332'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicodeWriter_Dealloc' mangled-name='_PyUnicodeWriter_Dealloc' filepath='./Include/cpython/unicodeobject.h' line='598' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicodeWriter_Dealloc'> + <parameter type-id='type-id-332'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_asdl_generic_seq_new' filepath='./Include/internal/pycore_asdl.h' line='47' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-562'/> + </function-decl> + <function-decl name='_Py_asdl_identifier_seq_new' filepath='./Include/internal/pycore_asdl.h' line='48' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-535'/> + </function-decl> + <function-decl name='_Py_asdl_int_seq_new' filepath='./Include/internal/pycore_asdl.h' line='49' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-564'/> + </function-decl> + <function-decl name='_Py_asdl_expr_seq_new' filepath='./Include/internal/pycore_ast.h' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-503'/> + </function-decl> + <function-decl name='_Py_asdl_arg_seq_new' filepath='./Include/internal/pycore_ast.h' line='106' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-565'/> + </function-decl> + <function-decl name='_Py_asdl_keyword_seq_new' filepath='./Include/internal/pycore_ast.h' line='113' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-529'/> + </function-decl> + <function-decl name='_Py_asdl_pattern_seq_new' filepath='./Include/internal/pycore_ast.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-553'/> + </function-decl> + <function-decl name='_Py_asdl_type_ignore_seq_new' filepath='./Include/internal/pycore_ast.h' line='149' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-501'/> + </function-decl> + <function-decl name='_PyAST_Module' filepath='./Include/internal/pycore_ast.h' line='679' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-501'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='_PyAST_FunctionDef' filepath='./Include/internal/pycore_ast.h' line='685' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-526'/> + <parameter type-id='type-id-527'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_AsyncFunctionDef' filepath='./Include/internal/pycore_ast.h' line='690' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-526'/> + <parameter type-id='type-id-527'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_ClassDef' filepath='./Include/internal/pycore_ast.h' line='696' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-526'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-529'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Call' filepath='./Include/internal/pycore_ast.h' line='814' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-529'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_FormattedValue' filepath='./Include/internal/pycore_ast.h' line='817' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_JoinedStr' filepath='./Include/internal/pycore_ast.h' line='820' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Attribute' filepath='./Include/internal/pycore_ast.h' line='825' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-566'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Subscript' filepath='./Include/internal/pycore_ast.h' line='828' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-566'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Starred' filepath='./Include/internal/pycore_ast.h' line='831' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-566'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_List' filepath='./Include/internal/pycore_ast.h' line='837' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-566'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Tuple' filepath='./Include/internal/pycore_ast.h' line='840' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-566'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_arguments' filepath='./Include/internal/pycore_ast.h' line='853' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-565'/> + <parameter type-id='type-id-565'/> + <parameter type-id='type-id-567'/> + <parameter type-id='type-id-565'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-567'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-527'/> + </function-decl> + <function-decl name='_PyAST_arg' filepath='./Include/internal/pycore_ast.h' line='857' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-567'/> + </function-decl> + <function-decl name='_PyAST_alias' filepath='./Include/internal/pycore_ast.h' line='863' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-444'/> + </function-decl> + <function-decl name='_PyAST_TypeIgnore' filepath='./Include/internal/pycore_ast.h' line='894' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-454'/> + </function-decl> + <function-decl name='PyUnicode_FromString' mangled-name='PyUnicode_FromString' filepath='./Include/unicodeobject.h' line='137' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromString'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='strcpy' filepath='/usr/include/string.h' line='141' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='strpbrk' filepath='/usr/include/string.h' line='323' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_PyPegen_new_identifier' filepath='Parser/pegen.h' line='294' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyPegen_parse_string' filepath='Parser/string_parser.h' line='8' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyPegen_decode_string' filepath='Parser/string_parser.h' line='9' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-2'/> + </function-decl> + <class-decl name='__anonymous_struct__7' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='228' column='1' id='type-id-509'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='229' column='1'/> + </data-member> + </class-decl> + </abi-instr> + <abi-instr address-size='64' path='Parser/myreadline.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-570' size-in-bits='512' id='type-id-571'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-573' size-in-bits='5120' id='type-id-574'> + <subrange length='80' type-id='type-id-28' id='type-id-575'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-329' size-in-bits='512' id='type-id-576'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-346' size-in-bits='5120' id='type-id-577'> + <subrange length='80' type-id='type-id-28' id='type-id-575'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-340' size-in-bits='5120' id='type-id-578'> + <subrange length='80' type-id='type-id-28' id='type-id-575'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-342' size-in-bits='512' id='type-id-579'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-366' size-in-bits='512' id='type-id-580'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-249' size-in-bits='5120' id='type-id-581'> + <subrange length='80' type-id='type-id-28' id='type-id-575'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-240' size-in-bits='67072' id='type-id-582'> + <subrange length='262' type-id='type-id-28' id='type-id-583'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-2' size-in-bits='512' id='type-id-584'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='2' type-id='type-id-2' size-in-bits='8192' id='type-id-585'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + <subrange length='16' type-id='type-id-28' id='type-id-57'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-586' size-in-bits='1280' id='type-id-587'> + <subrange length='20' type-id='type-id-28' id='type-id-588'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-435' size-in-bits='512' id='type-id-589'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-590' size-in-bits='32' id='type-id-591'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-592' size-in-bits='5120' id='type-id-593'> + <subrange length='80' type-id='type-id-28' id='type-id-575'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-594' size-in-bits='49152' id='type-id-595'> + <subrange length='128' type-id='type-id-28' id='type-id-437'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-596' size-in-bits='65536' id='type-id-597'> + <subrange length='128' type-id='type-id-28' id='type-id-437'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-598' size-in-bits='98304' id='type-id-599'> + <subrange length='256' type-id='type-id-28' id='type-id-62'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-600' size-in-bits='4096' id='type-id-601'> + <subrange length='32' type-id='type-id-28' id='type-id-60'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-602' size-in-bits='1048576' id='type-id-603'> + <subrange length='16384' type-id='type-id-28' id='type-id-604'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-605' size-in-bits='2097152' id='type-id-606'> + <subrange length='32768' type-id='type-id-28' id='type-id-607'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-608' size-in-bits='2097152' id='type-id-609'> + <subrange length='32768' type-id='type-id-28' id='type-id-607'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-610' size-in-bits='4160' id='type-id-611'> + <subrange length='65' type-id='type-id-28' id='type-id-64'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-612' size-in-bits='2048' id='type-id-613'> + <subrange length='32' type-id='type-id-28' id='type-id-60'/> + </array-type-def> + <type-decl name='bool' size-in-bits='8' id='type-id-614'/> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='320' id='type-id-615'> + <subrange length='40' type-id='type-id-28' id='type-id-616'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='384' id='type-id-617'> + <subrange length='48' type-id='type-id-28' id='type-id-618'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='32' id='type-id-619'> + <subrange length='4' type-id='type-id-28' id='type-id-223'/> + </array-type-def> + <class-decl name='PyAsyncGenASend' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-620'/> + <class-decl name='_PyAsyncGenWrappedValue' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-621'/> + <class-decl name='_dictkeysobject' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dict.h' line='72' column='1' id='type-id-350'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='dk_refcnt' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_dict.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='dk_log2_size' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_dict.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='72'> + <var-decl name='dk_log2_index_bytes' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_dict.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='80'> + <var-decl name='dk_kind' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_dict.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='dk_version' type-id='type-id-352' visibility='default' filepath='./Include/internal/pycore_dict.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='dk_usable' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_dict.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='dk_nentries' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_dict.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='dk_indices' type-id='type-id-257' visibility='default' filepath='./Include/internal/pycore_dict.h' line='106' column='1'/> + </data-member> + </class-decl> + <class-decl name='_dictvalues' size-in-bits='64' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dict.h' line='122' column='1' id='type-id-351'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='values' type-id='type-id-353' visibility='default' filepath='./Include/internal/pycore_dict.h' line='123' column='1'/> + </data-member> + </class-decl> + <class-decl name='code_arena_st' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-622'/> + <array-type-def dimensions='1' type-id='type-id-384' size-in-bits='32' id='type-id-623'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-251' size-in-bits='18432' id='type-id-624'> + <subrange length='288' type-id='type-id-28' id='type-id-625'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-397' size-in-bits='16320' id='type-id-626'> + <subrange length='255' type-id='type-id-28' id='type-id-627'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-628' size-in-bits='576' id='type-id-629'> + <subrange length='3' type-id='type-id-28' id='type-id-630'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-631' size-in-bits='576' id='type-id-632'> + <subrange length='3' type-id='type-id-28' id='type-id-630'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='640' id='type-id-633'> + <subrange length='20' type-id='type-id-28' id='type-id-588'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='896' id='type-id-634'> + <subrange length='28' type-id='type-id-28' id='type-id-635'/> + </array-type-def> + <type-decl name='long long int' size-in-bits='64' id='type-id-378'/> + <type-decl name='long long unsigned int' size-in-bits='64' id='type-id-387'/> + <array-type-def dimensions='1' type-id='type-id-636' size-in-bits='4096' id='type-id-637'> + <subrange length='64' type-id='type-id-28' id='type-id-638'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-639' size-in-bits='640' id='type-id-640'> + <subrange length='10' type-id='type-id-28' id='type-id-641'/> + </array-type-def> + <type-decl name='short int' size-in-bits='16' id='type-id-71'/> + <array-type-def dimensions='1' type-id='type-id-410' size-in-bits='89600' id='type-id-642'> + <subrange length='200' type-id='type-id-28' id='type-id-643'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-644' size-in-bits='96' id='type-id-645'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-646' size-in-bits='786432' id='type-id-647'> + <subrange length='4096' type-id='type-id-28' id='type-id-648'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='80' id='type-id-649'> + <subrange length='10' type-id='type-id-28' id='type-id-641'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='88' id='type-id-650'> + <subrange length='11' type-id='type-id-28' id='type-id-651'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='96' id='type-id-652'> + <subrange length='12' type-id='type-id-28' id='type-id-653'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='104' id='type-id-654'> + <subrange length='13' type-id='type-id-28' id='type-id-655'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='112' id='type-id-656'> + <subrange length='14' type-id='type-id-28' id='type-id-657'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='120' id='type-id-658'> + <subrange length='15' type-id='type-id-28' id='type-id-659'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='128' id='type-id-660'> + <subrange length='16' type-id='type-id-28' id='type-id-57'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='136' id='type-id-661'> + <subrange length='17' type-id='type-id-28' id='type-id-662'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='144' id='type-id-663'> + <subrange length='18' type-id='type-id-28' id='type-id-664'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='152' id='type-id-665'> + <subrange length='19' type-id='type-id-28' id='type-id-666'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='8' id='type-id-667'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='160' id='type-id-668'> + <subrange length='20' type-id='type-id-28' id='type-id-588'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='168' id='type-id-669'> + <subrange length='21' type-id='type-id-28' id='type-id-670'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='184' id='type-id-671'> + <subrange length='23' type-id='type-id-28' id='type-id-672'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='192' id='type-id-673'> + <subrange length='24' type-id='type-id-28' id='type-id-674'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='200' id='type-id-675'> + <subrange length='25' type-id='type-id-28' id='type-id-676'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='208' id='type-id-677'> + <subrange length='26' type-id='type-id-28' id='type-id-678'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='224' id='type-id-679'> + <subrange length='28' type-id='type-id-28' id='type-id-635'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='16' id='type-id-680'> + <subrange length='2' type-id='type-id-28' id='type-id-681'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='248' id='type-id-682'> + <subrange length='31' type-id='type-id-28' id='type-id-683'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='288' id='type-id-684'> + <subrange length='36' type-id='type-id-28' id='type-id-685'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='24' id='type-id-686'> + <subrange length='3' type-id='type-id-28' id='type-id-630'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='32' id='type-id-687'> + <subrange length='4' type-id='type-id-28' id='type-id-223'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='40' id='type-id-688'> + <subrange length='5' type-id='type-id-28' id='type-id-689'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='48' id='type-id-690'> + <subrange length='6' type-id='type-id-28' id='type-id-401'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='56' id='type-id-691'> + <subrange length='7' type-id='type-id-28' id='type-id-692'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='64' id='type-id-693'> + <subrange length='8' type-id='type-id-28' id='type-id-572'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-325' size-in-bits='72' id='type-id-694'> + <subrange length='9' type-id='type-id-28' id='type-id-695'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-95' size-in-bits='64' id='type-id-696'> + <subrange length='2' type-id='type-id-28' id='type-id-681'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-28' size-in-bits='1024' id='type-id-697'> + <subrange length='16' type-id='type-id-28' id='type-id-57'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-698' size-in-bits='8320' id='type-id-699'> + <subrange length='65' type-id='type-id-28' id='type-id-64'/> + </array-type-def> + <class-decl name='PyBytesObject' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-700' visibility='default' filepath='./Include/cpython/bytesobject.h' line='5' column='1' id='type-id-701'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-321' visibility='default' filepath='./Include/cpython/bytesobject.h' line='6' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ob_shash' type-id='type-id-305' visibility='default' filepath='./Include/cpython/bytesobject.h' line='7' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='ob_sval' type-id='type-id-702' visibility='default' filepath='./Include/cpython/bytesobject.h' line='8' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyBytesObject' type-id='type-id-701' filepath='./Include/cpython/bytesobject.h' line='15' column='1' id='type-id-700'/> + <class-decl name='_Py_Monitors' size-in-bits='112' is-struct='yes' visibility='default' filepath='./Include/cpython/code.h' line='18' column='1' id='type-id-703'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tools' type-id='type-id-656' visibility='default' filepath='./Include/cpython/code.h' line='19' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_Monitors' type-id='type-id-703' filepath='./Include/cpython/code.h' line='20' column='1' id='type-id-704'/> + <union-decl name='_Py_CODEUNIT' size-in-bits='16' naming-typedef-id='type-id-705' visibility='default' filepath='./Include/cpython/code.h' line='31' column='1' id='type-id-706'> + <data-member access='public'> + <var-decl name='cache' type-id='type-id-707' visibility='default' filepath='./Include/cpython/code.h' line='32' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='op' type-id='type-id-708' visibility='default' filepath='./Include/cpython/code.h' line='36' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__744' size-in-bits='16' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/cpython/code.h' line='33' column='1' id='type-id-708'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='code' type-id='type-id-325' visibility='default' filepath='./Include/cpython/code.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8'> + <var-decl name='arg' type-id='type-id-325' visibility='default' filepath='./Include/cpython/code.h' line='35' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_CODEUNIT' type-id='type-id-706' filepath='./Include/cpython/code.h' line='37' column='1' id='type-id-705'/> + <class-decl name='_PyCoCached' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-709' visibility='default' filepath='./Include/cpython/code.h' line='64' column='1' id='type-id-710'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_co_code' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_co_varnames' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='_co_cellvars' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='_co_freevars' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='68' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCoCached' type-id='type-id-710' filepath='./Include/cpython/code.h' line='69' column='1' id='type-id-709'/> + <class-decl name='_PyCoLineInstrumentationData' size-in-bits='16' is-struct='yes' naming-typedef-id='type-id-711' visibility='default' filepath='./Include/cpython/code.h' line='74' column='1' id='type-id-712'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='original_opcode' type-id='type-id-325' visibility='default' filepath='./Include/cpython/code.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8'> + <var-decl name='line_delta' type-id='type-id-370' visibility='default' filepath='./Include/cpython/code.h' line='76' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCoLineInstrumentationData' type-id='type-id-712' filepath='./Include/cpython/code.h' line='77' column='1' id='type-id-711'/> + <class-decl name='_PyCoMonitoringData' size-in-bits='576' is-struct='yes' naming-typedef-id='type-id-713' visibility='default' filepath='./Include/cpython/code.h' line='82' column='1' id='type-id-714'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='local_monitors' type-id='type-id-704' visibility='default' filepath='./Include/cpython/code.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='112'> + <var-decl name='active_monitors' type-id='type-id-704' visibility='default' filepath='./Include/cpython/code.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='tools' type-id='type-id-715' visibility='default' filepath='./Include/cpython/code.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='lines' type-id='type-id-716' visibility='default' filepath='./Include/cpython/code.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='line_tools' type-id='type-id-715' visibility='default' filepath='./Include/cpython/code.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='per_instruction_opcodes' type-id='type-id-715' visibility='default' filepath='./Include/cpython/code.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='per_instruction_tools' type-id='type-id-715' visibility='default' filepath='./Include/cpython/code.h' line='97' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCoMonitoringData' type-id='type-id-714' filepath='./Include/cpython/code.h' line='98' column='1' id='type-id-713'/> + <class-decl name='PyCodeObject' size-in-bits='1600' is-struct='yes' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1' id='type-id-717'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-321' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='co_consts' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='co_names' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='co_exceptiontable' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='co_flags' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='416'> + <var-decl name='co_argcount' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='co_posonlyargcount' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='480'> + <var-decl name='co_kwonlyargcount' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='co_stacksize' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='544'> + <var-decl name='co_firstlineno' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='co_nlocalsplus' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='608'> + <var-decl name='co_framesize' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='co_nlocals' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='672'> + <var-decl name='co_ncellvars' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='co_nfreevars' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='736'> + <var-decl name='co_version' type-id='type-id-352' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='co_localsplusnames' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='co_localspluskinds' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='co_filename' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='co_name' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='co_qualname' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='co_linetable' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='co_weakreflist' type-id='type-id-2' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='_co_cached' type-id='type-id-718' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='_co_instrumentation_version' type-id='type-id-117' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='_co_monitoring' type-id='type-id-719' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='_co_firsttraceable' type-id='type-id-8' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='co_extra' type-id='type-id-22' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='co_code_adaptive' type-id='type-id-702' visibility='default' filepath='./Include/cpython/code.h' line='168' column='1'/> + </data-member> + </class-decl> + <enum-decl name='PyCodeEvent' naming-typedef-id='type-id-720' filepath='./Include/cpython/code.h' line='272' column='1' id='type-id-721'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PY_CODE_EVENT_CREATE' value='0'/> + <enumerator name='PY_CODE_EVENT_DESTROY' value='1'/> + </enum-decl> + <typedef-decl name='PyCodeEvent' type-id='type-id-721' filepath='./Include/cpython/code.h' line='276' column='1' id='type-id-720'/> + <typedef-decl name='PyCode_WatchCallback' type-id='type-id-722' filepath='./Include/cpython/code.h' line='288' column='1' id='type-id-329'/> + <typedef-decl name='PyContext' type-id='type-id-723' filepath='./Include/cpython/context.h' line='9' column='1' id='type-id-724'/> + <typedef-decl name='wrapperfunc' type-id='type-id-725' filepath='./Include/cpython/descrobject.h' line='5' column='1' id='type-id-726'/> + <class-decl name='wrapperbase' size-in-bits='448' is-struct='yes' visibility='default' filepath='./Include/cpython/descrobject.h' line='11' column='1' id='type-id-333'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/cpython/descrobject.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='offset' type-id='type-id-8' visibility='default' filepath='./Include/cpython/descrobject.h' line='13' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='function' type-id='type-id-22' visibility='default' filepath='./Include/cpython/descrobject.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='wrapper' type-id='type-id-726' visibility='default' filepath='./Include/cpython/descrobject.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='doc' type-id='type-id-12' visibility='default' filepath='./Include/cpython/descrobject.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='flags' type-id='type-id-8' visibility='default' filepath='./Include/cpython/descrobject.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='name_strobj' type-id='type-id-2' visibility='default' filepath='./Include/cpython/descrobject.h' line='18' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyDictKeysObject' type-id='type-id-350' filepath='./Include/cpython/dictobject.h' line='5' column='1' id='type-id-348'/> + <typedef-decl name='PyDictValues' type-id='type-id-351' filepath='./Include/cpython/dictobject.h' line='6' column='1' id='type-id-349'/> + <class-decl name='PyDictObject' size-in-bits='384' is-struct='yes' naming-typedef-id='type-id-343' visibility='default' filepath='./Include/cpython/dictobject.h' line='11' column='1' id='type-id-344'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/dictobject.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ma_used' type-id='type-id-14' visibility='default' filepath='./Include/cpython/dictobject.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ma_version_tag' type-id='type-id-117' visibility='default' filepath='./Include/cpython/dictobject.h' line='20' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='ma_keys' type-id='type-id-346' visibility='default' filepath='./Include/cpython/dictobject.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='ma_values' type-id='type-id-347' visibility='default' filepath='./Include/cpython/dictobject.h' line='32' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyDictObject' type-id='type-id-344' filepath='./Include/cpython/dictobject.h' line='33' column='1' id='type-id-343'/> + <enum-decl name='PyDict_WatchEvent' naming-typedef-id='type-id-727' filepath='./Include/cpython/dictobject.h' line='101' column='1' id='type-id-728'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PyDict_EVENT_ADDED' value='0'/> + <enumerator name='PyDict_EVENT_MODIFIED' value='1'/> + <enumerator name='PyDict_EVENT_DELETED' value='2'/> + <enumerator name='PyDict_EVENT_CLONED' value='3'/> + <enumerator name='PyDict_EVENT_CLEARED' value='4'/> + <enumerator name='PyDict_EVENT_DEALLOCATED' value='5'/> + </enum-decl> + <typedef-decl name='PyDict_WatchEvent' type-id='type-id-728' filepath='./Include/cpython/dictobject.h' line='105' column='1' id='type-id-727'/> + <typedef-decl name='PyDict_WatchCallback' type-id='type-id-729' filepath='./Include/cpython/dictobject.h' line='110' column='1' id='type-id-342'/> + <typedef-decl name='Py_OpenCodeHookFunction' type-id='type-id-730' filepath='./Include/cpython/fileobject.h' line='13' column='1' id='type-id-355'/> + <class-decl name='PyFloatObject' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-731' visibility='default' filepath='./Include/cpython/floatobject.h' line='5' column='1' id='type-id-732'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/floatobject.h' line='6' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ob_fval' type-id='type-id-251' visibility='default' filepath='./Include/cpython/floatobject.h' line='7' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyFloatObject' type-id='type-id-732' filepath='./Include/cpython/floatobject.h' line='8' column='1' id='type-id-731'/> + <class-decl name='PyFunctionObject' size-in-bits='1152' is-struct='yes' naming-typedef-id='type-id-733' visibility='default' filepath='./Include/cpython/funcobject.h' line='36' column='1' id='type-id-734'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/funcobject.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='func_globals' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='func_builtins' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='func_name' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='func_qualname' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='func_code' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='func_defaults' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='func_kwdefaults' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='func_closure' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='func_doc' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='func_dict' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='func_weakreflist' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='func_module' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='func_annotations' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='func_typeparams' type-id='type-id-2' visibility='default' filepath='./Include/cpython/funcobject.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='vectorcall' type-id='type-id-311' visibility='default' filepath='./Include/cpython/funcobject.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='func_version' type-id='type-id-352' visibility='default' filepath='./Include/cpython/funcobject.h' line='54' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyFunctionObject' type-id='type-id-734' filepath='./Include/cpython/funcobject.h' line='61' column='1' id='type-id-733'/> + <enum-decl name='PyFunction_WatchEvent' naming-typedef-id='type-id-735' filepath='./Include/cpython/funcobject.h' line='142' column='1' id='type-id-736'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PyFunction_EVENT_CREATE' value='0'/> + <enumerator name='PyFunction_EVENT_DESTROY' value='1'/> + <enumerator name='PyFunction_EVENT_MODIFY_CODE' value='2'/> + <enumerator name='PyFunction_EVENT_MODIFY_DEFAULTS' value='3'/> + <enumerator name='PyFunction_EVENT_MODIFY_KWDEFAULTS' value='4'/> + </enum-decl> + <typedef-decl name='PyFunction_WatchEvent' type-id='type-id-736' filepath='./Include/cpython/funcobject.h' line='146' column='1' id='type-id-735'/> + <typedef-decl name='PyFunction_WatchCallback' type-id='type-id-737' filepath='./Include/cpython/funcobject.h' line='163' column='1' id='type-id-366'/> + <class-decl name='_inittab' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/cpython/import.h' line='24' column='1' id='type-id-738'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/cpython/import.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='initfunc' type-id='type-id-390' visibility='default' filepath='./Include/cpython/import.h' line='26' column='1'/> + </data-member> + </class-decl> + <class-decl name='PyWideStringList' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-739' visibility='default' filepath='./Include/cpython/initconfig.h' line='32' column='1' id='type-id-740'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='length' type-id='type-id-14' visibility='default' filepath='./Include/cpython/initconfig.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='items' type-id='type-id-235' visibility='default' filepath='./Include/cpython/initconfig.h' line='36' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyWideStringList' type-id='type-id-740' filepath='./Include/cpython/initconfig.h' line='37' column='1' id='type-id-739'/> + <class-decl name='PyPreConfig' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/cpython/initconfig.h' line='48' column='1' id='type-id-741'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_config_init' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='parse_argv' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='isolated' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='use_environment' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='configure_locale' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='coerce_c_locale' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='coerce_c_locale_warn' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='utf8_mode' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='115' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='dev_mode' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='allocator' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='125' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyPreConfig' type-id='type-id-741' filepath='./Include/cpython/initconfig.h' line='126' column='1' id='type-id-742'/> + <class-decl name='PyConfig' size-in-bits='3456' is-struct='yes' visibility='default' filepath='./Include/cpython/initconfig.h' line='135' column='1' id='type-id-743'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_config_init' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='isolated' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='use_environment' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='139' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='dev_mode' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='140' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='install_signal_handlers' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='141' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='use_hash_seed' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='142' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='hash_seed' type-id='type-id-28' visibility='default' filepath='./Include/cpython/initconfig.h' line='143' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='faulthandler' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='144' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='tracemalloc' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='perf_profiling' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='146' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='import_time' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='code_debug_ranges' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='416'> + <var-decl name='show_ref_count' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='149' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='dump_refs' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='dump_refs_file' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='151' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='malloc_stats' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='152' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='filesystem_encoding' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='filesystem_errors' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='pycache_prefix' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='155' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='parse_argv' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='orig_argv' type-id='type-id-739' visibility='default' filepath='./Include/cpython/initconfig.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='argv' type-id='type-id-739' visibility='default' filepath='./Include/cpython/initconfig.h' line='158' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='xoptions' type-id='type-id-739' visibility='default' filepath='./Include/cpython/initconfig.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='warnoptions' type-id='type-id-739' visibility='default' filepath='./Include/cpython/initconfig.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='site_import' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1440'> + <var-decl name='bytes_warning' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='warn_default_encoding' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='163' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1504'> + <var-decl name='inspect' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='interactive' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1568'> + <var-decl name='optimization_level' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='parser_debug' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='167' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1632'> + <var-decl name='write_bytecode' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1664'> + <var-decl name='verbose' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1696'> + <var-decl name='quiet' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='170' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='user_site_directory' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1760'> + <var-decl name='configure_c_stdio' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='172' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='buffered_stdio' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='173' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1856'> + <var-decl name='stdio_encoding' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1920'> + <var-decl name='stdio_errors' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='175' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1984'> + <var-decl name='check_hash_pycs_mode' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='179' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2048'> + <var-decl name='use_frozen_modules' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='180' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2080'> + <var-decl name='safe_path' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='int_max_str_digits' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='182' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2144'> + <var-decl name='pathconfig_warnings' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='185' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2176'> + <var-decl name='program_name' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='186' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2240'> + <var-decl name='pythonpath_env' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='187' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2304'> + <var-decl name='home' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='188' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2368'> + <var-decl name='platlibdir' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='189' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2432'> + <var-decl name='module_search_paths_set' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='192' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2496'> + <var-decl name='module_search_paths' type-id='type-id-739' visibility='default' filepath='./Include/cpython/initconfig.h' line='193' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2624'> + <var-decl name='stdlib_dir' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='194' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2688'> + <var-decl name='executable' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='195' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2752'> + <var-decl name='base_executable' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='196' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2816'> + <var-decl name='prefix' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='197' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2880'> + <var-decl name='base_prefix' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='198' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2944'> + <var-decl name='exec_prefix' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='199' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3008'> + <var-decl name='base_exec_prefix' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='200' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3072'> + <var-decl name='skip_source_first_line' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='203' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3136'> + <var-decl name='run_command' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='204' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3200'> + <var-decl name='run_module' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='205' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3264'> + <var-decl name='run_filename' type-id='type-id-52' visibility='default' filepath='./Include/cpython/initconfig.h' line='206' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3328'> + <var-decl name='_install_importlib' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='212' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3360'> + <var-decl name='_init_main' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='215' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3392'> + <var-decl name='_is_python_build' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='218' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyConfig' type-id='type-id-743' filepath='./Include/cpython/initconfig.h' line='219' column='1' id='type-id-258'/> + <class-decl name='PyListObject' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-744' visibility='default' filepath='./Include/cpython/listobject.h' line='5' column='1' id='type-id-745'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-321' visibility='default' filepath='./Include/cpython/listobject.h' line='6' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ob_item' type-id='type-id-233' visibility='default' filepath='./Include/cpython/listobject.h' line='8' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='allocated' type-id='type-id-14' visibility='default' filepath='./Include/cpython/listobject.h' line='21' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyListObject' type-id='type-id-745' filepath='./Include/cpython/listobject.h' line='22' column='1' id='type-id-744'/> + <typedef-decl name='digit' type-id='type-id-352' filepath='./Include/cpython/longintrepr.h' line='43' column='1' id='type-id-384'/> + <class-decl name='_PyLongValue' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/cpython/longintrepr.h' line='82' column='1' id='type-id-746'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='lv_tag' type-id='type-id-747' visibility='default' filepath='./Include/cpython/longintrepr.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ob_digit' type-id='type-id-623' visibility='default' filepath='./Include/cpython/longintrepr.h' line='84' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyLongValue' type-id='type-id-746' filepath='./Include/cpython/longintrepr.h' line='85' column='1' id='type-id-748'/> + <class-decl name='_longobject' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/cpython/longintrepr.h' line='87' column='1' id='type-id-749'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/longintrepr.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='long_value' type-id='type-id-748' visibility='default' filepath='./Include/cpython/longintrepr.h' line='89' column='1'/> + </data-member> + </class-decl> + <class-decl name='_PyArg_Parser' size-in-bits='576' is-struct='yes' visibility='default' filepath='./Include/cpython/modsupport.h' line='53' column='1' id='type-id-750'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='initialized' type-id='type-id-8' visibility='default' filepath='./Include/cpython/modsupport.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='format' type-id='type-id-12' visibility='default' filepath='./Include/cpython/modsupport.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='keywords' type-id='type-id-751' visibility='default' filepath='./Include/cpython/modsupport.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='fname' type-id='type-id-12' visibility='default' filepath='./Include/cpython/modsupport.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='custom_msg' type-id='type-id-12' visibility='default' filepath='./Include/cpython/modsupport.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='pos' type-id='type-id-8' visibility='default' filepath='./Include/cpython/modsupport.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='min' type-id='type-id-8' visibility='default' filepath='./Include/cpython/modsupport.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='max' type-id='type-id-8' visibility='default' filepath='./Include/cpython/modsupport.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='kwtuple' type-id='type-id-2' visibility='default' filepath='./Include/cpython/modsupport.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='next' type-id='type-id-262' visibility='default' filepath='./Include/cpython/modsupport.h' line='63' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyType_WatchCallback' type-id='type-id-752' filepath='./Include/cpython/object.h' line='563' column='1' id='type-id-435'/> + <class-decl name='PyObjectArenaAllocator' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-420' visibility='default' filepath='./Include/cpython/objimpl.h' line='59' column='1' id='type-id-753'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ctx' type-id='type-id-22' visibility='default' filepath='./Include/cpython/objimpl.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='alloc' type-id='type-id-754' visibility='default' filepath='./Include/cpython/objimpl.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='free' type-id='type-id-755' visibility='default' filepath='./Include/cpython/objimpl.h' line='67' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyObjectArenaAllocator' type-id='type-id-753' filepath='./Include/cpython/objimpl.h' line='68' column='1' id='type-id-420'/> + <class-decl name='PyBaseExceptionObject' size-in-bits='576' is-struct='yes' naming-typedef-id='type-id-756' visibility='default' filepath='./Include/cpython/pyerrors.h' line='13' column='1' id='type-id-757'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='dict' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='args' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='notes' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='traceback' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='context' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='cause' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='suppress_context' type-id='type-id-48' visibility='default' filepath='./Include/cpython/pyerrors.h' line='14' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyBaseExceptionObject' type-id='type-id-757' filepath='./Include/cpython/pyerrors.h' line='15' column='1' id='type-id-756'/> + <typedef-decl name='atexit_datacallbackfunc' type-id='type-id-758' filepath='./Include/cpython/pylifecycle.h' line='70' column='1' id='type-id-21'/> + <class-decl name='PyMemAllocatorEx' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-417' visibility='default' filepath='./Include/cpython/pymem.h' line='47' column='1' id='type-id-759'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ctx' type-id='type-id-22' visibility='default' filepath='./Include/cpython/pymem.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='malloc' type-id='type-id-754' visibility='default' filepath='./Include/cpython/pymem.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='calloc' type-id='type-id-760' visibility='default' filepath='./Include/cpython/pymem.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='realloc' type-id='type-id-761' visibility='default' filepath='./Include/cpython/pymem.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='free' type-id='type-id-762' visibility='default' filepath='./Include/cpython/pymem.h' line='61' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyMemAllocatorEx' type-id='type-id-759' filepath='./Include/cpython/pymem.h' line='62' column='1' id='type-id-417'/> + <typedef-decl name='Py_tracefunc' type-id='type-id-763' filepath='./Include/cpython/pystate.h' line='49' column='1' id='type-id-764'/> + <class-decl name='_PyCFrame' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='67' column='1' id='type-id-765'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='current_frame' type-id='type-id-375' visibility='default' filepath='./Include/cpython/pystate.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='previous' type-id='type-id-766' visibility='default' filepath='./Include/cpython/pystate.h' line='80' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCFrame' type-id='type-id-765' filepath='./Include/cpython/pystate.h' line='81' column='1' id='type-id-767'/> + <class-decl name='_err_stackitem' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='83' column='1' id='type-id-768'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='exc_value' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='previous_item' type-id='type-id-769' visibility='default' filepath='./Include/cpython/pystate.h' line='99' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyErr_StackItem' type-id='type-id-768' filepath='./Include/cpython/pystate.h' line='101' column='1' id='type-id-369'/> + <class-decl name='_stack_chunk' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='103' column='1' id='type-id-770'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='previous' type-id='type-id-771' visibility='default' filepath='./Include/cpython/pystate.h' line='104' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='size' type-id='type-id-19' visibility='default' filepath='./Include/cpython/pystate.h' line='105' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='top' type-id='type-id-19' visibility='default' filepath='./Include/cpython/pystate.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='data' type-id='type-id-353' visibility='default' filepath='./Include/cpython/pystate.h' line='107' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyStackChunk' type-id='type-id-770' filepath='./Include/cpython/pystate.h' line='108' column='1' id='type-id-772'/> + <class-decl name='_py_trashcan' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='110' column='1' id='type-id-773'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='delete_nesting' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='delete_later' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='112' column='1'/> + </data-member> + </class-decl> + <class-decl name='_ts' size-in-bits='2304' is-struct='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='115' column='1' id='type-id-774'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='prev' type-id='type-id-177' visibility='default' filepath='./Include/cpython/pystate.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='next' type-id='type-id-177' visibility='default' filepath='./Include/cpython/pystate.h' line='119' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='interp' type-id='type-id-20' visibility='default' filepath='./Include/cpython/pystate.h' line='120' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='_status' type-id='type-id-775' visibility='default' filepath='./Include/cpython/pystate.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='py_recursion_remaining' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='py_recursion_limit' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='c_recursion_remaining' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='recursion_headroom' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='151' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='tracing' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='what_event' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='cframe' type-id='type-id-766' visibility='default' filepath='./Include/cpython/pystate.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='c_profilefunc' type-id='type-id-764' visibility='default' filepath='./Include/cpython/pystate.h' line='163' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='c_tracefunc' type-id='type-id-764' visibility='default' filepath='./Include/cpython/pystate.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='c_profileobj' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='c_traceobj' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='current_exception' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='exc_info' type-id='type-id-376' visibility='default' filepath='./Include/cpython/pystate.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='dict' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='176' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='gilstate_counter' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='178' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='async_exc' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='180' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='thread_id' type-id='type-id-28' visibility='default' filepath='./Include/cpython/pystate.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='native_thread_id' type-id='type-id-28' visibility='default' filepath='./Include/cpython/pystate.h' line='187' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='trash' type-id='type-id-773' visibility='default' filepath='./Include/cpython/pystate.h' line='189' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='on_delete' type-id='type-id-758' visibility='default' filepath='./Include/cpython/pystate.h' line='214' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='on_delete_data' type-id='type-id-22' visibility='default' filepath='./Include/cpython/pystate.h' line='215' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='coroutine_origin_tracking_depth' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pystate.h' line='217' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='async_gen_firstiter' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='219' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='async_gen_finalizer' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='220' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1664'> + <var-decl name='context' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='222' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='context_ver' type-id='type-id-117' visibility='default' filepath='./Include/cpython/pystate.h' line='223' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='id' type-id='type-id-117' visibility='default' filepath='./Include/cpython/pystate.h' line='226' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1856'> + <var-decl name='datastack_chunk' type-id='type-id-776' visibility='default' filepath='./Include/cpython/pystate.h' line='228' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1920'> + <var-decl name='datastack_top' type-id='type-id-233' visibility='default' filepath='./Include/cpython/pystate.h' line='229' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1984'> + <var-decl name='datastack_limit' type-id='type-id-233' visibility='default' filepath='./Include/cpython/pystate.h' line='230' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2048'> + <var-decl name='exc_state' type-id='type-id-369' visibility='default' filepath='./Include/cpython/pystate.h' line='245' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2176'> + <var-decl name='root_cframe' type-id='type-id-767' visibility='default' filepath='./Include/cpython/pystate.h' line='248' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__746' size-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='122' column='1' id='type-id-775'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='initialized' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='127' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1'> + <var-decl name='bound' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2'> + <var-decl name='unbound' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='132' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3'> + <var-decl name='bound_gilstate' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='134' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4'> + <var-decl name='active' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5'> + <var-decl name='finalizing' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='139' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6'> + <var-decl name='cleared' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='140' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7'> + <var-decl name='finalized' type-id='type-id-95' visibility='default' filepath='./Include/cpython/pystate.h' line='141' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyFrameEvalFunction' type-id='type-id-777' filepath='./Include/cpython/pystate.h' line='322' column='1' id='type-id-778'/> + <typedef-decl name='_PyCrossInterpreterData' type-id='type-id-779' filepath='./Include/cpython/pystate.h' line='375' column='1' id='type-id-780'/> + <typedef-decl name='xid_newobjectfunc' type-id='type-id-781' filepath='./Include/cpython/pystate.h' line='377' column='1' id='type-id-782'/> + <typedef-decl name='xid_freefunc' type-id='type-id-758' filepath='./Include/cpython/pystate.h' line='378' column='1' id='type-id-783'/> + <class-decl name='_xid' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/cpython/pystate.h' line='380' column='1' id='type-id-779'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='data' type-id='type-id-22' visibility='default' filepath='./Include/cpython/pystate.h' line='384' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='obj' type-id='type-id-2' visibility='default' filepath='./Include/cpython/pystate.h' line='391' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='interp' type-id='type-id-377' visibility='default' filepath='./Include/cpython/pystate.h' line='401' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='new_object' type-id='type-id-782' visibility='default' filepath='./Include/cpython/pystate.h' line='406' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='free' type-id='type-id-783' visibility='default' filepath='./Include/cpython/pystate.h' line='416' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='crossinterpdatafunc' type-id='type-id-784' filepath='./Include/cpython/pystate.h' line='438' column='1' id='type-id-785'/> + <class-decl name='_Py_tss_t' size-in-bits='64' is-struct='yes' visibility='default' filepath='./Include/cpython/pythread.h' line='34' column='1' id='type-id-786'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_is_initialized' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pythread.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='_key' type-id='type-id-787' visibility='default' filepath='./Include/cpython/pythread.h' line='36' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyTime_t' type-id='type-id-377' filepath='./Include/cpython/pytime.h' line='63' column='1' id='type-id-788'/> + <typedef-decl name='Py_AuditHookFunction' type-id='type-id-789' filepath='./Include/cpython/sysmodule.h' line='10' column='1' id='type-id-234'/> + <class-decl name='PyTupleObject' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-790' visibility='default' filepath='./Include/cpython/tupleobject.h' line='5' column='1' id='type-id-791'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-321' visibility='default' filepath='./Include/cpython/tupleobject.h' line='6' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ob_item' type-id='type-id-353' visibility='default' filepath='./Include/cpython/tupleobject.h' line='10' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyTupleObject' type-id='type-id-791' filepath='./Include/cpython/tupleobject.h' line='11' column='1' id='type-id-790'/> + <class-decl name='PyASCIIObject' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-792' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='52' column='1' id='type-id-793'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='length' type-id='type-id-14' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='hash' type-id='type-id-305' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='state' type-id='type-id-794' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='146' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__26' size-in-bits='32' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='100' column='1' id='type-id-794'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='interned' type-id='type-id-95' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2'> + <var-decl name='kind' type-id='type-id-95' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='133' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5'> + <var-decl name='compact' type-id='type-id-95' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6'> + <var-decl name='ascii' type-id='type-id-95' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='142' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyASCIIObject' type-id='type-id-793' filepath='./Include/cpython/unicodeobject.h' line='147' column='1' id='type-id-792'/> + <class-decl name='PyCompactUnicodeObject' size-in-bits='448' is-struct='yes' naming-typedef-id='type-id-795' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='152' column='1' id='type-id-796'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_base' type-id='type-id-792' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='utf8_length' type-id='type-id-14' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='utf8' type-id='type-id-15' visibility='default' filepath='./Include/cpython/unicodeobject.h' line='156' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyCompactUnicodeObject' type-id='type-id-796' filepath='./Include/cpython/unicodeobject.h' line='157' column='1' id='type-id-795'/> + <class-decl name='ast_state' size-in-bits='15616' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='13' column='1' id='type-id-797'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='recursion_depth' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='recursion_limit' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='AST_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='Add_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='18' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='Add_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='19' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='And_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='20' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='And_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='AnnAssign_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='Assert_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='Assign_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='AsyncFor_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='AsyncFunctionDef_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='26' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='AsyncWith_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='Attribute_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='AugAssign_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='Await_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='BinOp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='BitAnd_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='BitAnd_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='BitOr_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='BitOr_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='BitXor_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='BitXor_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='BoolOp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='Break_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='Call_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1664'> + <var-decl name='ClassDef_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='Compare_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='Constant_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1856'> + <var-decl name='Continue_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1920'> + <var-decl name='Del_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1984'> + <var-decl name='Del_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2048'> + <var-decl name='Delete_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='DictComp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2176'> + <var-decl name='Dict_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2240'> + <var-decl name='Div_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2304'> + <var-decl name='Div_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2368'> + <var-decl name='Eq_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2432'> + <var-decl name='Eq_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2496'> + <var-decl name='ExceptHandler_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2560'> + <var-decl name='Expr_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2624'> + <var-decl name='Expression_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2688'> + <var-decl name='FloorDiv_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2752'> + <var-decl name='FloorDiv_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2816'> + <var-decl name='For_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2880'> + <var-decl name='FormattedValue_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2944'> + <var-decl name='FunctionDef_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3008'> + <var-decl name='FunctionType_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3072'> + <var-decl name='GeneratorExp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3136'> + <var-decl name='Global_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3200'> + <var-decl name='GtE_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3264'> + <var-decl name='GtE_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3328'> + <var-decl name='Gt_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3392'> + <var-decl name='Gt_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3456'> + <var-decl name='IfExp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3520'> + <var-decl name='If_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3584'> + <var-decl name='ImportFrom_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3648'> + <var-decl name='Import_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3712'> + <var-decl name='In_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3776'> + <var-decl name='In_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3840'> + <var-decl name='Interactive_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3904'> + <var-decl name='Invert_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3968'> + <var-decl name='Invert_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4032'> + <var-decl name='IsNot_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4096'> + <var-decl name='IsNot_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4160'> + <var-decl name='Is_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4224'> + <var-decl name='Is_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4288'> + <var-decl name='JoinedStr_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4352'> + <var-decl name='LShift_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4416'> + <var-decl name='LShift_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4480'> + <var-decl name='Lambda_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4544'> + <var-decl name='ListComp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4608'> + <var-decl name='List_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4672'> + <var-decl name='Load_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4736'> + <var-decl name='Load_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4800'> + <var-decl name='LtE_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4864'> + <var-decl name='LtE_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4928'> + <var-decl name='Lt_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4992'> + <var-decl name='Lt_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5056'> + <var-decl name='MatMult_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='94' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5120'> + <var-decl name='MatMult_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5184'> + <var-decl name='MatchAs_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5248'> + <var-decl name='MatchClass_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5312'> + <var-decl name='MatchMapping_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5376'> + <var-decl name='MatchOr_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5440'> + <var-decl name='MatchSequence_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5504'> + <var-decl name='MatchSingleton_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5568'> + <var-decl name='MatchStar_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5632'> + <var-decl name='MatchValue_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='103' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5696'> + <var-decl name='Match_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='104' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5760'> + <var-decl name='Mod_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='105' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5824'> + <var-decl name='Mod_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5888'> + <var-decl name='Module_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5952'> + <var-decl name='Mult_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='108' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6016'> + <var-decl name='Mult_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='109' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6080'> + <var-decl name='Name_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6144'> + <var-decl name='NamedExpr_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6208'> + <var-decl name='Nonlocal_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='112' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6272'> + <var-decl name='NotEq_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='113' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6336'> + <var-decl name='NotEq_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='114' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6400'> + <var-decl name='NotIn_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='115' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6464'> + <var-decl name='NotIn_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6528'> + <var-decl name='Not_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='117' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6592'> + <var-decl name='Not_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6656'> + <var-decl name='Or_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='119' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6720'> + <var-decl name='Or_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='120' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6784'> + <var-decl name='ParamSpec_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6848'> + <var-decl name='Pass_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='122' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6912'> + <var-decl name='Pow_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='123' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6976'> + <var-decl name='Pow_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='124' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7040'> + <var-decl name='RShift_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='125' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7104'> + <var-decl name='RShift_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='126' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7168'> + <var-decl name='Raise_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='127' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7232'> + <var-decl name='Return_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='128' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7296'> + <var-decl name='SetComp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='129' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7360'> + <var-decl name='Set_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7424'> + <var-decl name='Slice_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='131' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7488'> + <var-decl name='Starred_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='132' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7552'> + <var-decl name='Store_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='133' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7616'> + <var-decl name='Store_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='134' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7680'> + <var-decl name='Sub_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='135' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7744'> + <var-decl name='Sub_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7808'> + <var-decl name='Subscript_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='137' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7872'> + <var-decl name='TryStar_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7936'> + <var-decl name='Try_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='139' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8000'> + <var-decl name='Tuple_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='140' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8064'> + <var-decl name='TypeAlias_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='141' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8128'> + <var-decl name='TypeIgnore_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='142' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8192'> + <var-decl name='TypeVarTuple_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='143' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8256'> + <var-decl name='TypeVar_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='144' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8320'> + <var-decl name='UAdd_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8384'> + <var-decl name='UAdd_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='146' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8448'> + <var-decl name='USub_singleton' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8512'> + <var-decl name='USub_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8576'> + <var-decl name='UnaryOp_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='149' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8640'> + <var-decl name='While_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8704'> + <var-decl name='With_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='151' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8768'> + <var-decl name='YieldFrom_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='152' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8832'> + <var-decl name='Yield_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8896'> + <var-decl name='__dict__' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8960'> + <var-decl name='__doc__' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='155' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9024'> + <var-decl name='__match_args__' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9088'> + <var-decl name='__module__' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9152'> + <var-decl name='_attributes' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='158' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9216'> + <var-decl name='_fields' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9280'> + <var-decl name='alias_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9344'> + <var-decl name='annotation' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9408'> + <var-decl name='arg' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9472'> + <var-decl name='arg_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='163' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9536'> + <var-decl name='args' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9600'> + <var-decl name='argtypes' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9664'> + <var-decl name='arguments_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9728'> + <var-decl name='asname' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='167' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9792'> + <var-decl name='ast' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9856'> + <var-decl name='attr' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9920'> + <var-decl name='bases' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='170' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9984'> + <var-decl name='body' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10048'> + <var-decl name='boolop_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='172' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10112'> + <var-decl name='bound' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='173' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10176'> + <var-decl name='cases' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10240'> + <var-decl name='cause' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='175' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10304'> + <var-decl name='cls' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='176' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10368'> + <var-decl name='cmpop_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='177' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10432'> + <var-decl name='col_offset' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='178' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10496'> + <var-decl name='comparators' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='179' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10560'> + <var-decl name='comprehension_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='180' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10624'> + <var-decl name='context_expr' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10688'> + <var-decl name='conversion' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='182' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10752'> + <var-decl name='ctx' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='183' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10816'> + <var-decl name='decorator_list' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='184' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10880'> + <var-decl name='defaults' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='185' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10944'> + <var-decl name='elt' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='186' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11008'> + <var-decl name='elts' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='187' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11072'> + <var-decl name='end_col_offset' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='188' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11136'> + <var-decl name='end_lineno' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='189' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11200'> + <var-decl name='exc' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='190' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11264'> + <var-decl name='excepthandler_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='191' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11328'> + <var-decl name='expr_context_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='192' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11392'> + <var-decl name='expr_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='193' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11456'> + <var-decl name='finalbody' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='194' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11520'> + <var-decl name='format_spec' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='195' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11584'> + <var-decl name='func' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='196' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11648'> + <var-decl name='generators' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='197' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11712'> + <var-decl name='guard' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='198' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11776'> + <var-decl name='handlers' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='199' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11840'> + <var-decl name='id' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='200' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11904'> + <var-decl name='ifs' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='201' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11968'> + <var-decl name='is_async' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='202' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12032'> + <var-decl name='items' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='203' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12096'> + <var-decl name='iter' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='204' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12160'> + <var-decl name='key' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='205' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12224'> + <var-decl name='keys' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='206' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12288'> + <var-decl name='keyword_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='207' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12352'> + <var-decl name='keywords' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='208' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12416'> + <var-decl name='kind' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='209' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12480'> + <var-decl name='kw_defaults' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='210' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12544'> + <var-decl name='kwarg' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='211' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12608'> + <var-decl name='kwd_attrs' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='212' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12672'> + <var-decl name='kwd_patterns' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='213' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12736'> + <var-decl name='kwonlyargs' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='214' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12800'> + <var-decl name='left' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='215' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12864'> + <var-decl name='level' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='216' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12928'> + <var-decl name='lineno' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='217' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12992'> + <var-decl name='lower' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='218' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13056'> + <var-decl name='match_case_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='219' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13120'> + <var-decl name='mod_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='220' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13184'> + <var-decl name='module' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='221' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13248'> + <var-decl name='msg' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='222' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13312'> + <var-decl name='name' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='223' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13376'> + <var-decl name='names' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='224' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13440'> + <var-decl name='op' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='225' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13504'> + <var-decl name='operand' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='226' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13568'> + <var-decl name='operator_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='227' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13632'> + <var-decl name='ops' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='228' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13696'> + <var-decl name='optional_vars' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='229' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13760'> + <var-decl name='orelse' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='230' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13824'> + <var-decl name='pattern' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='231' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13888'> + <var-decl name='pattern_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='232' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13952'> + <var-decl name='patterns' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='233' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14016'> + <var-decl name='posonlyargs' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='234' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14080'> + <var-decl name='rest' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='235' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14144'> + <var-decl name='returns' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='236' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14208'> + <var-decl name='right' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='237' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14272'> + <var-decl name='simple' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='238' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14336'> + <var-decl name='slice' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='239' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14400'> + <var-decl name='step' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='240' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14464'> + <var-decl name='stmt_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='241' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14528'> + <var-decl name='subject' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='242' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14592'> + <var-decl name='tag' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='243' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14656'> + <var-decl name='target' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='244' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14720'> + <var-decl name='targets' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='245' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14784'> + <var-decl name='test' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='246' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14848'> + <var-decl name='type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='247' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14912'> + <var-decl name='type_comment' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='248' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14976'> + <var-decl name='type_ignore_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='249' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15040'> + <var-decl name='type_ignores' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='250' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15104'> + <var-decl name='type_param_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='251' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15168'> + <var-decl name='type_params' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='252' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15232'> + <var-decl name='unaryop_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='253' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15296'> + <var-decl name='upper' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='254' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15360'> + <var-decl name='value' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='255' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15424'> + <var-decl name='values' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='256' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15488'> + <var-decl name='vararg' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='257' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15552'> + <var-decl name='withitem_type' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_ast_state.h' line='258' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='atexit_callbackfunc' type-id='type-id-227' filepath='./Include/internal/pycore_atexit.h' line='15' column='1' id='type-id-612'/> + <class-decl name='_atexit_runtime_state' size-in-bits='2112' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='17' column='1' id='type-id-798'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='callbacks' type-id='type-id-613' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='19' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2048'> + <var-decl name='ncallbacks' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='20' column='1'/> + </data-member> + </class-decl> + <class-decl name='atexit_callback' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='28' column='1' id='type-id-799'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='func' type-id='type-id-21' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='data' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='next' type-id='type-id-800' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='31' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='atexit_callback' type-id='type-id-799' filepath='./Include/internal/pycore_atexit.h' line='32' column='1' id='type-id-801'/> + <class-decl name='atexit_py_callback' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-802' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='34' column='1' id='type-id-803'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='func' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='args' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='kwargs' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='37' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='atexit_py_callback' type-id='type-id-803' filepath='./Include/internal/pycore_atexit.h' line='38' column='1' id='type-id-802'/> + <class-decl name='atexit_state' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='40' column='1' id='type-id-804'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ll_callbacks' type-id='type-id-800' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='last_ll_callback' type-id='type-id-800' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='callbacks' type-id='type-id-805' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ncallbacks' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='callback_len' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_atexit.h' line='49' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_atomic_address' size-in-bits='64' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_atomic.h' line='45' column='1' id='type-id-806'/> + <typedef-decl name='_Py_atomic_address' type-id='type-id-806' filepath='./Include/internal/pycore_atomic.h' line='47' column='1' id='type-id-807'/> + <class-decl name='_Py_atomic_int' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_atomic.h' line='49' column='1' id='type-id-808'/> + <typedef-decl name='_Py_atomic_int' type-id='type-id-808' filepath='./Include/internal/pycore_atomic.h' line='51' column='1' id='type-id-809'/> + <enum-decl name='perf_status_t' naming-typedef-id='type-id-810' filepath='./Include/internal/pycore_ceval_state.h' line='16' column='1' id='type-id-811'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PERF_STATUS_FAILED' value='-1'/> + <enumerator name='PERF_STATUS_NO_INIT' value='0'/> + <enumerator name='PERF_STATUS_OK' value='1'/> + </enum-decl> + <typedef-decl name='perf_status_t' type-id='type-id-811' filepath='./Include/internal/pycore_ceval_state.h' line='20' column='1' id='type-id-810'/> + <class-decl name='trampoline_api_st' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='26' column='1' id='type-id-812'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='init_state' type-id='type-id-813' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='write_state' type-id='type-id-814' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='free_state' type-id='type-id-815' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='state' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='31' column='1'/> + </data-member> + </class-decl> + <class-decl name='_ceval_runtime_state' size-in-bits='576' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='35' column='1' id='type-id-816'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='perf' type-id='type-id-817' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='signals_pending' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='51' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__9' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='36' column='1' id='type-id-817'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='status' type-id='type-id-810' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='extra_code_index' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='code_arena' type-id='type-id-818' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='trampoline_api' type-id='type-id-812' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='map_file' type-id='type-id-229' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='42' column='1'/> + </data-member> + </class-decl> + <class-decl name='_pending_calls' size-in-bits='4352' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='65' column='1' id='type-id-819'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='busy' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='lock' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='calls_to_do' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='async_exc' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='calls' type-id='type-id-601' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4288'> + <var-decl name='first' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4320'> + <var-decl name='last' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='80' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__1' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='75' column='1' id='type-id-600'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='func' type-id='type-id-815' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='arg' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='77' column='1'/> + </data-member> + </class-decl> + <class-decl name='_ceval_state' size-in-bits='4608' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='83' column='1' id='type-id-821'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='eval_breaker' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='gil_drop_request' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='recursion_limit' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='gil' type-id='type-id-822' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='own_gil' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='gc_scheduled' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='pending' type-id='type-id-819' visibility='default' filepath='./Include/internal/pycore_ceval_state.h' line='94' column='1'/> + </data-member> + </class-decl> + <class-decl name='callable_cache' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_code.h' line='105' column='1' id='type-id-823'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='isinstance' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='len' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='list_append' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='108' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='object__getattribute__' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_code.h' line='109' column='1'/> + </data-member> + </class-decl> + <class-decl name='_PyContextTokenMissing' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-824' visibility='default' filepath='./Include/internal/pycore_context.h' line='21' column='1' id='type-id-825'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_context.h' line='22' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyContextTokenMissing' type-id='type-id-825' filepath='./Include/internal/pycore_context.h' line='23' column='1' id='type-id-824'/> + <class-decl name='_Py_context_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_context.h' line='34' column='1' id='type-id-826'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='freelist' type-id='type-id-827' visibility='default' filepath='./Include/internal/pycore_context.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_context.h' line='38' column='1'/> + </data-member> + </class-decl> + <class-decl name='_pycontextobject' size-in-bits='384' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_context.h' line='42' column='1' id='type-id-723'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_context.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ctx_prev' type-id='type-id-827' visibility='default' filepath='./Include/internal/pycore_context.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ctx_vars' type-id='type-id-828' visibility='default' filepath='./Include/internal/pycore_context.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='ctx_weakreflist' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_context.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='ctx_entered' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_context.h' line='47' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_dict_state' size-in-bits='10944' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='23' column='1' id='type-id-829'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='global_version' type-id='type-id-117' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='next_keys_version' type-id='type-id-352' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='free_list' type-id='type-id-578' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5248'> + <var-decl name='keys_free_list' type-id='type-id-577' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10368'> + <var-decl name='numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10400'> + <var-decl name='keys_numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10432'> + <var-decl name='watchers' type-id='type-id-579' visibility='default' filepath='./Include/internal/pycore_dict_state.h' line='38' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='ULong' type-id='type-id-352' filepath='./Include/internal/pycore_dtoa.h' line='16' column='1' id='type-id-590'/> + <class-decl name='Bigint' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='19' column='1' id='type-id-830'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next' type-id='type-id-570' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='20' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='k' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='maxwds' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='sign' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='wds' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='x' type-id='type-id-591' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='22' column='1'/> + </data-member> + </class-decl> + <class-decl name='_dtoa_state' size-in-bits='19072' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='44' column='1' id='type-id-831'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='p5s' type-id='type-id-570' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='freelist' type-id='type-id-571' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='preallocated' type-id='type-id-624' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='19008'> + <var-decl name='preallocated_next' type-id='type-id-182' visibility='default' filepath='./Include/internal/pycore_dtoa.h' line='50' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_exc_state' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_exceptions.h' line='22' column='1' id='type-id-832'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='errnomap' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_exceptions.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='memerrors_freelist' type-id='type-id-833' visibility='default' filepath='./Include/internal/pycore_exceptions.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='memerrors_numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_exceptions.h' line='26' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='PyExc_ExceptionGroup' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_exceptions.h' line='28' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_sighandler_t' type-id='type-id-834' filepath='./Include/internal/pycore_faulthandler.h' line='30' column='1' id='type-id-835'/> + <class-decl name='faulthandler_user_signal' size-in-bits='1536' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='37' column='1' id='type-id-836'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='enabled' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='file' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='fd' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='all_threads' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='chain' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='previous' type-id='type-id-835' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='interp' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='44' column='1'/> + </data-member> + </class-decl> + <class-decl name='_faulthandler_runtime_state' size-in-bits='1344' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='49' column='1' id='type-id-837'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='fatal_error' type-id='type-id-838' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='thread' type-id='type-id-839' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='user_signals' type-id='type-id-840' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='stack' type-id='type-id-38' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='old_stack' type-id='type-id-38' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='84' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__10' size-in-bits='256' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='50' column='1' id='type-id-838'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='enabled' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='file' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='fd' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='all_threads' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='interp' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='55' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__11' size-in-bits='640' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='61' column='1' id='type-id-839'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='file' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='fd' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='timeout_us' type-id='type-id-378' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='repeat' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='interp' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='exit' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='header' type-id='type-id-15' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='header_len' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='cancel_event' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='running' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_faulthandler.h' line='75' column='1'/> + </data-member> + </class-decl> + <class-decl name='_fileutils_state' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_fileutils.h' line='14' column='1' id='type-id-841'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='force_ascii' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_fileutils.h' line='15' column='1'/> + </data-member> + </class-decl> + <enum-decl name='_Py_error_handler' naming-typedef-id='type-id-442' filepath='./Include/internal/pycore_fileutils.h' line='18' column='1' id='type-id-842'> + <underlying-type type-id='type-id-24'/> + <enumerator name='_Py_ERROR_UNKNOWN' value='0'/> + <enumerator name='_Py_ERROR_STRICT' value='1'/> + <enumerator name='_Py_ERROR_SURROGATEESCAPE' value='2'/> + <enumerator name='_Py_ERROR_REPLACE' value='3'/> + <enumerator name='_Py_ERROR_IGNORE' value='4'/> + <enumerator name='_Py_ERROR_BACKSLASHREPLACE' value='5'/> + <enumerator name='_Py_ERROR_SURROGATEPASS' value='6'/> + <enumerator name='_Py_ERROR_XMLCHARREFREPLACE' value='7'/> + <enumerator name='_Py_ERROR_OTHER' value='8'/> + </enum-decl> + <typedef-decl name='_Py_error_handler' type-id='type-id-842' filepath='./Include/internal/pycore_fileutils.h' line='28' column='1' id='type-id-442'/> + <enum-decl name='_py_float_format_type' filepath='./Include/internal/pycore_floatobject.h' line='22' column='1' id='type-id-843'> + <underlying-type type-id='type-id-24'/> + <enumerator name='_py_float_format_unknown' value='0'/> + <enumerator name='_py_float_format_ieee_big_endian' value='1'/> + <enumerator name='_py_float_format_ieee_little_endian' value='2'/> + </enum-decl> + <class-decl name='_Py_float_runtime_state' size-in-bits='64' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_floatobject.h' line='28' column='1' id='type-id-844'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='float_format' type-id='type-id-843' visibility='default' filepath='./Include/internal/pycore_floatobject.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='double_format' type-id='type-id-843' visibility='default' filepath='./Include/internal/pycore_floatobject.h' line='30' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_float_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_floatobject.h' line='43' column='1' id='type-id-845'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_floatobject.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='free_list' type-id='type-id-846' visibility='default' filepath='./Include/internal/pycore_floatobject.h' line='49' column='1'/> + </data-member> + </class-decl> + <class-decl name='_frame' size-in-bits='448' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_frame.h' line='16' column='1' id='type-id-847'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_frame.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='f_back' type-id='type-id-365' visibility='default' filepath='./Include/internal/pycore_frame.h' line='18' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='f_frame' type-id='type-id-375' visibility='default' filepath='./Include/internal/pycore_frame.h' line='19' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='f_trace' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_frame.h' line='20' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='f_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_frame.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='f_trace_lines' type-id='type-id-48' visibility='default' filepath='./Include/internal/pycore_frame.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='360'> + <var-decl name='f_trace_opcodes' type-id='type-id-48' visibility='default' filepath='./Include/internal/pycore_frame.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='368'> + <var-decl name='f_fast_as_locals' type-id='type-id-48' visibility='default' filepath='./Include/internal/pycore_frame.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='_f_frame_data' type-id='type-id-353' visibility='default' filepath='./Include/internal/pycore_frame.h' line='26' column='1'/> + </data-member> + </class-decl> + <class-decl name='_PyInterpreterFrame' size-in-bits='640' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_frame.h' line='49' column='1' id='type-id-371'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='f_code' type-id='type-id-328' visibility='default' filepath='./Include/internal/pycore_frame.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='previous' type-id='type-id-375' visibility='default' filepath='./Include/internal/pycore_frame.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='f_funcobj' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_frame.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='f_globals' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_frame.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='f_builtins' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_frame.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='f_locals' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_frame.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='frame_obj' type-id='type-id-365' visibility='default' filepath='./Include/internal/pycore_frame.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='prev_instr' type-id='type-id-848' visibility='default' filepath='./Include/internal/pycore_frame.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='stacktop' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_frame.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='544'> + <var-decl name='return_offset' type-id='type-id-707' visibility='default' filepath='./Include/internal/pycore_frame.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='560'> + <var-decl name='owner' type-id='type-id-48' visibility='default' filepath='./Include/internal/pycore_frame.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='localsplus' type-id='type-id-353' visibility='default' filepath='./Include/internal/pycore_frame.h' line='72' column='1'/> + </data-member> + </class-decl> + <class-decl name='_py_func_state' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_function.h' line='13' column='1' id='type-id-849'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next_version' type-id='type-id-352' visibility='default' filepath='./Include/internal/pycore_function.h' line='14' column='1'/> + </data-member> + </class-decl> + <class-decl name='PyGC_Head' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-850' visibility='default' filepath='./Include/internal/pycore_gc.h' line='12' column='1' id='type-id-851'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_gc_next' type-id='type-id-747' visibility='default' filepath='./Include/internal/pycore_gc.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_gc_prev' type-id='type-id-747' visibility='default' filepath='./Include/internal/pycore_gc.h' line='19' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyGC_Head' type-id='type-id-851' filepath='./Include/internal/pycore_gc.h' line='20' column='1' id='type-id-850'/> + <class-decl name='gc_generation' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_gc.h' line='140' column='1' id='type-id-628'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='head' type-id='type-id-850' visibility='default' filepath='./Include/internal/pycore_gc.h' line='141' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='threshold' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_gc.h' line='142' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='count' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_gc.h' line='143' column='1'/> + </data-member> + </class-decl> + <class-decl name='gc_generation_stats' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_gc.h' line='148' column='1' id='type-id-631'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='collections' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_gc.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='collected' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_gc.h' line='152' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='uncollectable' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_gc.h' line='154' column='1'/> + </data-member> + </class-decl> + <class-decl name='_gc_runtime_state' size-in-bits='1920' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_gc.h' line='157' column='1' id='type-id-852'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='trash_delete_later' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_gc.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='trash_delete_nesting' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_gc.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='enabled' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_gc.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='debug' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_gc.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='generations' type-id='type-id-629' visibility='default' filepath='./Include/internal/pycore_gc.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='generation0' type-id='type-id-853' visibility='default' filepath='./Include/internal/pycore_gc.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='permanent_generation' type-id='type-id-628' visibility='default' filepath='./Include/internal/pycore_gc.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='generation_stats' type-id='type-id-632' visibility='default' filepath='./Include/internal/pycore_gc.h' line='172' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='collecting' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_gc.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1664'> + <var-decl name='garbage' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_gc.h' line='176' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='callbacks' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_gc.h' line='178' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='long_lived_total' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_gc.h' line='185' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1856'> + <var-decl name='long_lived_pending' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_gc.h' line='189' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_async_gen_state' size-in-bits='10368' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_genobject.h' line='31' column='1' id='type-id-854'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value_freelist' type-id='type-id-593' visibility='default' filepath='./Include/internal/pycore_genobject.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5120'> + <var-decl name='value_numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_genobject.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5184'> + <var-decl name='asend_freelist' type-id='type-id-574' visibility='default' filepath='./Include/internal/pycore_genobject.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10304'> + <var-decl name='asend_numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_genobject.h' line='41' column='1'/> + </data-member> + </class-decl> + <class-decl name='_gil_runtime_state' size-in-bits='1664' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_gil.h' line='23' column='1' id='type-id-855'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='interval' type-id='type-id-28' visibility='default' filepath='./Include/internal/pycore_gil.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='last_holder' type-id='type-id-807' visibility='default' filepath='./Include/internal/pycore_gil.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='locked' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_gil.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='switch_number' type-id='type-id-28' visibility='default' filepath='./Include/internal/pycore_gil.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='cond' type-id='type-id-856' visibility='default' filepath='./Include/internal/pycore_gil.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='mutex' type-id='type-id-857' visibility='default' filepath='./Include/internal/pycore_gil.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='switch_cond' type-id='type-id-856' visibility='default' filepath='./Include/internal/pycore_gil.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='switch_mutex' type-id='type-id-857' visibility='default' filepath='./Include/internal/pycore_gil.h' line='43' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_static_objects' size-in-bits='584576' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='31' column='1' id='type-id-858'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='singletons' type-id='type-id-859' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='54' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__21' size-in-bits='584576' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='32' column='1' id='type-id-859'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='small_ints' type-id='type-id-582' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='67072'> + <var-decl name='bytes_empty' type-id='type-id-700' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='67392'> + <var-decl name='bytes_characters' type-id='type-id-599' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='165696'> + <var-decl name='strings' type-id='type-id-860' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='583616'> + <var-decl name='_tuple_empty_gc_not_used' type-id='type-id-850' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='583744'> + <var-decl name='tuple_empty' type-id='type-id-790' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='584000'> + <var-decl name='_hamt_bitmap_node_empty_gc_not_used' type-id='type-id-850' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='584128'> + <var-decl name='hamt_bitmap_node_empty' type-id='type-id-861' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='584448'> + <var-decl name='context_token_missing' type-id='type-id-824' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='53' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__22' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='41' column='1' id='type-id-598'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob' type-id='type-id-700' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='eos' type-id='type-id-48' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='43' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_interp_cached_objects' size-in-bits='1280' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='60' column='1' id='type-id-862'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='interned_strings' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='str_replace_inf' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='objreduce' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='type_slots_pname' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='type_slots_ptrs' type-id='type-id-640' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='generic_type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='typevar_type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='typevartuple_type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='paramspec_type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='paramspecargs_type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='paramspeckwargs_type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='77' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_interp_static_objects' size-in-bits='1088' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='85' column='1' id='type-id-863'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='singletons' type-id='type-id-864' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='92' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__745' size-in-bits='1088' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='86' column='1' id='type-id-864'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_not_used' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_hamt_empty_gc_not_used' type-id='type-id-850' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='hamt_empty' type-id='type-id-865' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='last_resort_memory_error' type-id='type-id-756' visibility='default' filepath='./Include/internal/pycore_global_objects.h' line='91' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_global_strings' size-in-bits='417920' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='29' column='1' id='type-id-860'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='literals' type-id='type-id-866' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11008'> + <var-decl name='identifiers' type-id='type-id-867' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='748' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='303232'> + <var-decl name='ascii' type-id='type-id-595' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='752' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352384'> + <var-decl name='latin1' type-id='type-id-597' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='756' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__23' size-in-bits='11008' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='30' column='1' id='type-id-866'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_py_anon_dictcomp' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='_py_anon_genexpr' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='_py_anon_lambda' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='_py_anon_listcomp' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='_py_anon_module' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2240'> + <var-decl name='_py_anon_setcomp' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2688'> + <var-decl name='_py_anon_string' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3136'> + <var-decl name='_py_anon_unknown' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3584'> + <var-decl name='_py_close_br' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3968'> + <var-decl name='_py_dbl_close_br' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4352'> + <var-decl name='_py_dbl_open_br' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4736'> + <var-decl name='_py_dbl_percent' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5120'> + <var-decl name='_py_defaults' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5568'> + <var-decl name='_py_dot' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5952'> + <var-decl name='_py_dot_locals' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6400'> + <var-decl name='_py_empty' type-id='type-id-872' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6784'> + <var-decl name='_py_generic_base' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7232'> + <var-decl name='_py_json_decoder' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7680'> + <var-decl name='_py_kwdefaults' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8128'> + <var-decl name='_py_list_err' type-id='type-id-876' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8640'> + <var-decl name='_py_newline' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9024'> + <var-decl name='_py_open_br' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9408'> + <var-decl name='_py_percent' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9792'> + <var-decl name='_py_shim_name' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10176'> + <var-decl name='_py_type_params' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10624'> + <var-decl name='_py_utf_8' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='56' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__24' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='31' column='1' id='type-id-868'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-650' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='31' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__26' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='32' column='1' id='type-id-869'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-649' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='32' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__27' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='33' column='1' id='type-id-870'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-694' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='33' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__33' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='39' column='1' id='type-id-594'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-680' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='39' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__34' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='40' column='1' id='type-id-871'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-686' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='40' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__40' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='46' column='1' id='type-id-872'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-667' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='46' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__41' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='47' column='1' id='type-id-873'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-656' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='47' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__42' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='48' column='1' id='type-id-874'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-654' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='48' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__43' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='49' column='1' id='type-id-875'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-652' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='49' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__44' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='50' column='1' id='type-id-876'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-673' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='50' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__48' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='54' column='1' id='type-id-877'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-691' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='54' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__50' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='56' column='1' id='type-id-878'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-690' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='56' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__51' size-in-bits='292224' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='59' column='1' id='type-id-867'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_py_CANCELLED' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='_py_FINISHED' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='_py_False' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='_py_JSONDecodeError' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='_py_PENDING' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='_py_Py_Repr' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2496'> + <var-decl name='_py_TextIOWrapper' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2944'> + <var-decl name='_py_True' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3328'> + <var-decl name='_py_WarningMessage' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3776'> + <var-decl name='_py__' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4160'> + <var-decl name='_py__WindowsConsoleIO' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4672'> + <var-decl name='_py___IOBase_closed' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5120'> + <var-decl name='_py___abc_tpflags__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5568'> + <var-decl name='_py___abs__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5952'> + <var-decl name='_py___abstractmethods__' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6464'> + <var-decl name='_py___add__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='6848'> + <var-decl name='_py___aenter__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7296'> + <var-decl name='_py___aexit__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='7744'> + <var-decl name='_py___aiter__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8192'> + <var-decl name='_py___all__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8576'> + <var-decl name='_py___and__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8960'> + <var-decl name='_py___anext__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9408'> + <var-decl name='_py___annotations__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='9856'> + <var-decl name='_py___args__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10304'> + <var-decl name='_py___asyncio_running_event_loop__' type-id='type-id-885' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='10880'> + <var-decl name='_py___await__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11328'> + <var-decl name='_py___bases__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11776'> + <var-decl name='_py___bool__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12224'> + <var-decl name='_py___buffer__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12672'> + <var-decl name='_py___build_class__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13120'> + <var-decl name='_py___builtins__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='13568'> + <var-decl name='_py___bytes__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14016'> + <var-decl name='_py___call__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14464'> + <var-decl name='_py___cantrace__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='14912'> + <var-decl name='_py___class__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='94' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15360'> + <var-decl name='_py___class_getitem__' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15872'> + <var-decl name='_py___classcell__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='16320'> + <var-decl name='_py___classdict__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='16768'> + <var-decl name='_py___classdictcell__' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='17280'> + <var-decl name='_py___complex__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='17728'> + <var-decl name='_py___contains__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18176'> + <var-decl name='_py___copy__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18624'> + <var-decl name='_py___ctypes_from_outparam__' type-id='type-id-886' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='19200'> + <var-decl name='_py___del__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='103' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='19584'> + <var-decl name='_py___delattr__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='104' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='20032'> + <var-decl name='_py___delete__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='105' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='20480'> + <var-decl name='_py___delitem__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='20928'> + <var-decl name='_py___dict__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21376'> + <var-decl name='_py___dictoffset__' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='108' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21824'> + <var-decl name='_py___dir__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='109' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22208'> + <var-decl name='_py___divmod__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22656'> + <var-decl name='_py___doc__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='23040'> + <var-decl name='_py___enter__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='112' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='23488'> + <var-decl name='_py___eq__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='113' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='23872'> + <var-decl name='_py___exit__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='114' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='24320'> + <var-decl name='_py___file__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='115' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='24768'> + <var-decl name='_py___float__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='25216'> + <var-decl name='_py___floordiv__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='117' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='25664'> + <var-decl name='_py___format__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='26112'> + <var-decl name='_py___fspath__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='119' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='26560'> + <var-decl name='_py___ge__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='120' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='26944'> + <var-decl name='_py___get__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='27328'> + <var-decl name='_py___getattr__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='122' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='27776'> + <var-decl name='_py___getattribute__' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='123' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='28288'> + <var-decl name='_py___getinitargs__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='124' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='28736'> + <var-decl name='_py___getitem__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='125' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='29184'> + <var-decl name='_py___getnewargs__' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='126' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='29632'> + <var-decl name='_py___getnewargs_ex__' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='127' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='30144'> + <var-decl name='_py___getstate__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='128' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='30592'> + <var-decl name='_py___gt__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='129' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='30976'> + <var-decl name='_py___hash__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='31424'> + <var-decl name='_py___iadd__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='131' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='31872'> + <var-decl name='_py___iand__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='132' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32320'> + <var-decl name='_py___ifloordiv__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='133' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32768'> + <var-decl name='_py___ilshift__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='134' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='33216'> + <var-decl name='_py___imatmul__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='135' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='33664'> + <var-decl name='_py___imod__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='34112'> + <var-decl name='_py___import__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='137' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='34560'> + <var-decl name='_py___imul__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='35008'> + <var-decl name='_py___index__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='139' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='35456'> + <var-decl name='_py___init__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='140' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='35904'> + <var-decl name='_py___init_subclass__' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='141' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='36416'> + <var-decl name='_py___instancecheck__' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='142' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='36928'> + <var-decl name='_py___int__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='143' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='37312'> + <var-decl name='_py___invert__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='144' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='37760'> + <var-decl name='_py___ior__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='38144'> + <var-decl name='_py___ipow__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='146' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='38592'> + <var-decl name='_py___irshift__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='39040'> + <var-decl name='_py___isabstractmethod__' type-id='type-id-888' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='39552'> + <var-decl name='_py___isub__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='149' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='40000'> + <var-decl name='_py___iter__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='40448'> + <var-decl name='_py___itruediv__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='151' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='40896'> + <var-decl name='_py___ixor__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='152' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='41344'> + <var-decl name='_py___le__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='41728'> + <var-decl name='_py___len__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='42112'> + <var-decl name='_py___length_hint__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='155' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='42560'> + <var-decl name='_py___lltrace__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='43008'> + <var-decl name='_py___loader__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='43456'> + <var-decl name='_py___lshift__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='158' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='43904'> + <var-decl name='_py___lt__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='44288'> + <var-decl name='_py___main__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='44736'> + <var-decl name='_py___matmul__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='45184'> + <var-decl name='_py___missing__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='45632'> + <var-decl name='_py___mod__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='163' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='46016'> + <var-decl name='_py___module__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='46464'> + <var-decl name='_py___mro_entries__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='46912'> + <var-decl name='_py___mul__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='47296'> + <var-decl name='_py___name__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='167' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='47744'> + <var-decl name='_py___ne__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='48128'> + <var-decl name='_py___neg__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='48512'> + <var-decl name='_py___new__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='170' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='48896'> + <var-decl name='_py___newobj__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='49344'> + <var-decl name='_py___newobj_ex__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='172' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='49792'> + <var-decl name='_py___next__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='173' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='50240'> + <var-decl name='_py___notes__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='50688'> + <var-decl name='_py___or__' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='175' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='51072'> + <var-decl name='_py___orig_class__' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='176' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='51520'> + <var-decl name='_py___origin__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='177' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='51968'> + <var-decl name='_py___package__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='178' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='52416'> + <var-decl name='_py___parameters__' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='179' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='52864'> + <var-decl name='_py___path__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='180' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='53312'> + <var-decl name='_py___pos__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='53696'> + <var-decl name='_py___pow__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='182' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='54080'> + <var-decl name='_py___prepare__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='183' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='54528'> + <var-decl name='_py___qualname__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='184' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='54976'> + <var-decl name='_py___radd__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='185' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='55424'> + <var-decl name='_py___rand__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='186' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='55872'> + <var-decl name='_py___rdivmod__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='187' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='56320'> + <var-decl name='_py___reduce__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='188' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='56768'> + <var-decl name='_py___reduce_ex__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='189' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='57216'> + <var-decl name='_py___release_buffer__' type-id='type-id-889' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='190' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='57728'> + <var-decl name='_py___repr__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='191' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='58176'> + <var-decl name='_py___reversed__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='192' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='58624'> + <var-decl name='_py___rfloordiv__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='193' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='59072'> + <var-decl name='_py___rlshift__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='194' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='59520'> + <var-decl name='_py___rmatmul__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='195' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='59968'> + <var-decl name='_py___rmod__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='196' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='60416'> + <var-decl name='_py___rmul__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='197' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='60864'> + <var-decl name='_py___ror__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='198' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='61248'> + <var-decl name='_py___round__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='199' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='61696'> + <var-decl name='_py___rpow__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='200' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='62144'> + <var-decl name='_py___rrshift__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='201' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='62592'> + <var-decl name='_py___rshift__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='202' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='63040'> + <var-decl name='_py___rsub__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='203' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='63488'> + <var-decl name='_py___rtruediv__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='204' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='63936'> + <var-decl name='_py___rxor__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='205' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64384'> + <var-decl name='_py___set__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='206' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64768'> + <var-decl name='_py___set_name__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='207' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='65216'> + <var-decl name='_py___setattr__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='208' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='65664'> + <var-decl name='_py___setitem__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='209' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='66112'> + <var-decl name='_py___setstate__' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='210' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='66560'> + <var-decl name='_py___sizeof__' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='211' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='67008'> + <var-decl name='_py___slotnames__' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='212' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='67456'> + <var-decl name='_py___slots__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='213' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='67904'> + <var-decl name='_py___spec__' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='214' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='68352'> + <var-decl name='_py___str__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='215' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='68736'> + <var-decl name='_py___sub__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='216' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='69120'> + <var-decl name='_py___subclasscheck__' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='217' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='69632'> + <var-decl name='_py___subclasshook__' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='218' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='70144'> + <var-decl name='_py___truediv__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='219' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='70592'> + <var-decl name='_py___trunc__' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='220' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='71040'> + <var-decl name='_py___type_params__' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='221' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='71488'> + <var-decl name='_py___typing_is_unpacked_typevartuple__' type-id='type-id-890' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='222' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='72128'> + <var-decl name='_py___typing_prepare_subst__' type-id='type-id-886' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='223' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='72704'> + <var-decl name='_py___typing_subst__' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='224' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='73216'> + <var-decl name='_py___typing_unpacked_tuple_args__' type-id='type-id-885' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='225' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='73792'> + <var-decl name='_py___warningregistry__' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='226' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='74304'> + <var-decl name='_py___weaklistoffset__' type-id='type-id-889' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='227' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='74816'> + <var-decl name='_py___weakref__' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='228' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='75264'> + <var-decl name='_py___xor__' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='229' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='75648'> + <var-decl name='_py__abc_impl' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='230' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='76096'> + <var-decl name='_py__abstract_' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='231' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='76544'> + <var-decl name='_py__active' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='232' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='76928'> + <var-decl name='_py__annotation' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='233' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='77376'> + <var-decl name='_py__anonymous_' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='234' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='77824'> + <var-decl name='_py__argtypes_' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='235' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='78272'> + <var-decl name='_py__as_parameter_' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='236' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='78720'> + <var-decl name='_py__asyncio_future_blocking' type-id='type-id-886' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='237' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='79296'> + <var-decl name='_py__blksize' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='238' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='79744'> + <var-decl name='_py__bootstrap' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='239' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='80192'> + <var-decl name='_py__check_retval_' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='240' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='80640'> + <var-decl name='_py__dealloc_warn' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='241' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='81088'> + <var-decl name='_py__feature_version' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='242' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='81600'> + <var-decl name='_py__fields_' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='243' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='82048'> + <var-decl name='_py__finalizing' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='244' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='82496'> + <var-decl name='_py__find_and_load' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='245' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='82944'> + <var-decl name='_py__fix_up_module' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='246' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='83392'> + <var-decl name='_py__flags_' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='247' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='83776'> + <var-decl name='_py__get_sourcefile' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='248' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='84224'> + <var-decl name='_py__handle_fromlist' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='249' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='84736'> + <var-decl name='_py__initializing' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='250' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='85184'> + <var-decl name='_py__io' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='251' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='85568'> + <var-decl name='_py__is_text_encoding' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='252' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='86080'> + <var-decl name='_py__length_' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='253' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='86528'> + <var-decl name='_py__limbo' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='254' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='86912'> + <var-decl name='_py__lock_unlock_module' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='255' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='87424'> + <var-decl name='_py__loop' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='256' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='87808'> + <var-decl name='_py__needs_com_addref_' type-id='type-id-889' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='257' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='88320'> + <var-decl name='_py__pack_' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='258' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='88704'> + <var-decl name='_py__restype_' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='259' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='89152'> + <var-decl name='_py__showwarnmsg' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='260' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='89600'> + <var-decl name='_py__shutdown' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='261' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='90048'> + <var-decl name='_py__slotnames' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='262' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='90496'> + <var-decl name='_py__strptime_datetime' type-id='type-id-889' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='263' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='91008'> + <var-decl name='_py__swappedbytes_' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='264' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='91456'> + <var-decl name='_py__type_' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='265' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='91840'> + <var-decl name='_py__uninitialized_submodules' type-id='type-id-892' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='266' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='92416'> + <var-decl name='_py__warn_unawaited_coroutine' type-id='type-id-892' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='267' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='92992'> + <var-decl name='_py__xoptions' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='268' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='93440'> + <var-decl name='_py_a' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='269' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='93824'> + <var-decl name='_py_abs_tol' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='270' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='94208'> + <var-decl name='_py_access' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='271' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='94592'> + <var-decl name='_py_add' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='272' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='94976'> + <var-decl name='_py_add_done_callback' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='273' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='95488'> + <var-decl name='_py_after_in_child' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='274' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='95936'> + <var-decl name='_py_after_in_parent' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='275' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96384'> + <var-decl name='_py_aggregate_class' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='276' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96832'> + <var-decl name='_py_alias' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='277' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='97216'> + <var-decl name='_py_append' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='278' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='97600'> + <var-decl name='_py_arg' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='279' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='97984'> + <var-decl name='_py_argdefs' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='280' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='98368'> + <var-decl name='_py_args' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='281' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='98752'> + <var-decl name='_py_arguments' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='282' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='99200'> + <var-decl name='_py_argv' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='283' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='99584'> + <var-decl name='_py_as_integer_ratio' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='284' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='100096'> + <var-decl name='_py_ast' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='285' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='100480'> + <var-decl name='_py_attribute' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='286' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='100928'> + <var-decl name='_py_authorizer_callback' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='287' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='101440'> + <var-decl name='_py_autocommit' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='288' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='101888'> + <var-decl name='_py_b' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='289' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='102272'> + <var-decl name='_py_backtick' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='290' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='102720'> + <var-decl name='_py_base' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='291' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='103104'> + <var-decl name='_py_before' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='292' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='103488'> + <var-decl name='_py_big' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='293' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='103872'> + <var-decl name='_py_binary_form' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='294' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='104320'> + <var-decl name='_py_block' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='295' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='104704'> + <var-decl name='_py_bound' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='296' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='105088'> + <var-decl name='_py_buffer' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='297' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='105472'> + <var-decl name='_py_buffer_callback' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='298' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='105920'> + <var-decl name='_py_buffer_size' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='299' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='106368'> + <var-decl name='_py_buffering' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='300' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='106816'> + <var-decl name='_py_buffers' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='301' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='107200'> + <var-decl name='_py_bufsize' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='302' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='107584'> + <var-decl name='_py_builtins' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='303' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='108032'> + <var-decl name='_py_byteorder' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='304' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='108480'> + <var-decl name='_py_bytes' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='305' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='108864'> + <var-decl name='_py_bytes_per_sep' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='306' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='109312'> + <var-decl name='_py_c' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='307' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='109696'> + <var-decl name='_py_c_call' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='308' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='110080'> + <var-decl name='_py_c_exception' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='309' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='110528'> + <var-decl name='_py_c_return' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='310' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='110976'> + <var-decl name='_py_cached_statements' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='311' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='111488'> + <var-decl name='_py_cadata' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='312' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='111872'> + <var-decl name='_py_cafile' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='313' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='112256'> + <var-decl name='_py_call' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='314' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='112640'> + <var-decl name='_py_call_exception_handler' type-id='type-id-893' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='315' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='113152'> + <var-decl name='_py_call_soon' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='316' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='113600'> + <var-decl name='_py_cancel' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='317' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='113984'> + <var-decl name='_py_capath' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='318' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='114368'> + <var-decl name='_py_category' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='319' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='114816'> + <var-decl name='_py_cb_type' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='320' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='115200'> + <var-decl name='_py_certfile' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='321' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='115648'> + <var-decl name='_py_check_same_thread' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='322' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='116160'> + <var-decl name='_py_clear' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='323' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='116544'> + <var-decl name='_py_close' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='324' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='116928'> + <var-decl name='_py_closed' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='325' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='117312'> + <var-decl name='_py_closefd' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='326' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='117696'> + <var-decl name='_py_closure' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='327' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='118080'> + <var-decl name='_py_co_argcount' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='328' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='118528'> + <var-decl name='_py_co_cellvars' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='329' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='118976'> + <var-decl name='_py_co_code' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='330' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='119360'> + <var-decl name='_py_co_consts' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='331' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='119808'> + <var-decl name='_py_co_exceptiontable' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='332' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='120320'> + <var-decl name='_py_co_filename' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='333' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='120768'> + <var-decl name='_py_co_firstlineno' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='334' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='121216'> + <var-decl name='_py_co_flags' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='335' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='121664'> + <var-decl name='_py_co_freevars' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='336' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='122112'> + <var-decl name='_py_co_kwonlyargcount' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='337' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='122624'> + <var-decl name='_py_co_linetable' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='338' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='123072'> + <var-decl name='_py_co_name' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='339' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='123456'> + <var-decl name='_py_co_names' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='340' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='123904'> + <var-decl name='_py_co_nlocals' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='341' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='124352'> + <var-decl name='_py_co_posonlyargcount' type-id='type-id-889' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='342' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='124864'> + <var-decl name='_py_co_qualname' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='343' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='125312'> + <var-decl name='_py_co_stacksize' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='344' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='125760'> + <var-decl name='_py_co_varnames' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='345' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='126208'> + <var-decl name='_py_code' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='346' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='126592'> + <var-decl name='_py_command' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='347' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='126976'> + <var-decl name='_py_comment_factory' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='348' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='127424'> + <var-decl name='_py_compile_mode' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='349' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='127872'> + <var-decl name='_py_consts' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='350' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128256'> + <var-decl name='_py_context' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='351' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128640'> + <var-decl name='_py_contravariant' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='352' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='129088'> + <var-decl name='_py_cookie' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='353' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='129472'> + <var-decl name='_py_copy' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='354' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='129856'> + <var-decl name='_py_copyreg' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='355' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='130240'> + <var-decl name='_py_coro' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='356' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='130624'> + <var-decl name='_py_count' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='357' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='131008'> + <var-decl name='_py_covariant' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='358' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='131456'> + <var-decl name='_py_cwd' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='359' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='131840'> + <var-decl name='_py_d' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='360' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='132224'> + <var-decl name='_py_data' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='361' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='132608'> + <var-decl name='_py_database' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='362' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='133056'> + <var-decl name='_py_decode' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='363' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='133440'> + <var-decl name='_py_decoder' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='364' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='133824'> + <var-decl name='_py_default' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='365' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='134208'> + <var-decl name='_py_defaultaction' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='366' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='134656'> + <var-decl name='_py_delete' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='367' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='135040'> + <var-decl name='_py_depth' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='368' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='135424'> + <var-decl name='_py_detect_types' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='369' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='135872'> + <var-decl name='_py_deterministic' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='370' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='136320'> + <var-decl name='_py_device' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='371' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='136704'> + <var-decl name='_py_dict' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='372' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='137088'> + <var-decl name='_py_dictcomp' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='373' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='137536'> + <var-decl name='_py_difference_update' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='374' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138048'> + <var-decl name='_py_digest' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='375' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138432'> + <var-decl name='_py_digest_size' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='376' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138880'> + <var-decl name='_py_digestmod' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='377' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='139328'> + <var-decl name='_py_dir_fd' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='378' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='139712'> + <var-decl name='_py_discard' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='379' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='140096'> + <var-decl name='_py_dispatch_table' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='380' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='140544'> + <var-decl name='_py_displayhook' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='381' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='140992'> + <var-decl name='_py_dklen' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='382' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='141376'> + <var-decl name='_py_doc' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='383' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='141760'> + <var-decl name='_py_dont_inherit' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='384' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='142208'> + <var-decl name='_py_dst' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='385' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='142592'> + <var-decl name='_py_dst_dir_fd' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='386' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='143040'> + <var-decl name='_py_duration' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='387' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='143488'> + <var-decl name='_py_e' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='388' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='143872'> + <var-decl name='_py_eager_start' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='389' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='144320'> + <var-decl name='_py_effective_ids' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='390' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='144768'> + <var-decl name='_py_element_factory' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='391' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='145216'> + <var-decl name='_py_encode' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='392' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='145600'> + <var-decl name='_py_encoding' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='393' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='146048'> + <var-decl name='_py_end' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='394' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='146432'> + <var-decl name='_py_end_lineno' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='395' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='146880'> + <var-decl name='_py_end_offset' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='396' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='147328'> + <var-decl name='_py_endpos' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='397' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='147712'> + <var-decl name='_py_entrypoint' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='398' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='148160'> + <var-decl name='_py_env' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='399' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='148544'> + <var-decl name='_py_errors' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='400' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='148928'> + <var-decl name='_py_event' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='401' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='149312'> + <var-decl name='_py_eventmask' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='402' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='149760'> + <var-decl name='_py_exc_type' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='403' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='150208'> + <var-decl name='_py_exc_value' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='404' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='150656'> + <var-decl name='_py_excepthook' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='405' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='151104'> + <var-decl name='_py_exception' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='406' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='151552'> + <var-decl name='_py_exp' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='407' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='151936'> + <var-decl name='_py_extend' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='408' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='152320'> + <var-decl name='_py_extra_tokens' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='409' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='152768'> + <var-decl name='_py_facility' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='410' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='153216'> + <var-decl name='_py_factory' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='411' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='153600'> + <var-decl name='_py_false' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='412' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='153984'> + <var-decl name='_py_family' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='413' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='154368'> + <var-decl name='_py_fanout' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='414' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='154752'> + <var-decl name='_py_fd' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='415' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='155136'> + <var-decl name='_py_fd2' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='416' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='155520'> + <var-decl name='_py_fdel' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='417' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='155904'> + <var-decl name='_py_fget' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='418' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='156288'> + <var-decl name='_py_file' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='419' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='156672'> + <var-decl name='_py_file_actions' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='420' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='157120'> + <var-decl name='_py_filename' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='421' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='157568'> + <var-decl name='_py_fileno' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='422' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='157952'> + <var-decl name='_py_filepath' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='423' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='158400'> + <var-decl name='_py_fillvalue' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='424' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='158848'> + <var-decl name='_py_filters' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='425' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='159232'> + <var-decl name='_py_final' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='426' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='159616'> + <var-decl name='_py_find_class' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='427' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160064'> + <var-decl name='_py_fix_imports' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='428' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160512'> + <var-decl name='_py_flags' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='429' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160896'> + <var-decl name='_py_flush' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='430' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='161280'> + <var-decl name='_py_follow_symlinks' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='431' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='161728'> + <var-decl name='_py_format' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='432' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='162112'> + <var-decl name='_py_frequency' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='433' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='162560'> + <var-decl name='_py_from_param' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='434' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='163008'> + <var-decl name='_py_fromlist' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='435' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='163456'> + <var-decl name='_py_fromtimestamp' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='436' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='163904'> + <var-decl name='_py_fromutc' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='437' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='164288'> + <var-decl name='_py_fset' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='438' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='164672'> + <var-decl name='_py_func' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='439' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='165056'> + <var-decl name='_py_future' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='440' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='165440'> + <var-decl name='_py_generation' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='441' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='165888'> + <var-decl name='_py_genexpr' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='442' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='166272'> + <var-decl name='_py_get' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='443' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='166656'> + <var-decl name='_py_get_debug' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='444' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='167104'> + <var-decl name='_py_get_event_loop' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='445' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='167552'> + <var-decl name='_py_get_loop' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='446' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='168000'> + <var-decl name='_py_get_source' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='447' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='168448'> + <var-decl name='_py_getattr' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='448' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='168832'> + <var-decl name='_py_getstate' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='449' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='169280'> + <var-decl name='_py_gid' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='450' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='169664'> + <var-decl name='_py_globals' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='451' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='170048'> + <var-decl name='_py_groupindex' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='452' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='170496'> + <var-decl name='_py_groups' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='453' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='170880'> + <var-decl name='_py_handle' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='454' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='171264'> + <var-decl name='_py_hash_name' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='455' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='171712'> + <var-decl name='_py_header' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='456' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='172096'> + <var-decl name='_py_headers' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='457' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='172480'> + <var-decl name='_py_hi' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='458' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='172864'> + <var-decl name='_py_hook' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='459' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='173248'> + <var-decl name='_py_id' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='460' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='173632'> + <var-decl name='_py_ident' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='461' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='174016'> + <var-decl name='_py_ignore' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='462' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='174400'> + <var-decl name='_py_imag' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='463' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='174784'> + <var-decl name='_py_importlib' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='464' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='175232'> + <var-decl name='_py_in_fd' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='465' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='175616'> + <var-decl name='_py_incoming' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='466' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='176064'> + <var-decl name='_py_indexgroup' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='467' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='176512'> + <var-decl name='_py_inf' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='468' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='176896'> + <var-decl name='_py_infer_variance' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='469' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='177344'> + <var-decl name='_py_inheritable' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='470' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='177792'> + <var-decl name='_py_initial' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='471' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='178176'> + <var-decl name='_py_initial_bytes' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='472' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='178624'> + <var-decl name='_py_initial_value' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='473' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='179072'> + <var-decl name='_py_initval' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='474' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='179456'> + <var-decl name='_py_inner_size' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='475' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='179904'> + <var-decl name='_py_input' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='476' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='180288'> + <var-decl name='_py_insert_comments' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='477' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='180736'> + <var-decl name='_py_insert_pis' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='478' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='181184'> + <var-decl name='_py_instructions' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='479' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='181632'> + <var-decl name='_py_intern' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='480' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='182016'> + <var-decl name='_py_intersection' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='481' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='182464'> + <var-decl name='_py_is_running' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='482' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='182912'> + <var-decl name='_py_isatty' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='483' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='183296'> + <var-decl name='_py_isinstance' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='484' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='183744'> + <var-decl name='_py_isoformat' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='485' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='184192'> + <var-decl name='_py_isolation_level' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='486' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='184640'> + <var-decl name='_py_istext' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='487' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='185024'> + <var-decl name='_py_item' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='488' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='185408'> + <var-decl name='_py_items' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='489' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='185792'> + <var-decl name='_py_iter' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='490' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='186176'> + <var-decl name='_py_iterable' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='491' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='186624'> + <var-decl name='_py_iterations' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='492' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='187072'> + <var-decl name='_py_join' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='493' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='187456'> + <var-decl name='_py_jump' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='494' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='187840'> + <var-decl name='_py_keepends' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='495' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='188288'> + <var-decl name='_py_key' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='496' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='188672'> + <var-decl name='_py_keyfile' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='497' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='189056'> + <var-decl name='_py_keys' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='498' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='189440'> + <var-decl name='_py_kind' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='499' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='189824'> + <var-decl name='_py_kw' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='500' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='190208'> + <var-decl name='_py_kw1' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='501' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='190592'> + <var-decl name='_py_kw2' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='502' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='190976'> + <var-decl name='_py_lambda' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='503' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='191360'> + <var-decl name='_py_last' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='504' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='191744'> + <var-decl name='_py_last_exc' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='505' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192192'> + <var-decl name='_py_last_node' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='506' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192640'> + <var-decl name='_py_last_traceback' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='507' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='193088'> + <var-decl name='_py_last_type' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='508' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='193536'> + <var-decl name='_py_last_value' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='509' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='193984'> + <var-decl name='_py_latin1' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='510' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='194368'> + <var-decl name='_py_leaf_size' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='511' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='194816'> + <var-decl name='_py_len' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='512' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='195200'> + <var-decl name='_py_length' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='513' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='195584'> + <var-decl name='_py_level' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='514' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='195968'> + <var-decl name='_py_limit' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='515' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='196352'> + <var-decl name='_py_line' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='516' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='196736'> + <var-decl name='_py_line_buffering' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='517' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='197184'> + <var-decl name='_py_lineno' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='518' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='197568'> + <var-decl name='_py_listcomp' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='519' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='198016'> + <var-decl name='_py_little' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='520' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='198400'> + <var-decl name='_py_lo' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='521' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='198784'> + <var-decl name='_py_locale' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='522' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='199168'> + <var-decl name='_py_locals' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='523' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='199552'> + <var-decl name='_py_logoption' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='524' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='200000'> + <var-decl name='_py_loop' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='525' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='200384'> + <var-decl name='_py_mapping' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='526' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='200768'> + <var-decl name='_py_match' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='527' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='201152'> + <var-decl name='_py_max_length' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='528' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='201600'> + <var-decl name='_py_maxdigits' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='529' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='202048'> + <var-decl name='_py_maxevents' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='530' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='202496'> + <var-decl name='_py_maxmem' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='531' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='202880'> + <var-decl name='_py_maxsplit' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='532' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='203328'> + <var-decl name='_py_maxvalue' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='533' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='203776'> + <var-decl name='_py_memLevel' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='534' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='204224'> + <var-decl name='_py_memlimit' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='535' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='204672'> + <var-decl name='_py_message' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='536' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='205056'> + <var-decl name='_py_metaclass' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='537' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='205504'> + <var-decl name='_py_metadata' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='538' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='205952'> + <var-decl name='_py_method' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='539' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='206336'> + <var-decl name='_py_mod' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='540' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='206720'> + <var-decl name='_py_mode' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='541' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='207104'> + <var-decl name='_py_module' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='542' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='207488'> + <var-decl name='_py_module_globals' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='543' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='207936'> + <var-decl name='_py_modules' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='544' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='208320'> + <var-decl name='_py_mro' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='545' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='208704'> + <var-decl name='_py_msg' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='546' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='209088'> + <var-decl name='_py_mycmp' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='547' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='209472'> + <var-decl name='_py_n' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='548' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='209856'> + <var-decl name='_py_n_arg' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='549' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='210240'> + <var-decl name='_py_n_fields' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='550' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='210688'> + <var-decl name='_py_n_sequence_fields' type-id='type-id-883' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='551' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='211200'> + <var-decl name='_py_n_unnamed_fields' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='552' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='211712'> + <var-decl name='_py_name' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='553' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='212096'> + <var-decl name='_py_name_from' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='554' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='212544'> + <var-decl name='_py_namespace_separator' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='555' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='213056'> + <var-decl name='_py_namespaces' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='556' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='213504'> + <var-decl name='_py_narg' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='557' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='213888'> + <var-decl name='_py_ndigits' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='558' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='214272'> + <var-decl name='_py_new_limit' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='559' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='214720'> + <var-decl name='_py_newline' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='560' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='215104'> + <var-decl name='_py_newlines' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='561' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='215552'> + <var-decl name='_py_next' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='562' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='215936'> + <var-decl name='_py_nlocals' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='563' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='216320'> + <var-decl name='_py_node_depth' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='564' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='216768'> + <var-decl name='_py_node_offset' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='565' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='217216'> + <var-decl name='_py_ns' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='566' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='217600'> + <var-decl name='_py_nstype' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='567' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='217984'> + <var-decl name='_py_nt' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='568' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='218368'> + <var-decl name='_py_null' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='569' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='218752'> + <var-decl name='_py_number' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='570' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='219136'> + <var-decl name='_py_obj' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='571' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='219520'> + <var-decl name='_py_object' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='572' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='219904'> + <var-decl name='_py_offset' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='573' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='220288'> + <var-decl name='_py_offset_dst' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='574' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='220736'> + <var-decl name='_py_offset_src' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='575' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='221184'> + <var-decl name='_py_on_type_read' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='576' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='221632'> + <var-decl name='_py_onceregistry' type-id='type-id-874' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='577' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='222080'> + <var-decl name='_py_only_keys' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='578' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='222528'> + <var-decl name='_py_oparg' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='579' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='222912'> + <var-decl name='_py_opcode' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='580' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='223296'> + <var-decl name='_py_open' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='581' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='223680'> + <var-decl name='_py_opener' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='582' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224064'> + <var-decl name='_py_operation' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='583' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224512'> + <var-decl name='_py_optimize' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='584' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224960'> + <var-decl name='_py_options' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='585' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='225344'> + <var-decl name='_py_order' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='586' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='225728'> + <var-decl name='_py_origin' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='587' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='226112'> + <var-decl name='_py_out_fd' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='588' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='226496'> + <var-decl name='_py_outgoing' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='589' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='226944'> + <var-decl name='_py_overlapped' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='590' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='227392'> + <var-decl name='_py_owner' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='591' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='227776'> + <var-decl name='_py_p' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='592' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='228160'> + <var-decl name='_py_pages' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='593' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='228544'> + <var-decl name='_py_parent' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='594' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='228928'> + <var-decl name='_py_password' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='595' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='229376'> + <var-decl name='_py_path' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='596' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='229760'> + <var-decl name='_py_pattern' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='597' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='230144'> + <var-decl name='_py_peek' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='598' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='230528'> + <var-decl name='_py_persistent_id' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='599' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='230976'> + <var-decl name='_py_persistent_load' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='600' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='231424'> + <var-decl name='_py_person' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='601' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='231808'> + <var-decl name='_py_pi_factory' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='602' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='232256'> + <var-decl name='_py_pid' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='603' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='232640'> + <var-decl name='_py_policy' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='604' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='233024'> + <var-decl name='_py_pos' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='605' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='233408'> + <var-decl name='_py_pos1' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='606' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='233792'> + <var-decl name='_py_pos2' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='607' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='234176'> + <var-decl name='_py_posix' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='608' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='234560'> + <var-decl name='_py_print_file_and_line' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='609' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='235072'> + <var-decl name='_py_priority' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='610' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='235520'> + <var-decl name='_py_progress' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='611' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='235968'> + <var-decl name='_py_progress_handler' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='612' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='236480'> + <var-decl name='_py_proto' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='613' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='236864'> + <var-decl name='_py_protocol' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='614' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='237312'> + <var-decl name='_py_ps1' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='615' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='237696'> + <var-decl name='_py_ps2' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='616' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='238080'> + <var-decl name='_py_query' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='617' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='238464'> + <var-decl name='_py_quotetabs' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='618' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='238912'> + <var-decl name='_py_r' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='619' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='239296'> + <var-decl name='_py_raw' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='620' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='239680'> + <var-decl name='_py_read' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='621' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='240064'> + <var-decl name='_py_read1' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='622' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='240448'> + <var-decl name='_py_readable' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='623' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='240896'> + <var-decl name='_py_readall' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='624' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='241280'> + <var-decl name='_py_readinto' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='625' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='241728'> + <var-decl name='_py_readinto1' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='626' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='242176'> + <var-decl name='_py_readline' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='627' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='242624'> + <var-decl name='_py_readonly' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='628' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='243072'> + <var-decl name='_py_real' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='629' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='243456'> + <var-decl name='_py_reducer_override' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='630' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='243968'> + <var-decl name='_py_registry' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='631' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='244416'> + <var-decl name='_py_rel_tol' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='632' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='244800'> + <var-decl name='_py_release' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='633' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='245184'> + <var-decl name='_py_reload' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='634' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='245568'> + <var-decl name='_py_repl' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='635' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='245952'> + <var-decl name='_py_replace' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='636' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='246336'> + <var-decl name='_py_reserved' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='637' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='246784'> + <var-decl name='_py_reset' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='638' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='247168'> + <var-decl name='_py_resetids' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='639' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='247616'> + <var-decl name='_py_return' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='640' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='248000'> + <var-decl name='_py_reverse' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='641' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='248384'> + <var-decl name='_py_reversed' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='642' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='248832'> + <var-decl name='_py_s' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='643' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='249216'> + <var-decl name='_py_salt' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='644' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='249600'> + <var-decl name='_py_sched_priority' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='645' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='250048'> + <var-decl name='_py_scheduler' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='646' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='250496'> + <var-decl name='_py_seek' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='647' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='250880'> + <var-decl name='_py_seekable' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='648' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='251328'> + <var-decl name='_py_selectors' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='649' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='251776'> + <var-decl name='_py_self' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='650' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='252160'> + <var-decl name='_py_send' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='651' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='252544'> + <var-decl name='_py_sep' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='652' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='252928'> + <var-decl name='_py_sequence' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='653' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='253376'> + <var-decl name='_py_server_hostname' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='654' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='253824'> + <var-decl name='_py_server_side' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='655' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='254272'> + <var-decl name='_py_session' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='656' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='254656'> + <var-decl name='_py_setcomp' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='657' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='255040'> + <var-decl name='_py_setpgroup' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='658' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='255488'> + <var-decl name='_py_setsid' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='659' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='255872'> + <var-decl name='_py_setsigdef' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='660' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256320'> + <var-decl name='_py_setsigmask' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='661' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256768'> + <var-decl name='_py_setstate' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='662' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='257216'> + <var-decl name='_py_shape' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='663' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='257600'> + <var-decl name='_py_show_cmd' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='664' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='258048'> + <var-decl name='_py_signed' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='665' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='258432'> + <var-decl name='_py_size' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='666' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='258816'> + <var-decl name='_py_sizehint' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='667' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='259264'> + <var-decl name='_py_skip_file_prefixes' type-id='type-id-889' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='668' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='259776'> + <var-decl name='_py_sleep' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='669' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='260160'> + <var-decl name='_py_sock' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='670' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='260544'> + <var-decl name='_py_sort' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='671' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='260928'> + <var-decl name='_py_sound' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='672' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='261312'> + <var-decl name='_py_source' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='673' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='261696'> + <var-decl name='_py_source_traceback' type-id='type-id-887' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='674' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='262208'> + <var-decl name='_py_src' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='675' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='262592'> + <var-decl name='_py_src_dir_fd' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='676' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='263040'> + <var-decl name='_py_stacklevel' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='677' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='263488'> + <var-decl name='_py_start' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='678' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='263872'> + <var-decl name='_py_statement' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='679' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='264320'> + <var-decl name='_py_status' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='680' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='264704'> + <var-decl name='_py_stderr' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='681' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='265088'> + <var-decl name='_py_stdin' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='682' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='265472'> + <var-decl name='_py_stdout' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='683' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='265856'> + <var-decl name='_py_step' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='684' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='266240'> + <var-decl name='_py_steps' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='685' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='266624'> + <var-decl name='_py_store_name' type-id='type-id-868' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='686' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='267072'> + <var-decl name='_py_strategy' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='687' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='267520'> + <var-decl name='_py_strftime' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='688' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='267968'> + <var-decl name='_py_strict' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='689' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='268352'> + <var-decl name='_py_strict_mode' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='690' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='268800'> + <var-decl name='_py_string' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='691' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='269184'> + <var-decl name='_py_sub_key' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='692' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='269568'> + <var-decl name='_py_symmetric_difference_update' type-id='type-id-894' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='693' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='270144'> + <var-decl name='_py_tabsize' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='694' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='270528'> + <var-decl name='_py_tag' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='695' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='270912'> + <var-decl name='_py_target' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='696' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='271296'> + <var-decl name='_py_target_is_directory' type-id='type-id-884' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='697' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='271808'> + <var-decl name='_py_task' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='698' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='272192'> + <var-decl name='_py_tb_frame' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='699' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='272640'> + <var-decl name='_py_tb_lasti' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='700' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='273088'> + <var-decl name='_py_tb_lineno' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='701' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='273536'> + <var-decl name='_py_tb_next' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='702' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='273920'> + <var-decl name='_py_tell' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='703' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='274304'> + <var-decl name='_py_template' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='704' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='274752'> + <var-decl name='_py_term' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='705' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='275136'> + <var-decl name='_py_text' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='706' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='275520'> + <var-decl name='_py_threading' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='707' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='275968'> + <var-decl name='_py_throw' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='708' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='276352'> + <var-decl name='_py_timeout' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='709' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='276736'> + <var-decl name='_py_times' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='710' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='277120'> + <var-decl name='_py_timetuple' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='711' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='277568'> + <var-decl name='_py_top' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='712' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='277952'> + <var-decl name='_py_trace_callback' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='713' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='278400'> + <var-decl name='_py_traceback' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='714' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='278848'> + <var-decl name='_py_trailers' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='715' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='279296'> + <var-decl name='_py_translate' type-id='type-id-869' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='716' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='279744'> + <var-decl name='_py_true' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='717' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='280128'> + <var-decl name='_py_truncate' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='718' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='280576'> + <var-decl name='_py_twice' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='719' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='280960'> + <var-decl name='_py_txt' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='720' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='281344'> + <var-decl name='_py_type' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='721' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='281728'> + <var-decl name='_py_type_params' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='722' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='282176'> + <var-decl name='_py_tz' type-id='type-id-871' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='723' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='282560'> + <var-decl name='_py_tzname' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='724' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='282944'> + <var-decl name='_py_uid' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='725' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='283328'> + <var-decl name='_py_unlink' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='726' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='283712'> + <var-decl name='_py_unraisablehook' type-id='type-id-882' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='727' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='284160'> + <var-decl name='_py_uri' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='728' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='284544'> + <var-decl name='_py_usedforsecurity' type-id='type-id-879' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='729' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='284992'> + <var-decl name='_py_value' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='730' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='285376'> + <var-decl name='_py_values' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='731' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='285760'> + <var-decl name='_py_version' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='732' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='286144'> + <var-decl name='_py_volume' type-id='type-id-877' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='733' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='286528'> + <var-decl name='_py_warnings' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='734' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='286976'> + <var-decl name='_py_warnoptions' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='735' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='287424'> + <var-decl name='_py_wbits' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='736' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='287808'> + <var-decl name='_py_week' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='737' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288192'> + <var-decl name='_py_weekday' type-id='type-id-880' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='738' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288576'> + <var-decl name='_py_which' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='739' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288960'> + <var-decl name='_py_who' type-id='type-id-891' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='740' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='289344'> + <var-decl name='_py_withdata' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='741' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='289792'> + <var-decl name='_py_writable' type-id='type-id-870' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='742' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='290240'> + <var-decl name='_py_write' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='743' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='290624'> + <var-decl name='_py_write_through' type-id='type-id-873' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='744' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='291072'> + <var-decl name='_py_x' type-id='type-id-594' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='745' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='291456'> + <var-decl name='_py_year' type-id='type-id-881' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='746' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='291840'> + <var-decl name='_py_zdict' type-id='type-id-878' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='747' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__55' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='63' column='1' id='type-id-879'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-660' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='63' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__56' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='64' column='1' id='type-id-880'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-693' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='64' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__59' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='67' column='1' id='type-id-881'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-688' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='67' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__60' size-in-bits='448' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='68' column='1' id='type-id-882'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-658' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='68' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__62' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='70' column='1' id='type-id-883'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-663' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='70' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__66' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='74' column='1' id='type-id-884'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-668' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='74' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__76' size-in-bits='576' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='84' column='1' id='type-id-885'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-682' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='84' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__94' size-in-bits='576' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='102' column='1' id='type-id-886'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-675' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='102' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__115' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='123' column='1' id='type-id-887'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='123' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-661' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='123' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__140' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='148' column='1' id='type-id-888'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-669' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='148' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__182' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='190' column='1' id='type-id-889'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='190' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-665' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='190' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__214' size-in-bits='640' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='222' column='1' id='type-id-890'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='222' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-684' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='222' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__243' size-in-bits='384' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='251' column='1' id='type-id-891'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='251' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-687' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='251' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__258' size-in-bits='576' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='266' column='1' id='type-id-892'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='266' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-677' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='266' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__307' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='315' column='1' id='type-id-893'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='315' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-671' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='315' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__685' size-in-bits='576' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='693' column='1' id='type-id-894'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_ascii' type-id='type-id-792' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='693' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_data' type-id='type-id-679' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='693' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__741' size-in-bits='512' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='753' column='1' id='type-id-596'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_latin1' type-id='type-id-795' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='754' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='_data' type-id='type-id-680' visibility='default' filepath='./Include/internal/pycore_global_strings.h' line='755' column='1'/> + </data-member> + </class-decl> + <class-decl name='PyHamtNode' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-895' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='38' column='1' id='type-id-896'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='39' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyHamtNode' type-id='type-id-896' filepath='./Include/internal/pycore_hamt.h' line='40' column='1' id='type-id-895'/> + <class-decl name='PyHamtObject' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-865' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='44' column='1' id='type-id-897'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='h_root' type-id='type-id-898' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='h_weakreflist' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='h_count' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='48' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyHamtObject' type-id='type-id-897' filepath='./Include/internal/pycore_hamt.h' line='49' column='1' id='type-id-865'/> + <class-decl name='PyHamtNode_Bitmap' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-861' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='52' column='1' id='type-id-899'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-321' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='b_bitmap' type-id='type-id-352' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='b_array' type-id='type-id-353' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='55' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyHamtNode_Bitmap' type-id='type-id-899' filepath='./Include/internal/pycore_hamt.h' line='56' column='1' id='type-id-861'/> + <class-decl name='_Py_slist_item_s' size-in-bits='64' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='13' column='1' id='type-id-900'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next' type-id='type-id-901' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='14' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_slist_item_t' type-id='type-id-900' filepath='./Include/internal/pycore_hashtable.h' line='15' column='1' id='type-id-902'/> + <class-decl name='_Py_slist_t' size-in-bits='64' is-struct='yes' naming-typedef-id='type-id-903' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='17' column='1' id='type-id-904'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='head' type-id='type-id-905' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='18' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_slist_t' type-id='type-id-904' filepath='./Include/internal/pycore_hashtable.h' line='19' column='1' id='type-id-903'/> + <class-decl name='_Py_hashtable_entry_t' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-906' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='28' column='1' id='type-id-907'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_Py_slist_item' type-id='type-id-902' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='key_hash' type-id='type-id-908' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='key' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='value' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='34' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_hashtable_entry_t' type-id='type-id-907' filepath='./Include/internal/pycore_hashtable.h' line='35' column='1' id='type-id-906'/> + <typedef-decl name='_Py_hashtable_t' type-id='type-id-909' filepath='./Include/internal/pycore_hashtable.h' line='42' column='1' id='type-id-910'/> + <typedef-decl name='_Py_hashtable_hash_func' type-id='type-id-911' filepath='./Include/internal/pycore_hashtable.h' line='44' column='1' id='type-id-912'/> + <typedef-decl name='_Py_hashtable_compare_func' type-id='type-id-78' filepath='./Include/internal/pycore_hashtable.h' line='45' column='1' id='type-id-913'/> + <typedef-decl name='_Py_hashtable_destroy_func' type-id='type-id-758' filepath='./Include/internal/pycore_hashtable.h' line='46' column='1' id='type-id-914'/> + <typedef-decl name='_Py_hashtable_get_entry_func' type-id='type-id-915' filepath='./Include/internal/pycore_hashtable.h' line='47' column='1' id='type-id-916'/> + <class-decl name='_Py_hashtable_allocator_t' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-917' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='50' column='1' id='type-id-918'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='malloc' type-id='type-id-919' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='free' type-id='type-id-758' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='55' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_hashtable_allocator_t' type-id='type-id-918' filepath='./Include/internal/pycore_hashtable.h' line='56' column='1' id='type-id-917'/> + <class-decl name='_Py_hashtable_t' size-in-bits='640' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='60' column='1' id='type-id-909'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='nentries' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='nbuckets' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='buckets' type-id='type-id-920' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='get_entry_func' type-id='type-id-916' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='hash_func' type-id='type-id-912' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='compare_func' type-id='type-id-913' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='key_destroy_func' type-id='type-id-914' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='value_destroy_func' type-id='type-id-914' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='alloc' type-id='type-id-917' visibility='default' filepath='./Include/internal/pycore_hashtable.h' line='70' column='1'/> + </data-member> + </class-decl> + <class-decl name='_import_runtime_state' size-in-bits='2624' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_import.h' line='9' column='1' id='type-id-921'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='inittab' type-id='type-id-922' visibility='default' filepath='./Include/internal/pycore_import.h' line='11' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='last_module_index' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_import.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='extensions' type-id='type-id-923' visibility='default' filepath='./Include/internal/pycore_import.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2560'> + <var-decl name='pkgcontext' type-id='type-id-12' visibility='default' filepath='./Include/internal/pycore_import.h' line='33' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__8' size-in-bits='2432' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_import.h' line='17' column='1' id='type-id-923'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='main_tstate' type-id='type-id-924' visibility='default' filepath='./Include/internal/pycore_import.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2304'> + <var-decl name='mutex' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_import.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2368'> + <var-decl name='dict' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_import.h' line='30' column='1'/> + </data-member> + </class-decl> + <class-decl name='_import_state' size-in-bits='768' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_import.h' line='36' column='1' id='type-id-925'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='modules' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_import.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='modules_by_index' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_import.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='importlib' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_import.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='override_frozen_modules' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_import.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='override_multi_interp_extensions_check' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_import.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='dlopenflags' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_import.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='import_func' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_import.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='lock' type-id='type-id-926' visibility='default' filepath='./Include/internal/pycore_import.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='find_and_load' type-id='type-id-927' visibility='default' filepath='./Include/internal/pycore_import.h' line='80' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__742' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_import.h' line='70' column='1' id='type-id-926'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='mutex' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_import.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='thread' type-id='type-id-28' visibility='default' filepath='./Include/internal/pycore_import.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_import.h' line='73' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__743' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_import.h' line='76' column='1' id='type-id-927'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='import_level' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_import.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='accumulated' type-id='type-id-788' visibility='default' filepath='./Include/internal/pycore_import.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='header' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_import.h' line='79' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_long_state' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='38' column='1' id='type-id-928'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='max_str_digits' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_interp.h' line='39' column='1'/> + </data-member> + </class-decl> + <class-decl name='_is' size-in-bits='3093248' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='49' column='1' id='type-id-929'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ceval' type-id='type-id-821' visibility='default' filepath='./Include/internal/pycore_interp.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4608'> + <var-decl name='next' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_interp.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4672'> + <var-decl name='monitoring_version' type-id='type-id-117' visibility='default' filepath='./Include/internal/pycore_interp.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4736'> + <var-decl name='last_restart_version' type-id='type-id-117' visibility='default' filepath='./Include/internal/pycore_interp.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4800'> + <var-decl name='threads' type-id='type-id-930' visibility='default' filepath='./Include/internal/pycore_interp.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5056'> + <var-decl name='runtime' type-id='type-id-931' visibility='default' filepath='./Include/internal/pycore_interp.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5120'> + <var-decl name='id' type-id='type-id-377' visibility='default' filepath='./Include/internal/pycore_interp.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5184'> + <var-decl name='id_refcount' type-id='type-id-377' visibility='default' filepath='./Include/internal/pycore_interp.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5248'> + <var-decl name='requires_idref' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_interp.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5312'> + <var-decl name='id_mutex' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_interp.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5376'> + <var-decl name='_initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_interp.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5408'> + <var-decl name='finalizing' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_interp.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5440'> + <var-decl name='_finalizing' type-id='type-id-807' visibility='default' filepath='./Include/internal/pycore_interp.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5504'> + <var-decl name='obmalloc' type-id='type-id-932' visibility='default' filepath='./Include/internal/pycore_interp.h' line='94' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2111488'> + <var-decl name='gc' type-id='type-id-852' visibility='default' filepath='./Include/internal/pycore_interp.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2113408'> + <var-decl name='imports' type-id='type-id-925' visibility='default' filepath='./Include/internal/pycore_interp.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114176'> + <var-decl name='sysdict' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114240'> + <var-decl name='builtins' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='103' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114304'> + <var-decl name='codec_search_path' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='105' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114368'> + <var-decl name='codec_search_cache' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114432'> + <var-decl name='codec_error_registry' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114496'> + <var-decl name='codecs_initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_interp.h' line='108' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2114560'> + <var-decl name='config' type-id='type-id-258' visibility='default' filepath='./Include/internal/pycore_interp.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118016'> + <var-decl name='feature_flags' type-id='type-id-28' visibility='default' filepath='./Include/internal/pycore_interp.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118080'> + <var-decl name='dict' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='113' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118144'> + <var-decl name='sysdict_copy' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='115' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118208'> + <var-decl name='builtins_copy' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118272'> + <var-decl name='eval_frame' type-id='type-id-778' visibility='default' filepath='./Include/internal/pycore_interp.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118336'> + <var-decl name='func_watchers' type-id='type-id-580' visibility='default' filepath='./Include/internal/pycore_interp.h' line='120' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118848'> + <var-decl name='active_func_watchers' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_interp.h' line='122' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118912'> + <var-decl name='co_extra_user_count' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_interp.h' line='124' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2118976'> + <var-decl name='co_extra_freefuncs' type-id='type-id-626' visibility='default' filepath='./Include/internal/pycore_interp.h' line='125' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2135296'> + <var-decl name='before_forkers' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='128' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2135360'> + <var-decl name='after_forkers_parent' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='129' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2135424'> + <var-decl name='after_forkers_child' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2135488'> + <var-decl name='warnings' type-id='type-id-933' visibility='default' filepath='./Include/internal/pycore_interp.h' line='133' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2135744'> + <var-decl name='atexit' type-id='type-id-804' visibility='default' filepath='./Include/internal/pycore_interp.h' line='134' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2136000'> + <var-decl name='audit_hooks' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2136064'> + <var-decl name='type_watchers' type-id='type-id-589' visibility='default' filepath='./Include/internal/pycore_interp.h' line='137' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2136576'> + <var-decl name='code_watchers' type-id='type-id-576' visibility='default' filepath='./Include/internal/pycore_interp.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2137088'> + <var-decl name='active_code_watchers' type-id='type-id-325' visibility='default' filepath='./Include/internal/pycore_interp.h' line='140' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2137120'> + <var-decl name='object_state' type-id='type-id-934' visibility='default' filepath='./Include/internal/pycore_interp.h' line='142' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2137152'> + <var-decl name='unicode' type-id='type-id-935' visibility='default' filepath='./Include/internal/pycore_interp.h' line='143' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2137600'> + <var-decl name='float_state' type-id='type-id-845' visibility='default' filepath='./Include/internal/pycore_interp.h' line='144' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2137728'> + <var-decl name='long_state' type-id='type-id-928' visibility='default' filepath='./Include/internal/pycore_interp.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2137792'> + <var-decl name='dtoa' type-id='type-id-831' visibility='default' filepath='./Include/internal/pycore_interp.h' line='146' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2156864'> + <var-decl name='func_state' type-id='type-id-849' visibility='default' filepath='./Include/internal/pycore_interp.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2156928'> + <var-decl name='slice_cache' type-id='type-id-424' visibility='default' filepath='./Include/internal/pycore_interp.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2156992'> + <var-decl name='tuple' type-id='type-id-936' visibility='default' filepath='./Include/internal/pycore_interp.h' line='152' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2158912'> + <var-decl name='list' type-id='type-id-937' visibility='default' filepath='./Include/internal/pycore_interp.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2164096'> + <var-decl name='dict_state' type-id='type-id-829' visibility='default' filepath='./Include/internal/pycore_interp.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2175040'> + <var-decl name='async_gen' type-id='type-id-854' visibility='default' filepath='./Include/internal/pycore_interp.h' line='155' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2185408'> + <var-decl name='context' type-id='type-id-826' visibility='default' filepath='./Include/internal/pycore_interp.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2185536'> + <var-decl name='exc_state' type-id='type-id-832' visibility='default' filepath='./Include/internal/pycore_interp.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2185792'> + <var-decl name='ast' type-id='type-id-797' visibility='default' filepath='./Include/internal/pycore_interp.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2201408'> + <var-decl name='types' type-id='type-id-938' visibility='default' filepath='./Include/internal/pycore_interp.h' line='160' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3077568'> + <var-decl name='callable_cache' type-id='type-id-823' visibility='default' filepath='./Include/internal/pycore_interp.h' line='161' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3077824'> + <var-decl name='interpreter_trampoline' type-id='type-id-328' visibility='default' filepath='./Include/internal/pycore_interp.h' line='162' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3077888'> + <var-decl name='monitors' type-id='type-id-704' visibility='default' filepath='./Include/internal/pycore_interp.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3078000'> + <var-decl name='f_opcode_trace_set' type-id='type-id-614' visibility='default' filepath='./Include/internal/pycore_interp.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3078008'> + <var-decl name='sys_profile_initialized' type-id='type-id-614' visibility='default' filepath='./Include/internal/pycore_interp.h' line='166' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3078016'> + <var-decl name='sys_trace_initialized' type-id='type-id-614' visibility='default' filepath='./Include/internal/pycore_interp.h' line='167' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3078080'> + <var-decl name='sys_profiling_threads' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_interp.h' line='168' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3078144'> + <var-decl name='sys_tracing_threads' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_interp.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3078208'> + <var-decl name='monitoring_callables' type-id='type-id-585' visibility='default' filepath='./Include/internal/pycore_interp.h' line='170' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3086400'> + <var-decl name='monitoring_tool_names' type-id='type-id-584' visibility='default' filepath='./Include/internal/pycore_interp.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3086912'> + <var-decl name='cached_objects' type-id='type-id-862' visibility='default' filepath='./Include/internal/pycore_interp.h' line='173' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3088192'> + <var-decl name='static_objects' type-id='type-id-863' visibility='default' filepath='./Include/internal/pycore_interp.h' line='174' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3089280'> + <var-decl name='_gil' type-id='type-id-855' visibility='default' filepath='./Include/internal/pycore_interp.h' line='189' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3090944'> + <var-decl name='_initial_thread' type-id='type-id-924' visibility='default' filepath='./Include/internal/pycore_interp.h' line='192' column='1'/> + </data-member> + </class-decl> + <class-decl name='pythreads' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='57' column='1' id='type-id-930'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next_unique_id' type-id='type-id-117' visibility='default' filepath='./Include/internal/pycore_interp.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='head' type-id='type-id-177' visibility='default' filepath='./Include/internal/pycore_interp.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='count' type-id='type-id-47' visibility='default' filepath='./Include/internal/pycore_interp.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='stacksize' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_interp.h' line='67' column='1'/> + </data-member> + </class-decl> + <class-decl name='_xidregitem' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='220' column='1' id='type-id-939'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='prev' type-id='type-id-940' visibility='default' filepath='./Include/internal/pycore_interp.h' line='221' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='next' type-id='type-id-940' visibility='default' filepath='./Include/internal/pycore_interp.h' line='222' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='cls' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='223' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='getdata' type-id='type-id-785' visibility='default' filepath='./Include/internal/pycore_interp.h' line='224' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_list_state' size-in-bits='5184' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_list.h' line='31' column='1' id='type-id-937'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='free_list' type-id='type-id-581' visibility='default' filepath='./Include/internal/pycore_list.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5120'> + <var-decl name='numfree' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_list.h' line='34' column='1'/> + </data-member> + </class-decl> + <class-decl name='_py_object_runtime_state' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_object_state.h' line='11' column='1' id='type-id-941'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_not_used' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_object_state.h' line='15' column='1'/> + </data-member> + </class-decl> + <class-decl name='_py_object_state' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_object_state.h' line='19' column='1' id='type-id-934'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_not_used' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_object_state.h' line='23' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='pymem_uint' type-id='type-id-95' filepath='./Include/internal/pycore_obmalloc.h' line='12' column='1' id='type-id-942'/> + <typedef-decl name='pymem_block' type-id='type-id-325' filepath='./Include/internal/pycore_obmalloc.h' line='251' column='1' id='type-id-943'/> + <class-decl name='pool_header' size-in-bits='384' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='254' column='1' id='type-id-944'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ref' type-id='type-id-945' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='256' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='freeblock' type-id='type-id-946' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='257' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='nextpool' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='258' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='prevpool' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='259' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='arenaindex' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='260' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='szidx' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='261' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='nextoffset' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='262' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='maxnextoffset' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='263' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__3' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='255' column='1' id='type-id-945'> + <data-member access='public'> + <var-decl name='_padding' type-id='type-id-946' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='255' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='count' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='256' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='poolp' type-id='type-id-947' filepath='./Include/internal/pycore_obmalloc.h' line='266' column='1' id='type-id-636'/> + <class-decl name='arena_object' size-in-bits='384' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='269' column='1' id='type-id-948'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='address' type-id='type-id-747' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='275' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='pool_address' type-id='type-id-946' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='278' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='nfreepools' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='283' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='ntotalpools' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='286' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='freepools' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='289' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='nextarena' type-id='type-id-610' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='305' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='prevarena' type-id='type-id-610' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='306' column='1'/> + </data-member> + </class-decl> + <class-decl name='_obmalloc_pools' size-in-bits='4096' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='419' column='1' id='type-id-949'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='used' type-id='type-id-637' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='420' column='1'/> + </data-member> + </class-decl> + <class-decl name='_obmalloc_mgmt' size-in-bits='4672' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='477' column='1' id='type-id-950'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='arenas' type-id='type-id-610' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='479' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='maxarenas' type-id='type-id-942' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='481' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='unused_arena_objects' type-id='type-id-610' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='486' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='usable_arenas' type-id='type-id-610' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='491' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='nfp2lasta' type-id='type-id-611' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='494' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4416'> + <var-decl name='narenas_currently_allocated' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='497' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4480'> + <var-decl name='ntimes_arena_allocated' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='500' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4544'> + <var-decl name='narenas_highwater' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='502' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4608'> + <var-decl name='raw_allocated_blocks' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='504' column='1'/> + </data-member> + </class-decl> + <class-decl name='arena_coverage_t' size-in-bits='64' is-struct='yes' naming-typedef-id='type-id-602' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='619' column='1' id='type-id-951'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tail_hi' type-id='type-id-952' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='620' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='tail_lo' type-id='type-id-952' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='621' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='arena_coverage_t' type-id='type-id-951' filepath='./Include/internal/pycore_obmalloc.h' line='622' column='1' id='type-id-602'/> + <class-decl name='arena_map_bot' size-in-bits='1048576' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='624' column='1' id='type-id-953'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='arenas' type-id='type-id-603' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='629' column='1'/> + </data-member> + </class-decl> + <class-decl name='arena_map_mid' size-in-bits='2097152' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='633' column='1' id='type-id-954'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ptrs' type-id='type-id-606' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='634' column='1'/> + </data-member> + </class-decl> + <class-decl name='arena_map_top' size-in-bits='2097152' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='637' column='1' id='type-id-955'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ptrs' type-id='type-id-609' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='638' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='arena_map_top_t' type-id='type-id-955' filepath='./Include/internal/pycore_obmalloc.h' line='639' column='1' id='type-id-956'/> + <class-decl name='_obmalloc_usage' size-in-bits='2097216' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='642' column='1' id='type-id-957'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='arena_map_root' type-id='type-id-956' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='648' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2097152'> + <var-decl name='arena_map_mid_count' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='650' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2097184'> + <var-decl name='arena_map_bot_count' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='651' column='1'/> + </data-member> + </class-decl> + <class-decl name='_obmalloc_global_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='660' column='1' id='type-id-958'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='dump_debug_stats' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='661' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='interpreter_leaks' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='662' column='1'/> + </data-member> + </class-decl> + <class-decl name='_obmalloc_state' size-in-bits='2105984' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='665' column='1' id='type-id-932'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='pools' type-id='type-id-949' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='666' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4096'> + <var-decl name='mgmt' type-id='type-id-950' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='667' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8768'> + <var-decl name='usage' type-id='type-id-957' visibility='default' filepath='./Include/internal/pycore_obmalloc.h' line='668' column='1'/> + </data-member> + </class-decl> + <class-decl name='_parser_runtime_state' size-in-bits='448' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_parser.h' line='21' column='1' id='type-id-959'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_not_used' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_parser.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='dummy_name' type-id='type-id-960' visibility='default' filepath='./Include/internal/pycore_parser.h' line='27' column='1'/> + </data-member> + </class-decl> + <class-decl name='pyhash_runtime_state' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_pyhash.h' line='9' column='1' id='type-id-961'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='urandom_cache' type-id='type-id-962' visibility='default' filepath='./Include/internal/pycore_pyhash.h' line='19' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__4' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_pyhash.h' line='10' column='1' id='type-id-962'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='fd' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_pyhash.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='st_dev' type-id='type-id-963' visibility='default' filepath='./Include/internal/pycore_pyhash.h' line='13' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='st_ino' type-id='type-id-964' visibility='default' filepath='./Include/internal/pycore_pyhash.h' line='14' column='1'/> + </data-member> + </class-decl> + <class-decl name='debug_alloc_api_t' size-in-bits='384' is-struct='yes' naming-typedef-id='type-id-965' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='14' column='1' id='type-id-966'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='api_id' type-id='type-id-48' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='alloc' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='17' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='debug_alloc_api_t' type-id='type-id-966' filepath='./Include/internal/pycore_pymem.h' line='18' column='1' id='type-id-965'/> + <class-decl name='_pymem_allocators' size-in-bits='2304' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='20' column='1' id='type-id-967'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='standard' type-id='type-id-968' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='debug' type-id='type-id-969' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='obj_arena' type-id='type-id-420' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='31' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__2' size-in-bits='960' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='21' column='1' id='type-id-968'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='raw' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='mem' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='obj' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='24' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__3' size-in-bits='1152' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='26' column='1' id='type-id-969'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='raw' type-id='type-id-965' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='mem' type-id='type-id-965' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='obj' type-id='type-id-965' visibility='default' filepath='./Include/internal/pycore_pymem.h' line='29' column='1'/> + </data-member> + </class-decl> + <class-decl name='_pythread_runtime_state' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_pythread.h' line='54' column='1' id='type-id-970'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_pythread.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_condattr_monotonic' type-id='type-id-971' visibility='default' filepath='./Include/internal/pycore_pythread.h' line='66' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__5' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_pythread.h' line='59' column='1' id='type-id-971'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ptr' type-id='type-id-972' visibility='default' filepath='./Include/internal/pycore_pythread.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='val' type-id='type-id-973' visibility='default' filepath='./Include/internal/pycore_pythread.h' line='64' column='1'/> + </data-member> + </class-decl> + <class-decl name='_getargs_runtime_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='30' column='1' id='type-id-974'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='mutex' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='static_parsers' type-id='type-id-262' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='32' column='1'/> + </data-member> + </class-decl> + <class-decl name='_gilstate_runtime_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='37' column='1' id='type-id-975'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='check_enabled' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='autoInterpreterState' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='45' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_AuditHookEntry' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='50' column='1' id='type-id-976'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next' type-id='type-id-977' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='hookCFunction' type-id='type-id-234' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='userData' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='53' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_AuditHookEntry' type-id='type-id-976' filepath='./Include/internal/pycore_runtime.h' line='54' column='1' id='type-id-978'/> + <class-decl name='pyruntimestate' size-in-bits='3700480' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='61' column='1' id='type-id-979'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='preinitializing' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='preinitialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='core_initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='_finalizing' type-id='type-id-807' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='allocators' type-id='type-id-967' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2560'> + <var-decl name='obmalloc' type-id='type-id-958' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2688'> + <var-decl name='pyhash_state' type-id='type-id-961' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2880'> + <var-decl name='time' type-id='type-id-980' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3008'> + <var-decl name='threads' type-id='type-id-970' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3200'> + <var-decl name='signals' type-id='type-id-981' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='11840'> + <var-decl name='interpreters' type-id='type-id-982' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12096'> + <var-decl name='xidregistry' type-id='type-id-983' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12224'> + <var-decl name='main_thread' type-id='type-id-28' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12288'> + <var-decl name='autoTSSkey' type-id='type-id-408' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12352'> + <var-decl name='trashTSSkey' type-id='type-id-408' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='124' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12416'> + <var-decl name='orig_argv' type-id='type-id-739' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='126' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12544'> + <var-decl name='parser' type-id='type-id-959' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='128' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12992'> + <var-decl name='atexit' type-id='type-id-798' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='15104'> + <var-decl name='imports' type-id='type-id-921' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='132' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='17728'> + <var-decl name='ceval' type-id='type-id-816' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='133' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18304'> + <var-decl name='gilstate' type-id='type-id-975' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='134' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18432'> + <var-decl name='getargs' type-id='type-id-974' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='135' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18560'> + <var-decl name='fileutils' type-id='type-id-841' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18624'> + <var-decl name='faulthandler' type-id='type-id-837' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='137' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='19968'> + <var-decl name='tracemalloc' type-id='type-id-984' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='138' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21824'> + <var-decl name='preconfig' type-id='type-id-742' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='140' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22144'> + <var-decl name='open_code_hook' type-id='type-id-355' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='144' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22208'> + <var-decl name='open_code_userdata' type-id='type-id-22' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='145' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22272'> + <var-decl name='audit_hook_head' type-id='type-id-977' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='146' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22336'> + <var-decl name='object_state' type-id='type-id-941' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22368'> + <var-decl name='float_state' type-id='type-id-844' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='149' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22464'> + <var-decl name='unicode_state' type-id='type-id-985' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='150' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22592'> + <var-decl name='types' type-id='type-id-986' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='151' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22656'> + <var-decl name='static_objects' type-id='type-id-858' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='607232'> + <var-decl name='_main_interpreter' type-id='type-id-987' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='171' column='1'/> + </data-member> + </class-decl> + <class-decl name='pyinterpreters' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='94' column='1' id='type-id-982'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='mutex' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='head' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='main' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='next_id' type-id='type-id-377' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='110' column='1'/> + </data-member> + </class-decl> + <class-decl name='_xidregistry' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='113' column='1' id='type-id-983'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='mutex' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='114' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='head' type-id='type-id-940' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='115' column='1'/> + </data-member> + </class-decl> + <class-decl name='_signals_runtime_state' size-in-bits='8640' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_signal.h' line='37' column='1' id='type-id-981'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='handlers' type-id='type-id-699' visibility='default' filepath='./Include/internal/pycore_signal.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8320'> + <var-decl name='wakeup' type-id='type-id-988' visibility='default' filepath='./Include/internal/pycore_signal.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8384'> + <var-decl name='is_tripped' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_signal.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8448'> + <var-decl name='default_handler' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_signal.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8512'> + <var-decl name='ignore_handler' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_signal.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='8576'> + <var-decl name='unhandled_keyboard_interrupt' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_signal.h' line='78' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__6' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_signal.h' line='38' column='1' id='type-id-989'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tripped' type-id='type-id-809' visibility='default' filepath='./Include/internal/pycore_signal.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='func' type-id='type-id-807' visibility='default' filepath='./Include/internal/pycore_signal.h' line='43' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__7' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_signal.h' line='46' column='1' id='type-id-990'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='fd' type-id='type-id-991' visibility='default' filepath='./Include/internal/pycore_signal.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='warn_on_full_buffer' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_signal.h' line='57' column='1'/> + </data-member> + </class-decl> + <class-decl name='_time_runtime_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_time.h' line='12' column='1' id='type-id-980'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ticks_per_second_initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_time.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ticks_per_second' type-id='type-id-47' visibility='default' filepath='./Include/internal/pycore_time.h' line='15' column='1'/> + </data-member> + </class-decl> + <class-decl name='_PyTraceMalloc_Config' size-in-bits='96' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='18' column='1' id='type-id-992'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='initialized' type-id='type-id-993' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='tracing' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='max_nframe' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='33' column='1'/> + </data-member> + </class-decl> + <enum-decl name='__anonymous_enum__' is-anonymous='yes' filepath='./Include/internal/pycore_tracemalloc.h' line='21' column='1' id='type-id-993'> + <underlying-type type-id='type-id-24'/> + <enumerator name='TRACEMALLOC_NOT_INITIALIZED' value='0'/> + <enumerator name='TRACEMALLOC_INITIALIZED' value='1'/> + <enumerator name='TRACEMALLOC_FINALIZED' value='2'/> + </enum-decl> + <class-decl name='tracemalloc_frame' size-in-bits='96' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='47' column='1' id='type-id-644'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='filename' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='lineno' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='51' column='1'/> + </data-member> + </class-decl> + <class-decl name='tracemalloc_traceback' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='57' column='1' id='type-id-994'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='hash' type-id='type-id-908' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='nframe' type-id='type-id-707' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='80'> + <var-decl name='total_nframe' type-id='type-id-707' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='frames' type-id='type-id-645' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='63' column='1'/> + </data-member> + </class-decl> + <class-decl name='_tracemalloc_runtime_state' size-in-bits='1856' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='67' column='1' id='type-id-984'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='config' type-id='type-id-992' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='allocators' type-id='type-id-995' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='tables_lock' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='traced_memory' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='peak_traced_memory' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='filenames' type-id='type-id-996' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='traceback' type-id='type-id-997' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='tracebacks' type-id='type-id-996' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='traces' type-id='type-id-996' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='domains' type-id='type-id-996' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='empty_traceback' type-id='type-id-994' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='104' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='reentrant_key' type-id='type-id-408' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='106' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__20' size-in-bits='960' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='71' column='1' id='type-id-995'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='mem' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='raw' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='obj' type-id='type-id-417' visibility='default' filepath='./Include/internal/pycore_tracemalloc.h' line='74' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_tuple_state' size-in-bits='1920' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_tuple.h' line='47' column='1' id='type-id-936'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='free_list' type-id='type-id-587' visibility='default' filepath='./Include/internal/pycore_tuple.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='numfree' type-id='type-id-633' visibility='default' filepath='./Include/internal/pycore_tuple.h' line='58' column='1'/> + </data-member> + </class-decl> + <class-decl name='_types_runtime_state' size-in-bits='32' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='19' column='1' id='type-id-986'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next_version_tag' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='23' column='1'/> + </data-member> + </class-decl> + <class-decl name='type_cache_entry' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='29' column='1' id='type-id-646'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='version' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='name' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='value' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='32' column='1'/> + </data-member> + </class-decl> + <class-decl name='type_cache' size-in-bits='786432' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='37' column='1' id='type-id-998'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='hashtable' type-id='type-id-647' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='38' column='1'/> + </data-member> + </class-decl> + <class-decl name='static_builtin_state' size-in-bits='448' is-struct='yes' naming-typedef-id='type-id-410' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='45' column='1' id='type-id-999'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='type' type-id='type-id-1' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='readying' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='ready' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='tp_dict' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='tp_bases' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='tp_mro' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='tp_subclasses' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='tp_weaklist' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='59' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='static_builtin_state' type-id='type-id-999' filepath='./Include/internal/pycore_typeobject.h' line='60' column='1' id='type-id-410'/> + <class-decl name='types_state' size-in-bits='876160' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='62' column='1' id='type-id-938'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='next_version_tag' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type_cache' type-id='type-id-998' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='786496'> + <var-decl name='num_builtins_initialized' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='786560'> + <var-decl name='builtins' type-id='type-id-642' visibility='default' filepath='./Include/internal/pycore_typeobject.h' line='70' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='pytype_slotdef' type-id='type-id-333' filepath='./Include/internal/pycore_typeobject.h' line='89' column='1' id='type-id-1000'/> + <class-decl name='_PyUnicode_Name_CAPI' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1001' visibility='default' filepath='./Include/internal/pycore_ucnhash.h' line='16' column='1' id='type-id-1002'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='getname' type-id='type-id-1003' visibility='default' filepath='./Include/internal/pycore_ucnhash.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='getcode' type-id='type-id-1004' visibility='default' filepath='./Include/internal/pycore_ucnhash.h' line='26' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyUnicode_Name_CAPI' type-id='type-id-1002' filepath='./Include/internal/pycore_ucnhash.h' line='29' column='1' id='type-id-1001'/> + <class-decl name='_Py_unicode_runtime_ids' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='29' column='1' id='type-id-1005'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='lock' type-id='type-id-820' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='next_index' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='33' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_unicode_runtime_state' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='36' column='1' id='type-id-985'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ids' type-id='type-id-1005' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='37' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_unicode_fs_codec' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='42' column='1' id='type-id-1006'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='encoding' type-id='type-id-15' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='utf8' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='errors' type-id='type-id-15' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='error_handler' type-id='type-id-442' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='46' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_unicode_ids' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='49' column='1' id='type-id-1007'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='array' type-id='type-id-233' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='51' column='1'/> + </data-member> + </class-decl> + <class-decl name='_Py_unicode_state' size-in-bits='448' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='54' column='1' id='type-id-935'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='fs_codec' type-id='type-id-1006' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='ucnhash_capi' type-id='type-id-1008' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='ids' type-id='type-id-1007' visibility='default' filepath='./Include/internal/pycore_unicodeobject.h' line='60' column='1'/> + </data-member> + </class-decl> + <class-decl name='_warnings_runtime_state' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_warnings.h' line='11' column='1' id='type-id-933'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='filters' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_warnings.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='once_registry' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_warnings.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='default_action' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_warnings.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='filters_version' type-id='type-id-47' visibility='default' filepath='./Include/internal/pycore_warnings.h' line='17' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Py_uhash_t' type-id='type-id-19' filepath='./Include/pyport.h' line='148' column='1' id='type-id-908'/> + <typedef-decl name='PyThread_type_lock' type-id='type-id-22' filepath='./Include/pythread.h' line='4' column='1' id='type-id-820'/> + <typedef-decl name='Py_tss_t' type-id='type-id-786' filepath='./Include/pythread.h' line='113' column='1' id='type-id-408'/> + <typedef-decl name='PyLongObject' type-id='type-id-749' filepath='./Include/pytypedefs.h' line='19' column='1' id='type-id-240'/> + <typedef-decl name='PyCodeObject' type-id='type-id-717' filepath='./Include/pytypedefs.h' line='21' column='1' id='type-id-1009'/> + <typedef-decl name='PyFrameObject' type-id='type-id-847' filepath='./Include/pytypedefs.h' line='22' column='1' id='type-id-1010'/> + <typedef-decl name='PyThreadState' type-id='type-id-774' filepath='./Include/pytypedefs.h' line='24' column='1' id='type-id-924'/> + <typedef-decl name='PyInterpreterState' type-id='type-id-929' filepath='./Include/pytypedefs.h' line='25' column='1' id='type-id-987'/> + <class-decl name='PySliceObject' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-1011' visibility='default' filepath='./Include/sliceobject.h' line='22' column='1' id='type-id-1012'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/sliceobject.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='start' type-id='type-id-2' visibility='default' filepath='./Include/sliceobject.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='stop' type-id='type-id-2' visibility='default' filepath='./Include/sliceobject.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='step' type-id='type-id-2' visibility='default' filepath='./Include/sliceobject.h' line='24' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PySliceObject' type-id='type-id-1012' filepath='./Include/sliceobject.h' line='25' column='1' id='type-id-1011'/> + <typedef-decl name='__sighandler_t' type-id='type-id-1013' filepath='/usr/include/signal.h' line='72' column='1' id='type-id-1014'/> + <typedef-decl name='uintptr_t' type-id='type-id-28' filepath='/usr/include/stdint.h' line='90' column='1' id='type-id-747'/> + <union-decl name='__atomic_wide_counter' size-in-bits='64' naming-typedef-id='type-id-1015' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='25' column='1' id='type-id-1016'> + <data-member access='public'> + <var-decl name='__value64' type-id='type-id-387' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='27' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__value32' type-id='type-id-1017' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='32' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='28' column='1' id='type-id-1017'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__low' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='__high' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='31' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__atomic_wide_counter' type-id='type-id-1016' filepath='/usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h' line='33' column='1' id='type-id-1015'/> + <union-decl name='pthread_condattr_t' size-in-bits='32' naming-typedef-id='type-id-973' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='41' column='1' id='type-id-1018'> + <data-member access='public'> + <var-decl name='__size' type-id='type-id-619' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='43' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__align' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='44' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='pthread_condattr_t' type-id='type-id-1018' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='45' column='1' id='type-id-973'/> + <typedef-decl name='pthread_key_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='49' column='1' id='type-id-787'/> + <union-decl name='pthread_mutex_t' size-in-bits='320' naming-typedef-id='type-id-857' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='67' column='1' id='type-id-1019'> + <data-member access='public'> + <var-decl name='__data' type-id='type-id-1020' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='69' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__size' type-id='type-id-615' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='70' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__align' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='71' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='pthread_mutex_t' type-id='type-id-1019' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='72' column='1' id='type-id-857'/> + <union-decl name='pthread_cond_t' size-in-bits='384' naming-typedef-id='type-id-856' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='75' column='1' id='type-id-1021'> + <data-member access='public'> + <var-decl name='__data' type-id='type-id-1022' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='77' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__size' type-id='type-id-617' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='78' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__align' type-id='type-id-378' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='79' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='pthread_cond_t' type-id='type-id-1021' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='80' column='1' id='type-id-856'/> + <class-decl name='sigaction' size-in-bits='1216' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='27' column='1' id='type-id-834'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__sigaction_handler' type-id='type-id-1023' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='sa_mask' type-id='type-id-30' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='sa_flags' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='sa_restorer' type-id='type-id-227' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='52' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='31' column='1' id='type-id-1023'> + <data-member access='public'> + <var-decl name='sa_handler' type-id='type-id-1014' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='34' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='sa_sigaction' type-id='type-id-1024' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/sigaction.h' line='36' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='int8_t' type-id='type-id-1025' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-intn.h' line='24' column='1' id='type-id-370'/> + <typedef-decl name='int32_t' type-id='type-id-1026' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-intn.h' line='26' column='1' id='type-id-952'/> + <typedef-decl name='int64_t' type-id='type-id-1027' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-intn.h' line='27' column='1' id='type-id-377'/> + <typedef-decl name='uint8_t' type-id='type-id-1028' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h' line='24' column='1' id='type-id-325'/> + <typedef-decl name='uint16_t' type-id='type-id-1029' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h' line='25' column='1' id='type-id-707'/> + <typedef-decl name='uint64_t' type-id='type-id-1030' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h' line='27' column='1' id='type-id-117'/> + <class-decl name='__pthread_mutex_s' size-in-bits='320' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='22' column='1' id='type-id-1020'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__lock' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='__count' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='__owner' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='26' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='__nusers' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='__kind' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='__spins' type-id='type-id-71' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='176'> + <var-decl name='__elision' type-id='type-id-71' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='__list' type-id='type-id-1031' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_mutex.h' line='36' column='1'/> + </data-member> + </class-decl> + <class-decl name='__pthread_internal_list' size-in-bits='128' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='51' column='1' id='type-id-1032'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__prev' type-id='type-id-1033' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='__next' type-id='type-id-1033' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='54' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__pthread_list_t' type-id='type-id-1032' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='55' column='1' id='type-id-1031'/> + <class-decl name='__pthread_cond_s' size-in-bits='384' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='94' column='1' id='type-id-1022'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__wseq' type-id='type-id-1015' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='__g1_start' type-id='type-id-1015' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='__g_refs' type-id='type-id-696' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='__g_size' type-id='type-id-696' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='__g1_orig_size' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='__wrefs' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='__g_signals' type-id='type-id-696' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h' line='102' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__int8_t' type-id='type-id-1034' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='37' column='1' id='type-id-1025'/> + <typedef-decl name='__uint8_t' type-id='type-id-85' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='38' column='1' id='type-id-1028'/> + <typedef-decl name='__uint16_t' type-id='type-id-84' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='40' column='1' id='type-id-1029'/> + <typedef-decl name='__int32_t' type-id='type-id-8' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='41' column='1' id='type-id-1026'/> + <typedef-decl name='__int64_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='44' column='1' id='type-id-1027'/> + <typedef-decl name='__uint64_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='45' column='1' id='type-id-1030'/> + <typedef-decl name='__dev_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='145' column='1' id='type-id-187'/> + <typedef-decl name='__uid_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='146' column='1' id='type-id-125'/> + <typedef-decl name='__ino64_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='149' column='1' id='type-id-83'/> + <typedef-decl name='__pid_t' type-id='type-id-8' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='154' column='1' id='type-id-127'/> + <typedef-decl name='__clock_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='156' column='1' id='type-id-97'/> + <typedef-decl name='__sig_atomic_t' type-id='type-id-8' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='215' column='1' id='type-id-1035'/> + <class-decl name='__sigset_t' size-in-bits='1024' is-struct='yes' naming-typedef-id='type-id-30' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h' line='5' column='1' id='type-id-1036'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__val' type-id='type-id-697' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h' line='7' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__sigset_t' type-id='type-id-1036' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h' line='8' column='1' id='type-id-30'/> + <union-decl name='sigval' size-in-bits='64' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigval_t.h' line='24' column='1' id='type-id-1037'> + <data-member access='public'> + <var-decl name='sival_int' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigval_t.h' line='26' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='sival_ptr' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigval_t.h' line='27' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='__sigval_t' type-id='type-id-1037' filepath='/usr/include/x86_64-linux-gnu/bits/types/__sigval_t.h' line='30' column='1' id='type-id-1038'/> + <typedef-decl name='sig_atomic_t' type-id='type-id-1035' filepath='/usr/include/x86_64-linux-gnu/bits/types/sig_atomic_t.h' line='8' column='1' id='type-id-991'/> + <class-decl name='siginfo_t' size-in-bits='1024' is-struct='yes' naming-typedef-id='type-id-1039' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='36' column='1' id='type-id-1040'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_signo' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='si_errno' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='si_code' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='__pad0' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='_sifields' type-id='type-id-1041' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='123' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__1' size-in-bits='896' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='51' column='1' id='type-id-1041'> + <data-member access='public'> + <var-decl name='_pad' type-id='type-id-634' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='53' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_kill' type-id='type-id-1042' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='60' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_timer' type-id='type-id-1043' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='68' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_rt' type-id='type-id-1044' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='76' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_sigchld' type-id='type-id-1045' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='86' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_sigfault' type-id='type-id-1046' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='105' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_sigpoll' type-id='type-id-1047' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='112' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_sigsys' type-id='type-id-1048' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='121' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__13' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='56' column='1' id='type-id-1042'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_pid' type-id='type-id-127' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='si_uid' type-id='type-id-125' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='59' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__14' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='63' column='1' id='type-id-1043'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_tid' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='si_overrun' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='si_sigval' type-id='type-id-1038' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='67' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__15' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='71' column='1' id='type-id-1044'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_pid' type-id='type-id-127' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='si_uid' type-id='type-id-125' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='si_sigval' type-id='type-id-1038' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='75' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__16' size-in-bits='256' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='79' column='1' id='type-id-1045'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_pid' type-id='type-id-127' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='si_uid' type-id='type-id-125' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='si_status' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='si_utime' type-id='type-id-97' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='si_stime' type-id='type-id-97' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='85' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__17' size-in-bits='256' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='89' column='1' id='type-id-1046'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_addr' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='si_addr_lsb' type-id='type-id-71' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='_bounds' type-id='type-id-1049' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='104' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__2' size-in-bits='128' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='94' column='1' id='type-id-1049'> + <data-member access='public'> + <var-decl name='_addr_bnd' type-id='type-id-1050' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='101' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='_pkey' type-id='type-id-1051' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='103' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__18' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='97' column='1' id='type-id-1050'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_lower' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_upper' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='100' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__19' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='108' column='1' id='type-id-1047'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='si_band' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='si_fd' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='111' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__20' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='116' column='1' id='type-id-1048'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_call_addr' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_syscall' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='119' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='_arch' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='120' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='siginfo_t' type-id='type-id-1040' filepath='/usr/include/x86_64-linux-gnu/bits/types/siginfo_t.h' line='124' column='1' id='type-id-1039'/> + <class-decl name='stack_t' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-38' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/stack_t.h' line='26' column='1' id='type-id-1052'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ss_sp' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/stack_t.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ss_flags' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/stack_t.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ss_size' type-id='type-id-19' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/stack_t.h' line='30' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='stack_t' type-id='type-id-1052' filepath='/usr/include/x86_64-linux-gnu/bits/types/stack_t.h' line='31' column='1' id='type-id-38'/> + <typedef-decl name='ino_t' type-id='type-id-83' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='49' column='1' id='type-id-964'/> + <typedef-decl name='dev_t' type-id='type-id-187' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='59' column='1' id='type-id-963'/> + <typedef-decl name='wchar_t' type-id='type-id-8' filepath='/usr/lib/gcc/x86_64-linux-gnu/11/include/stddef.h' line='321' column='1' id='type-id-422'/> + <pointer-type-def type-id='type-id-830' size-in-bits='64' id='type-id-570'/> + <qualified-type-def type-id='type-id-229' restrict='yes' id='type-id-412'/> + <pointer-type-def type-id='type-id-620' size-in-bits='64' id='type-id-573'/> + <pointer-type-def type-id='type-id-756' size-in-bits='64' id='type-id-833'/> + <pointer-type-def type-id='type-id-1009' size-in-bits='64' id='type-id-328'/> + <pointer-type-def type-id='type-id-724' size-in-bits='64' id='type-id-827'/> + <pointer-type-def type-id='type-id-348' size-in-bits='64' id='type-id-346'/> + <pointer-type-def type-id='type-id-343' size-in-bits='64' id='type-id-340'/> + <pointer-type-def type-id='type-id-349' size-in-bits='64' id='type-id-347'/> + <pointer-type-def type-id='type-id-731' size-in-bits='64' id='type-id-846'/> + <pointer-type-def type-id='type-id-1010' size-in-bits='64' id='type-id-365'/> + <pointer-type-def type-id='type-id-733' size-in-bits='64' id='type-id-310'/> + <pointer-type-def type-id='type-id-850' size-in-bits='64' id='type-id-853'/> + <pointer-type-def type-id='type-id-895' size-in-bits='64' id='type-id-898'/> + <pointer-type-def type-id='type-id-865' size-in-bits='64' id='type-id-828'/> + <pointer-type-def type-id='type-id-987' size-in-bits='64' id='type-id-20'/> + <pointer-type-def type-id='type-id-744' size-in-bits='64' id='type-id-249'/> + <pointer-type-def type-id='type-id-400' size-in-bits='64' id='type-id-390'/> + <pointer-type-def type-id='type-id-1053' size-in-bits='64' id='type-id-725'/> + <pointer-type-def type-id='type-id-1054' size-in-bits='64' id='type-id-777'/> + <pointer-type-def type-id='type-id-1055' size-in-bits='64' id='type-id-781'/> + <pointer-type-def type-id='type-id-1011' size-in-bits='64' id='type-id-424'/> + <pointer-type-def type-id='type-id-924' size-in-bits='64' id='type-id-177'/> + <pointer-type-def type-id='type-id-790' size-in-bits='64' id='type-id-586'/> + <pointer-type-def type-id='type-id-250' size-in-bits='64' id='type-id-440'/> + <pointer-type-def type-id='type-id-750' size-in-bits='64' id='type-id-262'/> + <pointer-type-def type-id='type-id-621' size-in-bits='64' id='type-id-592'/> + <pointer-type-def type-id='type-id-765' size-in-bits='64' id='type-id-766'/> + <pointer-type-def type-id='type-id-709' size-in-bits='64' id='type-id-718'/> + <pointer-type-def type-id='type-id-711' size-in-bits='64' id='type-id-716'/> + <pointer-type-def type-id='type-id-713' size-in-bits='64' id='type-id-719'/> + <pointer-type-def type-id='type-id-780' size-in-bits='64' id='type-id-1056'/> + <pointer-type-def type-id='type-id-369' size-in-bits='64' id='type-id-376'/> + <pointer-type-def type-id='type-id-371' size-in-bits='64' id='type-id-375'/> + <pointer-type-def type-id='type-id-772' size-in-bits='64' id='type-id-776'/> + <pointer-type-def type-id='type-id-1001' size-in-bits='64' id='type-id-1008'/> + <pointer-type-def type-id='type-id-976' size-in-bits='64' id='type-id-977'/> + <pointer-type-def type-id='type-id-705' size-in-bits='64' id='type-id-848'/> + <pointer-type-def type-id='type-id-906' size-in-bits='64' id='type-id-1057'/> + <pointer-type-def type-id='type-id-1058' size-in-bits='64' id='type-id-915'/> + <pointer-type-def type-id='type-id-910' size-in-bits='64' id='type-id-996'/> + <pointer-type-def type-id='type-id-900' size-in-bits='64' id='type-id-901'/> + <pointer-type-def type-id='type-id-902' size-in-bits='64' id='type-id-905'/> + <pointer-type-def type-id='type-id-903' size-in-bits='64' id='type-id-920'/> + <pointer-type-def type-id='type-id-1032' size-in-bits='64' id='type-id-1033'/> + <pointer-type-def type-id='type-id-768' size-in-bits='64' id='type-id-769'/> + <pointer-type-def type-id='type-id-855' size-in-bits='64' id='type-id-822'/> + <pointer-type-def type-id='type-id-738' size-in-bits='64' id='type-id-922'/> + <pointer-type-def type-id='type-id-770' size-in-bits='64' id='type-id-771'/> + <pointer-type-def type-id='type-id-939' size-in-bits='64' id='type-id-940'/> + <pointer-type-def type-id='type-id-953' size-in-bits='64' id='type-id-605'/> + <pointer-type-def type-id='type-id-954' size-in-bits='64' id='type-id-608'/> + <pointer-type-def type-id='type-id-948' size-in-bits='64' id='type-id-610'/> + <pointer-type-def type-id='type-id-799' size-in-bits='64' id='type-id-800'/> + <pointer-type-def type-id='type-id-802' size-in-bits='64' id='type-id-1059'/> + <pointer-type-def type-id='type-id-1059' size-in-bits='64' id='type-id-805'/> + <pointer-type-def type-id='type-id-1060' size-in-bits='64' id='type-id-1061'/> + <qualified-type-def type-id='type-id-15' restrict='yes' id='type-id-183'/> + <pointer-type-def type-id='type-id-622' size-in-bits='64' id='type-id-818'/> + <pointer-type-def type-id='type-id-430' size-in-bits='64' id='type-id-751'/> + <pointer-type-def type-id='type-id-251' size-in-bits='64' id='type-id-182'/> + <pointer-type-def type-id='type-id-836' size-in-bits='64' id='type-id-840'/> + <pointer-type-def type-id='type-id-1062' size-in-bits='64' id='type-id-1063'/> + <pointer-type-def type-id='type-id-1064' size-in-bits='64' id='type-id-763'/> + <pointer-type-def type-id='type-id-1065' size-in-bits='64' id='type-id-784'/> + <pointer-type-def type-id='type-id-1066' size-in-bits='64' id='type-id-752'/> + <pointer-type-def type-id='type-id-1067' size-in-bits='64' id='type-id-789'/> + <pointer-type-def type-id='type-id-1068' size-in-bits='64' id='type-id-1004'/> + <pointer-type-def type-id='type-id-1069' size-in-bits='64' id='type-id-722'/> + <pointer-type-def type-id='type-id-1070' size-in-bits='64' id='type-id-729'/> + <pointer-type-def type-id='type-id-1071' size-in-bits='64' id='type-id-737'/> + <pointer-type-def type-id='type-id-1072' size-in-bits='64' id='type-id-1003'/> + <pointer-type-def type-id='type-id-1073' size-in-bits='64' id='type-id-815'/> + <pointer-type-def type-id='type-id-190' size-in-bits='64' id='type-id-78'/> + <pointer-type-def type-id='type-id-944' size-in-bits='64' id='type-id-947'/> + <pointer-type-def type-id='type-id-973' size-in-bits='64' id='type-id-972'/> + <pointer-type-def type-id='type-id-943' size-in-bits='64' id='type-id-946'/> + <pointer-type-def type-id='type-id-979' size-in-bits='64' id='type-id-931'/> + <pointer-type-def type-id='type-id-1000' size-in-bits='64' id='type-id-639'/> + <pointer-type-def type-id='type-id-1039' size-in-bits='64' id='type-id-189'/> + <pointer-type-def type-id='type-id-994' size-in-bits='64' id='type-id-997'/> + <pointer-type-def type-id='type-id-1074' size-in-bits='64' id='type-id-911'/> + <pointer-type-def type-id='type-id-325' size-in-bits='64' id='type-id-715'/> + <pointer-type-def type-id='type-id-230' size-in-bits='64' id='type-id-227'/> + <pointer-type-def type-id='type-id-1075' size-in-bits='64' id='type-id-1013'/> + <pointer-type-def type-id='type-id-1076' size-in-bits='64' id='type-id-1024'/> + <pointer-type-def type-id='type-id-1077' size-in-bits='64' id='type-id-762'/> + <pointer-type-def type-id='type-id-1078' size-in-bits='64' id='type-id-755'/> + <pointer-type-def type-id='type-id-1079' size-in-bits='64' id='type-id-814'/> + <pointer-type-def type-id='type-id-1080' size-in-bits='64' id='type-id-813'/> + <pointer-type-def type-id='type-id-1081' size-in-bits='64' id='type-id-919'/> + <pointer-type-def type-id='type-id-1082' size-in-bits='64' id='type-id-754'/> + <pointer-type-def type-id='type-id-1083' size-in-bits='64' id='type-id-760'/> + <pointer-type-def type-id='type-id-1084' size-in-bits='64' id='type-id-761'/> + <qualified-type-def type-id='type-id-990' volatile='yes' id='type-id-988'/> + <qualified-type-def type-id='type-id-989' volatile='yes' id='type-id-698'/> + <pointer-type-def type-id='type-id-422' size-in-bits='64' id='type-id-52'/> + <pointer-type-def type-id='type-id-52' size-in-bits='64' id='type-id-235'/> + <class-decl name='PyAsyncGenASend' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-620'/> + <class-decl name='_PyAsyncGenWrappedValue' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-621'/> + <class-decl name='code_arena_st' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-622'/> + <function-decl name='PyEval_SaveThread' mangled-name='PyEval_SaveThread' filepath='./Include/ceval.h' line='128' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_SaveThread'> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='PyEval_RestoreThread' mangled-name='PyEval_RestoreThread' filepath='./Include/ceval.h' line='129' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_RestoreThread'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyMem_RawRealloc' mangled-name='PyMem_RawRealloc' filepath='./Include/cpython/pymem.h' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_RawRealloc'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyMem_RawFree' mangled-name='PyMem_RawFree' filepath='./Include/cpython/pymem.h' line='8' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_RawFree'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <var-decl name='_PyOS_ReadlineTState' type-id='type-id-177' mangled-name='_PyOS_ReadlineTState' visibility='default' filepath='./Include/cpython/pythonrun.h' line='120' column='1' elf-symbol-id='_PyOS_ReadlineTState'/> + <var-decl name='PyOS_ReadlineFunctionPointer' type-id='type-id-1061' mangled-name='PyOS_ReadlineFunctionPointer' visibility='default' filepath='./Include/cpython/pythonrun.h' line='121' column='1' elf-symbol-id='PyOS_ReadlineFunctionPointer'/> + <function-decl name='_PyOS_InterruptOccurred' mangled-name='_PyOS_InterruptOccurred' filepath='./Include/internal/pycore_pystate.h' line='165' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyOS_InterruptOccurred'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_CheckSignals' mangled-name='PyErr_CheckSignals' filepath='./Include/pyerrors.h' line='239' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_CheckSignals'> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='PyOS_InputHook' type-id='type-id-1063' mangled-name='PyOS_InputHook' visibility='default' filepath='./Include/pythonrun.h' line='22' column='1' elf-symbol-id='PyOS_InputHook'/> + <function-decl name='PyThread_allocate_lock' mangled-name='PyThread_allocate_lock' filepath='./Include/pythread.h' line='30' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_allocate_lock'> + <return type-id='type-id-820'/> + </function-decl> + <function-decl name='PyThread_acquire_lock' mangled-name='PyThread_acquire_lock' filepath='./Include/pythread.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_acquire_lock'> + <parameter type-id='type-id-820'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_release_lock' mangled-name='PyThread_release_lock' filepath='./Include/pythread.h' line='81' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_release_lock'> + <parameter type-id='type-id-820'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='fflush' filepath='/usr/include/stdio.h' line='230' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fgets' filepath='/usr/include/stdio.h' line='592' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-412'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='clearerr' filepath='/usr/include/stdio.h' line='786' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='feof' filepath='/usr/include/stdio.h' line='788' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fileno' filepath='/usr/include/stdio.h' line='809' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='isatty' filepath='/usr/include/unistd.h' line='809' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyOS_Readline' mangled-name='PyOS_Readline' filepath='Parser/myreadline.c' line='358' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_Readline'> + <parameter type-id='type-id-229' name='sys_stdin' filepath='Parser/myreadline.c' line='358' column='1'/> + <parameter type-id='type-id-229' name='sys_stdout' filepath='Parser/myreadline.c' line='358' column='1'/> + <parameter type-id='type-id-12' name='prompt' filepath='Parser/myreadline.c' line='358' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1053'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1054'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-375'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1055'> + <parameter type-id='type-id-1056'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1058'> + <parameter type-id='type-id-996'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-1057'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1060'> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1062'> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1064'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-365'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1065'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-1056'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1066'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1067'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1068'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-440'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1069'> + <parameter type-id='type-id-720'/> + <parameter type-id='type-id-328'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1070'> + <parameter type-id='type-id-727'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1071'> + <parameter type-id='type-id-735'/> + <parameter type-id='type-id-310'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1072'> + <parameter type-id='type-id-250'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1073'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1074'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-908'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1075'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1076'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-189'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1077'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1078'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-46'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1079'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-95'/> + <parameter type-id='type-id-328'/> + <return type-id='type-id-46'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1080'> + <return type-id='type-id-22'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1081'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1082'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1083'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1084'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1085'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1086'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Parser/parser.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='asdl_seq' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1087' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='28' column='1' id='type-id-1088'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='29' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_seq' type-id='type-id-1088' filepath='./Include/internal/pycore_asdl.h' line='30' column='1' id='type-id-1087'/> + <enum-decl name='_cmpop' filepath='./Include/internal/pycore_ast.h' line='31' column='1' id='type-id-1089'> + <underlying-type type-id='type-id-24'/> + <enumerator name='Eq' value='1'/> + <enumerator name='NotEq' value='2'/> + <enumerator name='Lt' value='3'/> + <enumerator name='LtE' value='4'/> + <enumerator name='Gt' value='5'/> + <enumerator name='GtE' value='6'/> + <enumerator name='Is' value='7'/> + <enumerator name='IsNot' value='8'/> + <enumerator name='In' value='9'/> + <enumerator name='NotIn' value='10'/> + </enum-decl> + <typedef-decl name='cmpop_ty' type-id='type-id-1089' filepath='./Include/internal/pycore_ast.h' line='32' column='1' id='type-id-1090'/> + <class-decl name='CmpopExprPair' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1091' visibility='default' filepath='Parser/pegen.h' line='85' column='1' id='type-id-1092'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='cmpop' type-id='type-id-1090' visibility='default' filepath='Parser/pegen.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='expr' type-id='type-id-502' visibility='default' filepath='Parser/pegen.h' line='87' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='CmpopExprPair' type-id='type-id-1092' filepath='Parser/pegen.h' line='88' column='1' id='type-id-1091'/> + <class-decl name='KeyValuePair' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1093' visibility='default' filepath='Parser/pegen.h' line='90' column='1' id='type-id-1094'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='key' type-id='type-id-502' visibility='default' filepath='Parser/pegen.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='Parser/pegen.h' line='92' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='KeyValuePair' type-id='type-id-1094' filepath='Parser/pegen.h' line='93' column='1' id='type-id-1093'/> + <class-decl name='KeyPatternPair' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1095' visibility='default' filepath='Parser/pegen.h' line='95' column='1' id='type-id-1096'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='key' type-id='type-id-502' visibility='default' filepath='Parser/pegen.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='pattern' type-id='type-id-450' visibility='default' filepath='Parser/pegen.h' line='97' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='KeyPatternPair' type-id='type-id-1096' filepath='Parser/pegen.h' line='98' column='1' id='type-id-1095'/> + <class-decl name='NameDefaultPair' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1097' visibility='default' filepath='Parser/pegen.h' line='100' column='1' id='type-id-1098'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='arg' type-id='type-id-567' visibility='default' filepath='Parser/pegen.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='Parser/pegen.h' line='102' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='NameDefaultPair' type-id='type-id-1098' filepath='Parser/pegen.h' line='103' column='1' id='type-id-1097'/> + <class-decl name='SlashWithDefault' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1099' visibility='default' filepath='Parser/pegen.h' line='105' column='1' id='type-id-1100'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='plain_names' type-id='type-id-565' visibility='default' filepath='Parser/pegen.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='names_with_defaults' type-id='type-id-1101' visibility='default' filepath='Parser/pegen.h' line='107' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='SlashWithDefault' type-id='type-id-1100' filepath='Parser/pegen.h' line='108' column='1' id='type-id-1099'/> + <class-decl name='StarEtc' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1102' visibility='default' filepath='Parser/pegen.h' line='110' column='1' id='type-id-1103'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='vararg' type-id='type-id-567' visibility='default' filepath='Parser/pegen.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='kwonlyargs' type-id='type-id-1101' visibility='default' filepath='Parser/pegen.h' line='112' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='kwarg' type-id='type-id-567' visibility='default' filepath='Parser/pegen.h' line='113' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='StarEtc' type-id='type-id-1103' filepath='Parser/pegen.h' line='114' column='1' id='type-id-1102'/> + <class-decl name='AugOperator' size-in-bits='32' is-struct='yes' naming-typedef-id='type-id-1104' visibility='default' filepath='Parser/pegen.h' line='116' column='1' id='type-id-1105'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-530' visibility='default' filepath='Parser/pegen.h' line='116' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='AugOperator' type-id='type-id-1105' filepath='Parser/pegen.h' line='116' column='1' id='type-id-1104'/> + <class-decl name='KeywordOrStarred' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1106' visibility='default' filepath='Parser/pegen.h' line='117' column='1' id='type-id-1107'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='element' type-id='type-id-22' visibility='default' filepath='Parser/pegen.h' line='118' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='is_keyword' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='119' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='KeywordOrStarred' type-id='type-id-1107' filepath='Parser/pegen.h' line='120' column='1' id='type-id-1106'/> + <class-decl name='ResultTokenWithMetadata' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1108' visibility='default' filepath='Parser/pegen.h' line='122' column='1' id='type-id-1109'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='result' type-id='type-id-22' visibility='default' filepath='Parser/pegen.h' line='123' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='metadata' type-id='type-id-2' visibility='default' filepath='Parser/pegen.h' line='124' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='ResultTokenWithMetadata' type-id='type-id-1109' filepath='Parser/pegen.h' line='125' column='1' id='type-id-1108'/> + <enum-decl name='TARGETS_TYPE' naming-typedef-id='type-id-1110' filepath='Parser/pegen.h' line='156' column='1' id='type-id-1111'> + <underlying-type type-id='type-id-24'/> + <enumerator name='STAR_TARGETS' value='0'/> + <enumerator name='DEL_TARGETS' value='1'/> + <enumerator name='FOR_TARGETS' value='2'/> + </enum-decl> + <typedef-decl name='TARGETS_TYPE' type-id='type-id-1111' filepath='Parser/pegen.h' line='160' column='1' id='type-id-1110'/> + <pointer-type-def type-id='type-id-1104' size-in-bits='64' id='type-id-1112'/> + <pointer-type-def type-id='type-id-1091' size-in-bits='64' id='type-id-1113'/> + <pointer-type-def type-id='type-id-1095' size-in-bits='64' id='type-id-1114'/> + <pointer-type-def type-id='type-id-1093' size-in-bits='64' id='type-id-1115'/> + <pointer-type-def type-id='type-id-1106' size-in-bits='64' id='type-id-1116'/> + <pointer-type-def type-id='type-id-1097' size-in-bits='64' id='type-id-1117'/> + <pointer-type-def type-id='type-id-1108' size-in-bits='64' id='type-id-1118'/> + <pointer-type-def type-id='type-id-1099' size-in-bits='64' id='type-id-1119'/> + <pointer-type-def type-id='type-id-1102' size-in-bits='64' id='type-id-1120'/> + <pointer-type-def type-id='type-id-1121' size-in-bits='64' id='type-id-1122'/> + <pointer-type-def type-id='type-id-1087' size-in-bits='64' id='type-id-1101'/> + <pointer-type-def type-id='type-id-1123' size-in-bits='64' id='type-id-1124'/> + <pointer-type-def type-id='type-id-1125' size-in-bits='64' id='type-id-1126'/> + <pointer-type-def type-id='type-id-1127' size-in-bits='64' id='type-id-1128'/> + <class-decl name='tok_state' size-in-bits='138176' is-struct='yes' visibility='default' filepath='Parser/tokenizer.h' line='68' column='1' id='type-id-1129'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='buf' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='cur' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='inp' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='fp_interactive' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='interactive_src_start' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='interactive_src_end' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='end' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='done' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='fp' type-id='type-id-229' visibility='default' filepath='Parser/tokenizer.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='tabsize' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='672'> + <var-decl name='indent' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='indstack' type-id='type-id-1130' visibility='default' filepath='Parser/tokenizer.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3904'> + <var-decl name='atbol' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3936'> + <var-decl name='pendin' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3968'> + <var-decl name='prompt' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4032'> + <var-decl name='nextprompt' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4096'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4128'> + <var-decl name='first_lineno' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4160'> + <var-decl name='starting_col_offset' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4192'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4224'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4256'> + <var-decl name='parenstack' type-id='type-id-1131' visibility='default' filepath='Parser/tokenizer.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5856'> + <var-decl name='parenlinenostack' type-id='type-id-1132' visibility='default' filepath='Parser/tokenizer.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12256'> + <var-decl name='parencolstack' type-id='type-id-1132' visibility='default' filepath='Parser/tokenizer.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18688'> + <var-decl name='filename' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18752'> + <var-decl name='altindstack' type-id='type-id-1130' visibility='default' filepath='Parser/tokenizer.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21952'> + <var-decl name='decoding_state' type-id='type-id-1133' visibility='default' filepath='Parser/tokenizer.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21984'> + <var-decl name='decoding_erred' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='103' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22016'> + <var-decl name='encoding' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='104' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22080'> + <var-decl name='cont_line' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='105' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22144'> + <var-decl name='line_start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22208'> + <var-decl name='multi_line_start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22272'> + <var-decl name='decoding_readline' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22336'> + <var-decl name='decoding_buffer' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22400'> + <var-decl name='enc' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='112' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22464'> + <var-decl name='str' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='113' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22528'> + <var-decl name='input' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='114' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22592'> + <var-decl name='type_comments' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22624'> + <var-decl name='async_hacks' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='119' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22656'> + <var-decl name='async_def' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='120' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22688'> + <var-decl name='async_def_indent' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22720'> + <var-decl name='async_def_nl' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='122' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22752'> + <var-decl name='interactive_underflow' type-id='type-id-1134' visibility='default' filepath='Parser/tokenizer.h' line='125' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22784'> + <var-decl name='report_warnings' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='126' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22848'> + <var-decl name='tok_mode_stack' type-id='type-id-1135' visibility='default' filepath='Parser/tokenizer.h' line='128' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138048'> + <var-decl name='tok_mode_stack_index' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='129' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138080'> + <var-decl name='tok_report_warnings' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138112'> + <var-decl name='tok_extra_tokens' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='131' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138144'> + <var-decl name='comment_newline' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='132' column='1'/> + </data-member> + </class-decl> + <function-decl name='_PyAST_Interactive' filepath='./Include/internal/pycore_ast.h' line='681' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='_PyAST_Expression' filepath='./Include/internal/pycore_ast.h' line='682' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='_PyAST_FunctionType' filepath='./Include/internal/pycore_ast.h' line='683' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='_PyAST_Return' filepath='./Include/internal/pycore_ast.h' line='701' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Delete' filepath='./Include/internal/pycore_ast.h' line='703' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Assign' filepath='./Include/internal/pycore_ast.h' line='705' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_TypeAlias' filepath='./Include/internal/pycore_ast.h' line='708' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-526'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_AugAssign' filepath='./Include/internal/pycore_ast.h' line='711' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-530'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_AnnAssign' filepath='./Include/internal/pycore_ast.h' line='714' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_For' filepath='./Include/internal/pycore_ast.h' line='717' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_AsyncFor' filepath='./Include/internal/pycore_ast.h' line='721' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_While' filepath='./Include/internal/pycore_ast.h' line='725' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_If' filepath='./Include/internal/pycore_ast.h' line='728' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_With' filepath='./Include/internal/pycore_ast.h' line='731' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-531'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_AsyncWith' filepath='./Include/internal/pycore_ast.h' line='734' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-531'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Match' filepath='./Include/internal/pycore_ast.h' line='737' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-532'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Raise' filepath='./Include/internal/pycore_ast.h' line='740' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Try' filepath='./Include/internal/pycore_ast.h' line='742' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-533'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_TryStar' filepath='./Include/internal/pycore_ast.h' line='746' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-533'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Assert' filepath='./Include/internal/pycore_ast.h' line='750' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Import' filepath='./Include/internal/pycore_ast.h' line='752' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-534'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_ImportFrom' filepath='./Include/internal/pycore_ast.h' line='754' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-534'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Global' filepath='./Include/internal/pycore_ast.h' line='757' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-535'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Nonlocal' filepath='./Include/internal/pycore_ast.h' line='759' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-535'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Expr' filepath='./Include/internal/pycore_ast.h' line='762' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Pass' filepath='./Include/internal/pycore_ast.h' line='764' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Break' filepath='./Include/internal/pycore_ast.h' line='766' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_Continue' filepath='./Include/internal/pycore_ast.h' line='768' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyAST_BoolOp' filepath='./Include/internal/pycore_ast.h' line='770' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1136'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_NamedExpr' filepath='./Include/internal/pycore_ast.h' line='773' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_BinOp' filepath='./Include/internal/pycore_ast.h' line='776' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-530'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_UnaryOp' filepath='./Include/internal/pycore_ast.h' line='779' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1137'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Lambda' filepath='./Include/internal/pycore_ast.h' line='782' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-527'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_IfExp' filepath='./Include/internal/pycore_ast.h' line='785' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Dict' filepath='./Include/internal/pycore_ast.h' line='788' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Set' filepath='./Include/internal/pycore_ast.h' line='791' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_ListComp' filepath='./Include/internal/pycore_ast.h' line='793' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-1138'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_SetComp' filepath='./Include/internal/pycore_ast.h' line='796' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-1138'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_DictComp' filepath='./Include/internal/pycore_ast.h' line='799' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-1138'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_GeneratorExp' filepath='./Include/internal/pycore_ast.h' line='802' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-1138'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Await' filepath='./Include/internal/pycore_ast.h' line='805' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Yield' filepath='./Include/internal/pycore_ast.h' line='807' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_YieldFrom' filepath='./Include/internal/pycore_ast.h' line='809' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Compare' filepath='./Include/internal/pycore_ast.h' line='811' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-564'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Slice' filepath='./Include/internal/pycore_ast.h' line='843' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_comprehension' filepath='./Include/internal/pycore_ast.h' line='846' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-1139'/> + </function-decl> + <function-decl name='_PyAST_ExceptHandler' filepath='./Include/internal/pycore_ast.h' line='849' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-446'/> + </function-decl> + <function-decl name='_PyAST_keyword' filepath='./Include/internal/pycore_ast.h' line='860' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-1140'/> + </function-decl> + <function-decl name='_PyAST_withitem' filepath='./Include/internal/pycore_ast.h' line='866' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-459'/> + </function-decl> + <function-decl name='_PyAST_match_case' filepath='./Include/internal/pycore_ast.h' line='868' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-450'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-500'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-448'/> + </function-decl> + <function-decl name='_PyAST_MatchValue' filepath='./Include/internal/pycore_ast.h' line='870' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchSingleton' filepath='./Include/internal/pycore_ast.h' line='872' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-552'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchSequence' filepath='./Include/internal/pycore_ast.h' line='875' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-553'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchMapping' filepath='./Include/internal/pycore_ast.h' line='878' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-553'/> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchClass' filepath='./Include/internal/pycore_ast.h' line='882' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-553'/> + <parameter type-id='type-id-535'/> + <parameter type-id='type-id-553'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchStar' filepath='./Include/internal/pycore_ast.h' line='886' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchAs' filepath='./Include/internal/pycore_ast.h' line='888' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-450'/> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_MatchOr' filepath='./Include/internal/pycore_ast.h' line='891' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-553'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-450'/> + </function-decl> + <function-decl name='_PyAST_TypeVar' filepath='./Include/internal/pycore_ast.h' line='895' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-456'/> + </function-decl> + <function-decl name='_PyAST_ParamSpec' filepath='./Include/internal/pycore_ast.h' line='898' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-456'/> + </function-decl> + <function-decl name='_PyAST_TypeVarTuple' filepath='./Include/internal/pycore_ast.h' line='900' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-456'/> + </function-decl> + <function-decl name='_PyPegen_insert_memo' filepath='Parser/pegen.h' line='133' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_update_memo' filepath='Parser/pegen.h' line='134' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_is_memoized' filepath='Parser/pegen.h' line='135' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_lookahead_with_name' filepath='Parser/pegen.h' line='137' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1124'/> + <parameter type-id='type-id-568'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_lookahead_with_int' filepath='Parser/pegen.h' line='138' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1122'/> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_lookahead_with_string' filepath='Parser/pegen.h' line='139' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1126'/> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_lookahead' filepath='Parser/pegen.h' line='140' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1128'/> + <parameter type-id='type-id-568'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_expect_token' filepath='Parser/pegen.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-569'/> + </function-decl> + <function-decl name='_PyPegen_expect_forced_token' filepath='Parser/pegen.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-569'/> + </function-decl> + <function-decl name='_PyPegen_expect_soft_keyword' filepath='Parser/pegen.h' line='145' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_soft_keyword_token' filepath='Parser/pegen.h' line='146' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_get_last_nonnwhitespace_token' filepath='Parser/pegen.h' line='148' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-569'/> + </function-decl> + <function-decl name='_PyPegen_name_token' filepath='Parser/pegen.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_number_token' filepath='Parser/pegen.h' line='151' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_string_token' filepath='Parser/pegen.h' line='152' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_get_invalid_target' filepath='Parser/pegen.h' line='220' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-1110'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_get_expr_name' filepath='Parser/pegen.h' line='221' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_PyPegen_dummy_name' filepath='Parser/pegen.h' line='246' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_seq_last_item' filepath='Parser/pegen.h' line='247' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_seq_first_item' filepath='Parser/pegen.h' line='249' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_new_type_comment' filepath='Parser/pegen.h' line='254' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyPegen_add_type_comment_to_arg' filepath='Parser/pegen.h' line='293' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-567'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-567'/> + </function-decl> + <function-decl name='_PyPegen_singleton_seq' filepath='Parser/pegen.h' line='295' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-1101'/> + </function-decl> + <function-decl name='_PyPegen_seq_insert_in_front' filepath='Parser/pegen.h' line='296' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-1101'/> + </function-decl> + <function-decl name='_PyPegen_seq_append_to_end' filepath='Parser/pegen.h' line='297' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-1101'/> + </function-decl> + <function-decl name='_PyPegen_seq_flatten' filepath='Parser/pegen.h' line='298' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-1101'/> + </function-decl> + <function-decl name='_PyPegen_join_names_with_dot' filepath='Parser/pegen.h' line='299' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_seq_count_dots' filepath='Parser/pegen.h' line='300' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_alias_for_star' filepath='Parser/pegen.h' line='301' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-444'/> + </function-decl> + <function-decl name='_PyPegen_map_names_to_ids' filepath='Parser/pegen.h' line='302' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-503'/> + <return type-id='type-id-535'/> + </function-decl> + <function-decl name='_PyPegen_cmpop_expr_pair' filepath='Parser/pegen.h' line='303' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1090'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-1113'/> + </function-decl> + <function-decl name='_PyPegen_get_cmpops' filepath='Parser/pegen.h' line='304' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-564'/> + </function-decl> + <function-decl name='_PyPegen_get_exprs' filepath='Parser/pegen.h' line='305' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-503'/> + </function-decl> + <function-decl name='_PyPegen_set_expr_context' filepath='Parser/pegen.h' line='306' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-566'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_key_value_pair' filepath='Parser/pegen.h' line='307' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-1115'/> + </function-decl> + <function-decl name='_PyPegen_get_keys' filepath='Parser/pegen.h' line='308' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-503'/> + </function-decl> + <function-decl name='_PyPegen_get_values' filepath='Parser/pegen.h' line='309' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-503'/> + </function-decl> + <function-decl name='_PyPegen_key_pattern_pair' filepath='Parser/pegen.h' line='310' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-450'/> + <return type-id='type-id-1114'/> + </function-decl> + <function-decl name='_PyPegen_get_pattern_keys' filepath='Parser/pegen.h' line='311' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-503'/> + </function-decl> + <function-decl name='_PyPegen_get_patterns' filepath='Parser/pegen.h' line='312' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-553'/> + </function-decl> + <function-decl name='_PyPegen_name_default_pair' filepath='Parser/pegen.h' line='313' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-567'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-1117'/> + </function-decl> + <function-decl name='_PyPegen_slash_with_default' filepath='Parser/pegen.h' line='314' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-565'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-1119'/> + </function-decl> + <function-decl name='_PyPegen_star_etc' filepath='Parser/pegen.h' line='315' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-567'/> + <parameter type-id='type-id-1101'/> + <parameter type-id='type-id-567'/> + <return type-id='type-id-1120'/> + </function-decl> + <function-decl name='_PyPegen_make_arguments' filepath='Parser/pegen.h' line='316' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-565'/> + <parameter type-id='type-id-1119'/> + <parameter type-id='type-id-565'/> + <parameter type-id='type-id-1101'/> + <parameter type-id='type-id-1120'/> + <return type-id='type-id-527'/> + </function-decl> + <function-decl name='_PyPegen_empty_arguments' filepath='Parser/pegen.h' line='318' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-527'/> + </function-decl> + <function-decl name='_PyPegen_formatted_value' filepath='Parser/pegen.h' line='319' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-569'/> + <parameter type-id='type-id-1118'/> + <parameter type-id='type-id-1118'/> + <parameter type-id='type-id-569'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_augoperator' filepath='Parser/pegen.h' line='321' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-530'/> + <return type-id='type-id-1112'/> + </function-decl> + <function-decl name='_PyPegen_function_def_decorators' filepath='Parser/pegen.h' line='322' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-452'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyPegen_class_def_decorators' filepath='Parser/pegen.h' line='323' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-452'/> + <return type-id='type-id-452'/> + </function-decl> + <function-decl name='_PyPegen_keyword_or_starred' filepath='Parser/pegen.h' line='324' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-1116'/> + </function-decl> + <function-decl name='_PyPegen_seq_extract_starred_exprs' filepath='Parser/pegen.h' line='325' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-503'/> + </function-decl> + <function-decl name='_PyPegen_seq_delete_starred_exprs' filepath='Parser/pegen.h' line='326' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-529'/> + </function-decl> + <function-decl name='_PyPegen_collect_call_seqs' filepath='Parser/pegen.h' line='327' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-1101'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_constant_from_token' filepath='Parser/pegen.h' line='330' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_constant_from_string' filepath='Parser/pegen.h' line='331' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_concatenate_strings' filepath='Parser/pegen.h' line='332' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_ensure_imaginary' filepath='Parser/pegen.h' line='334' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_ensure_real' filepath='Parser/pegen.h' line='335' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_join_sequences' filepath='Parser/pegen.h' line='336' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-1101'/> + <parameter type-id='type-id-1101'/> + <return type-id='type-id-1101'/> + </function-decl> + <function-decl name='_PyPegen_check_barry_as_flufl' filepath='Parser/pegen.h' line='337' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_check_legacy_stmt' filepath='Parser/pegen.h' line='338' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_check_fstring_conversion' filepath='Parser/pegen.h' line='339' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-1118'/> + </function-decl> + <function-decl name='_PyPegen_setup_full_format_spec' filepath='Parser/pegen.h' line='340' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-1118'/> + </function-decl> + <function-decl name='_PyPegen_make_module' filepath='Parser/pegen.h' line='342' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-500'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='_PyPegen_arguments_parsing_error' filepath='Parser/pegen.h' line='343' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_get_last_comprehension_item' filepath='Parser/pegen.h' line='344' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1139'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyPegen_nonparen_genexp_in_call' filepath='Parser/pegen.h' line='345' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-502'/> + <parameter type-id='type-id-1138'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_interactive_exit' filepath='Parser/pegen.h' line='355' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-500'/> + </function-decl> + <function-decl name='_PyPegen_joined_str' filepath='Parser/pegen.h' line='358' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <parameter type-id='type-id-503'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-502'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1121'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-569'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1123'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-502'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1125'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-502'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1127'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-22'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Parser/peg_api.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyCompilerFlags' size-in-bits='64' is-struct='yes' naming-typedef-id='type-id-1141' visibility='default' filepath='./Include/cpython/compile.h' line='26' column='1' id='type-id-1142'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='cf_flags' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='cf_feature_version' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='28' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyCompilerFlags' type-id='type-id-1142' filepath='./Include/cpython/compile.h' line='29' column='1' id='type-id-1141'/> + <pointer-type-def type-id='type-id-1141' size-in-bits='64' id='type-id-208'/> + <function-decl name='PySys_Audit' mangled-name='PySys_Audit' filepath='./Include/cpython/sysmodule.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_Audit'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_run_parser_from_file_pointer' filepath='Parser/pegen.h' line='351' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='_PyPegen_run_parser_from_string' filepath='Parser/pegen.h' line='354' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-468'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Parser/pegen.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-567' size-in-bits='64' id='type-id-1143'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='8' id='type-id-702'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='1600' id='type-id-1131'> + <subrange length='200' type-id='type-id-28' id='type-id-643'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='160' id='type-id-1144'> + <subrange length='20' type-id='type-id-28' id='type-id-588'/> + </array-type-def> + <class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1145'/> + <class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1146'/> + <class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1147'/> + <class-decl name='__va_list_tag' size-in-bits='192' is-struct='yes' visibility='default' id='type-id-1148'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='gp_offset' type-id='type-id-95' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='fp_offset' type-id='type-id-95' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='overflow_arg_area' type-id='type-id-22' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='reg_save_area' type-id='type-id-22' visibility='default'/> + </data-member> + </class-decl> + <class-decl name='_arena' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1149'/> + <array-type-def dimensions='1' type-id='type-id-1139' size-in-bits='64' id='type-id-1150'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <type-decl name='double' size-in-bits='64' id='type-id-251'/> + <array-type-def dimensions='1' type-id='type-id-502' size-in-bits='64' id='type-id-1151'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='3200' id='type-id-1130'> + <subrange length='100' type-id='type-id-28' id='type-id-1152'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='32' id='type-id-1153'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-8' size-in-bits='6400' id='type-id-1132'> + <subrange length='200' type-id='type-id-28' id='type-id-643'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-1140' size-in-bits='64' id='type-id-1154'> + <subrange length='1' type-id='type-id-28' id='type-id-443'/> + </array-type-def> + <type-decl name='long int' size-in-bits='64' id='type-id-47'/> + <type-decl name='signed char' size-in-bits='8' id='type-id-1034'/> + <array-type-def dimensions='1' type-id='type-id-1155' size-in-bits='115200' id='type-id-1135'> + <subrange length='150' type-id='type-id-28' id='type-id-1156'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-352' size-in-bits='64' id='type-id-1157'> + <subrange length='2' type-id='type-id-28' id='type-id-681'/> + </array-type-def> + <type-decl name='unnamed-enum-underlying-type-32' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='type-id-24'/> + <type-decl name='unsigned int' size-in-bits='32' id='type-id-95'/> + <type-decl name='unsigned short int' size-in-bits='16' id='type-id-84'/> + <type-decl name='void' id='type-id-46'/> + <class-decl name='Py_complex' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-327' visibility='default' filepath='./Include/cpython/complexobject.h' line='5' column='1' id='type-id-1158'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='real' type-id='type-id-251' visibility='default' filepath='./Include/cpython/complexobject.h' line='6' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='imag' type-id='type-id-251' visibility='default' filepath='./Include/cpython/complexobject.h' line='7' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Py_complex' type-id='type-id-1158' filepath='./Include/cpython/complexobject.h' line='8' column='1' id='type-id-327'/> + <class-decl name='PyNumberMethods' size-in-bits='2304' is-struct='yes' naming-typedef-id='type-id-1159' visibility='default' filepath='./Include/cpython/object.h' line='59' column='1' id='type-id-1160'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='nb_add' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='nb_subtract' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='nb_multiply' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='nb_remainder' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='nb_divmod' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='nb_power' type-id='type-id-1162' visibility='default' filepath='./Include/cpython/object.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='nb_negative' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='nb_positive' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='nb_absolute' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='nb_bool' type-id='type-id-396' visibility='default' filepath='./Include/cpython/object.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='nb_invert' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='nb_lshift' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='nb_rshift' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='nb_and' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='nb_xor' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='nb_or' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='nb_int' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='nb_reserved' type-id='type-id-22' visibility='default' filepath='./Include/cpython/object.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='nb_float' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='nb_inplace_add' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='nb_inplace_subtract' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='nb_inplace_multiply' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='nb_inplace_remainder' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='nb_inplace_power' type-id='type-id-1162' visibility='default' filepath='./Include/cpython/object.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='nb_inplace_lshift' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='nb_inplace_rshift' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='90' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1664'> + <var-decl name='nb_inplace_and' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='nb_inplace_xor' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='nb_inplace_or' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1856'> + <var-decl name='nb_floor_divide' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1920'> + <var-decl name='nb_true_divide' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1984'> + <var-decl name='nb_inplace_floor_divide' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2048'> + <var-decl name='nb_inplace_true_divide' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='nb_index' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2176'> + <var-decl name='nb_matrix_multiply' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2240'> + <var-decl name='nb_inplace_matrix_multiply' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='103' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyNumberMethods' type-id='type-id-1160' filepath='./Include/cpython/object.h' line='104' column='1' id='type-id-1159'/> + <class-decl name='PySequenceMethods' size-in-bits='640' is-struct='yes' naming-typedef-id='type-id-1164' visibility='default' filepath='./Include/cpython/object.h' line='106' column='1' id='type-id-1165'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='sq_length' type-id='type-id-1166' visibility='default' filepath='./Include/cpython/object.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='sq_concat' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='108' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='sq_repeat' type-id='type-id-1167' visibility='default' filepath='./Include/cpython/object.h' line='109' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='sq_item' type-id='type-id-1167' visibility='default' filepath='./Include/cpython/object.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='was_sq_slice' type-id='type-id-22' visibility='default' filepath='./Include/cpython/object.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='sq_ass_item' type-id='type-id-1168' visibility='default' filepath='./Include/cpython/object.h' line='112' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='was_sq_ass_slice' type-id='type-id-22' visibility='default' filepath='./Include/cpython/object.h' line='113' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='sq_contains' type-id='type-id-1169' visibility='default' filepath='./Include/cpython/object.h' line='114' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='sq_inplace_concat' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='sq_inplace_repeat' type-id='type-id-1167' visibility='default' filepath='./Include/cpython/object.h' line='117' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PySequenceMethods' type-id='type-id-1165' filepath='./Include/cpython/object.h' line='118' column='1' id='type-id-1164'/> + <class-decl name='PyMappingMethods' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1170' visibility='default' filepath='./Include/cpython/object.h' line='120' column='1' id='type-id-1171'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='mp_length' type-id='type-id-1166' visibility='default' filepath='./Include/cpython/object.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='mp_subscript' type-id='type-id-1161' visibility='default' filepath='./Include/cpython/object.h' line='122' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='mp_ass_subscript' type-id='type-id-1172' visibility='default' filepath='./Include/cpython/object.h' line='123' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyMappingMethods' type-id='type-id-1171' filepath='./Include/cpython/object.h' line='124' column='1' id='type-id-1170'/> + <typedef-decl name='sendfunc' type-id='type-id-1173' filepath='./Include/cpython/object.h' line='126' column='1' id='type-id-1174'/> + <class-decl name='PyAsyncMethods' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-1175' visibility='default' filepath='./Include/cpython/object.h' line='128' column='1' id='type-id-1176'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='am_await' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='129' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='am_aiter' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='am_anext' type-id='type-id-1163' visibility='default' filepath='./Include/cpython/object.h' line='131' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='am_send' type-id='type-id-1174' visibility='default' filepath='./Include/cpython/object.h' line='132' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyAsyncMethods' type-id='type-id-1176' filepath='./Include/cpython/object.h' line='133' column='1' id='type-id-1175'/> + <class-decl name='PyBufferProcs' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1177' visibility='default' filepath='./Include/cpython/object.h' line='135' column='1' id='type-id-1178'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='bf_getbuffer' type-id='type-id-434' visibility='default' filepath='./Include/cpython/object.h' line='136' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='bf_releasebuffer' type-id='type-id-1179' visibility='default' filepath='./Include/cpython/object.h' line='137' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyBufferProcs' type-id='type-id-1178' filepath='./Include/cpython/object.h' line='138' column='1' id='type-id-1177'/> + <class-decl name='_typeobject' size-in-bits='3328' is-struct='yes' visibility='default' filepath='./Include/cpython/object.h' line='146' column='1' id='type-id-1180'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-321' visibility='default' filepath='./Include/cpython/object.h' line='147' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='tp_name' type-id='type-id-12' visibility='default' filepath='./Include/cpython/object.h' line='148' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='tp_basicsize' type-id='type-id-14' visibility='default' filepath='./Include/cpython/object.h' line='149' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='tp_itemsize' type-id='type-id-14' visibility='default' filepath='./Include/cpython/object.h' line='149' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='tp_dealloc' type-id='type-id-335' visibility='default' filepath='./Include/cpython/object.h' line='153' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='tp_vectorcall_offset' type-id='type-id-14' visibility='default' filepath='./Include/cpython/object.h' line='154' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='tp_getattr' type-id='type-id-1181' visibility='default' filepath='./Include/cpython/object.h' line='155' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='tp_setattr' type-id='type-id-1182' visibility='default' filepath='./Include/cpython/object.h' line='156' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='tp_as_async' type-id='type-id-1183' visibility='default' filepath='./Include/cpython/object.h' line='157' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='tp_repr' type-id='type-id-1184' visibility='default' filepath='./Include/cpython/object.h' line='159' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='tp_as_number' type-id='type-id-1185' visibility='default' filepath='./Include/cpython/object.h' line='163' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='tp_as_sequence' type-id='type-id-1186' visibility='default' filepath='./Include/cpython/object.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='tp_as_mapping' type-id='type-id-1187' visibility='default' filepath='./Include/cpython/object.h' line='165' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='tp_hash' type-id='type-id-1188' visibility='default' filepath='./Include/cpython/object.h' line='169' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='tp_call' type-id='type-id-1162' visibility='default' filepath='./Include/cpython/object.h' line='170' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='tp_str' type-id='type-id-1184' visibility='default' filepath='./Include/cpython/object.h' line='171' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='tp_getattro' type-id='type-id-1189' visibility='default' filepath='./Include/cpython/object.h' line='172' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='tp_setattro' type-id='type-id-1190' visibility='default' filepath='./Include/cpython/object.h' line='173' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='tp_as_buffer' type-id='type-id-1191' visibility='default' filepath='./Include/cpython/object.h' line='176' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='tp_flags' type-id='type-id-28' visibility='default' filepath='./Include/cpython/object.h' line='179' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='tp_doc' type-id='type-id-12' visibility='default' filepath='./Include/cpython/object.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='tp_traverse' type-id='type-id-395' visibility='default' filepath='./Include/cpython/object.h' line='185' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='tp_clear' type-id='type-id-396' visibility='default' filepath='./Include/cpython/object.h' line='188' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1600'> + <var-decl name='tp_richcompare' type-id='type-id-1192' visibility='default' filepath='./Include/cpython/object.h' line='192' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1664'> + <var-decl name='tp_weaklistoffset' type-id='type-id-14' visibility='default' filepath='./Include/cpython/object.h' line='195' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1728'> + <var-decl name='tp_iter' type-id='type-id-1193' visibility='default' filepath='./Include/cpython/object.h' line='198' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1792'> + <var-decl name='tp_iternext' type-id='type-id-1194' visibility='default' filepath='./Include/cpython/object.h' line='199' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1856'> + <var-decl name='tp_methods' type-id='type-id-337' visibility='default' filepath='./Include/cpython/object.h' line='202' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1920'> + <var-decl name='tp_members' type-id='type-id-336' visibility='default' filepath='./Include/cpython/object.h' line='203' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1984'> + <var-decl name='tp_getset' type-id='type-id-338' visibility='default' filepath='./Include/cpython/object.h' line='204' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2048'> + <var-decl name='tp_base' type-id='type-id-1' visibility='default' filepath='./Include/cpython/object.h' line='206' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2112'> + <var-decl name='tp_dict' type-id='type-id-2' visibility='default' filepath='./Include/cpython/object.h' line='207' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2176'> + <var-decl name='tp_descr_get' type-id='type-id-1195' visibility='default' filepath='./Include/cpython/object.h' line='208' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2240'> + <var-decl name='tp_descr_set' type-id='type-id-1196' visibility='default' filepath='./Include/cpython/object.h' line='209' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2304'> + <var-decl name='tp_dictoffset' type-id='type-id-14' visibility='default' filepath='./Include/cpython/object.h' line='210' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2368'> + <var-decl name='tp_init' type-id='type-id-1197' visibility='default' filepath='./Include/cpython/object.h' line='211' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2432'> + <var-decl name='tp_alloc' type-id='type-id-1198' visibility='default' filepath='./Include/cpython/object.h' line='212' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2496'> + <var-decl name='tp_new' type-id='type-id-1199' visibility='default' filepath='./Include/cpython/object.h' line='213' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2560'> + <var-decl name='tp_free' type-id='type-id-397' visibility='default' filepath='./Include/cpython/object.h' line='214' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2624'> + <var-decl name='tp_is_gc' type-id='type-id-396' visibility='default' filepath='./Include/cpython/object.h' line='215' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2688'> + <var-decl name='tp_bases' type-id='type-id-2' visibility='default' filepath='./Include/cpython/object.h' line='216' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2752'> + <var-decl name='tp_mro' type-id='type-id-2' visibility='default' filepath='./Include/cpython/object.h' line='217' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2816'> + <var-decl name='tp_cache' type-id='type-id-2' visibility='default' filepath='./Include/cpython/object.h' line='218' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2880'> + <var-decl name='tp_subclasses' type-id='type-id-22' visibility='default' filepath='./Include/cpython/object.h' line='219' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='2944'> + <var-decl name='tp_weaklist' type-id='type-id-2' visibility='default' filepath='./Include/cpython/object.h' line='220' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3008'> + <var-decl name='tp_del' type-id='type-id-335' visibility='default' filepath='./Include/cpython/object.h' line='221' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3072'> + <var-decl name='tp_version_tag' type-id='type-id-95' visibility='default' filepath='./Include/cpython/object.h' line='224' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3136'> + <var-decl name='tp_finalize' type-id='type-id-335' visibility='default' filepath='./Include/cpython/object.h' line='226' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3200'> + <var-decl name='tp_vectorcall' type-id='type-id-311' visibility='default' filepath='./Include/cpython/object.h' line='227' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3264'> + <var-decl name='tp_watched' type-id='type-id-48' visibility='default' filepath='./Include/cpython/object.h' line='230' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='getter' type-id='type-id-730' filepath='./Include/descrobject.h' line='8' column='1' id='type-id-1200'/> + <typedef-decl name='setter' type-id='type-id-1201' filepath='./Include/descrobject.h' line='9' column='1' id='type-id-1202'/> + <class-decl name='PyGetSetDef' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/descrobject.h' line='11' column='1' id='type-id-1203'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/descrobject.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='get' type-id='type-id-1200' visibility='default' filepath='./Include/descrobject.h' line='13' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='set' type-id='type-id-1202' visibility='default' filepath='./Include/descrobject.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='doc' type-id='type-id-12' visibility='default' filepath='./Include/descrobject.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='closure' type-id='type-id-22' visibility='default' filepath='./Include/descrobject.h' line='16' column='1'/> + </data-member> + </class-decl> + <class-decl name='PyMemberDef' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/descrobject.h' line='41' column='1' id='type-id-1204'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/descrobject.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type' type-id='type-id-8' visibility='default' filepath='./Include/descrobject.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='offset' type-id='type-id-14' visibility='default' filepath='./Include/descrobject.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='flags' type-id='type-id-8' visibility='default' filepath='./Include/descrobject.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='doc' type-id='type-id-12' visibility='default' filepath='./Include/descrobject.h' line='46' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='identifier' type-id='type-id-2' filepath='./Include/internal/pycore_asdl.h' line='13' column='1' id='type-id-525'/> + <typedef-decl name='string' type-id='type-id-2' filepath='./Include/internal/pycore_asdl.h' line='14' column='1' id='type-id-528'/> + <typedef-decl name='constant' type-id='type-id-2' filepath='./Include/internal/pycore_asdl.h' line='16' column='1' id='type-id-552'/> + <class-decl name='asdl_int_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1205' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='42' column='1' id='type-id-1206'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-1153' visibility='default' filepath='./Include/internal/pycore_asdl.h' line='44' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_int_seq' type-id='type-id-1206' filepath='./Include/internal/pycore_asdl.h' line='45' column='1' id='type-id-1205'/> + <typedef-decl name='expr_ty' type-id='type-id-1207' filepath='./Include/internal/pycore_ast.h' line='19' column='1' id='type-id-502'/> + <enum-decl name='_expr_context' filepath='./Include/internal/pycore_ast.h' line='21' column='1' id='type-id-1208'> + <underlying-type type-id='type-id-24'/> + <enumerator name='Load' value='1'/> + <enumerator name='Store' value='2'/> + <enumerator name='Del' value='3'/> + </enum-decl> + <typedef-decl name='expr_context_ty' type-id='type-id-1208' filepath='./Include/internal/pycore_ast.h' line='21' column='1' id='type-id-566'/> + <enum-decl name='_boolop' filepath='./Include/internal/pycore_ast.h' line='23' column='1' id='type-id-1209'> + <underlying-type type-id='type-id-24'/> + <enumerator name='And' value='1'/> + <enumerator name='Or' value='2'/> + </enum-decl> + <typedef-decl name='boolop_ty' type-id='type-id-1209' filepath='./Include/internal/pycore_ast.h' line='23' column='1' id='type-id-1136'/> + <enum-decl name='_operator' filepath='./Include/internal/pycore_ast.h' line='25' column='1' id='type-id-1210'> + <underlying-type type-id='type-id-24'/> + <enumerator name='Add' value='1'/> + <enumerator name='Sub' value='2'/> + <enumerator name='Mult' value='3'/> + <enumerator name='MatMult' value='4'/> + <enumerator name='Div' value='5'/> + <enumerator name='Mod' value='6'/> + <enumerator name='Pow' value='7'/> + <enumerator name='LShift' value='8'/> + <enumerator name='RShift' value='9'/> + <enumerator name='BitOr' value='10'/> + <enumerator name='BitXor' value='11'/> + <enumerator name='BitAnd' value='12'/> + <enumerator name='FloorDiv' value='13'/> + </enum-decl> + <typedef-decl name='operator_ty' type-id='type-id-1210' filepath='./Include/internal/pycore_ast.h' line='27' column='1' id='type-id-530'/> + <enum-decl name='_unaryop' filepath='./Include/internal/pycore_ast.h' line='29' column='1' id='type-id-1211'> + <underlying-type type-id='type-id-24'/> + <enumerator name='Invert' value='1'/> + <enumerator name='Not' value='2'/> + <enumerator name='UAdd' value='3'/> + <enumerator name='USub' value='4'/> + </enum-decl> + <typedef-decl name='unaryop_ty' type-id='type-id-1211' filepath='./Include/internal/pycore_ast.h' line='29' column='1' id='type-id-1137'/> + <typedef-decl name='comprehension_ty' type-id='type-id-1212' filepath='./Include/internal/pycore_ast.h' line='34' column='1' id='type-id-1139'/> + <typedef-decl name='arguments_ty' type-id='type-id-1213' filepath='./Include/internal/pycore_ast.h' line='38' column='1' id='type-id-527'/> + <typedef-decl name='arg_ty' type-id='type-id-1214' filepath='./Include/internal/pycore_ast.h' line='40' column='1' id='type-id-567'/> + <typedef-decl name='keyword_ty' type-id='type-id-1215' filepath='./Include/internal/pycore_ast.h' line='42' column='1' id='type-id-1140'/> + <class-decl name='asdl_expr_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1216' visibility='default' filepath='./Include/internal/pycore_ast.h' line='71' column='1' id='type-id-1217'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-1151' visibility='default' filepath='./Include/internal/pycore_ast.h' line='73' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_expr_seq' type-id='type-id-1217' filepath='./Include/internal/pycore_ast.h' line='74' column='1' id='type-id-1216'/> + <class-decl name='asdl_comprehension_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1218' visibility='default' filepath='./Include/internal/pycore_ast.h' line='78' column='1' id='type-id-1219'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-1150' visibility='default' filepath='./Include/internal/pycore_ast.h' line='80' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_comprehension_seq' type-id='type-id-1219' filepath='./Include/internal/pycore_ast.h' line='81' column='1' id='type-id-1218'/> + <class-decl name='asdl_arg_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1220' visibility='default' filepath='./Include/internal/pycore_ast.h' line='101' column='1' id='type-id-1221'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-1143' visibility='default' filepath='./Include/internal/pycore_ast.h' line='103' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_arg_seq' type-id='type-id-1221' filepath='./Include/internal/pycore_ast.h' line='104' column='1' id='type-id-1220'/> + <class-decl name='asdl_keyword_seq' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1222' visibility='default' filepath='./Include/internal/pycore_ast.h' line='108' column='1' id='type-id-1223'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='size' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_ast.h' line='109' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='elements' type-id='type-id-253' visibility='default' filepath='./Include/internal/pycore_ast.h' line='109' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='typed_elements' type-id='type-id-1154' visibility='default' filepath='./Include/internal/pycore_ast.h' line='110' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='asdl_keyword_seq' type-id='type-id-1223' filepath='./Include/internal/pycore_ast.h' line='111' column='1' id='type-id-1222'/> + <enum-decl name='_expr_kind' filepath='./Include/internal/pycore_ast.h' line='359' column='1' id='type-id-1224'> + <underlying-type type-id='type-id-24'/> + <enumerator name='BoolOp_kind' value='1'/> + <enumerator name='NamedExpr_kind' value='2'/> + <enumerator name='BinOp_kind' value='3'/> + <enumerator name='UnaryOp_kind' value='4'/> + <enumerator name='Lambda_kind' value='5'/> + <enumerator name='IfExp_kind' value='6'/> + <enumerator name='Dict_kind' value='7'/> + <enumerator name='Set_kind' value='8'/> + <enumerator name='ListComp_kind' value='9'/> + <enumerator name='SetComp_kind' value='10'/> + <enumerator name='DictComp_kind' value='11'/> + <enumerator name='GeneratorExp_kind' value='12'/> + <enumerator name='Await_kind' value='13'/> + <enumerator name='Yield_kind' value='14'/> + <enumerator name='YieldFrom_kind' value='15'/> + <enumerator name='Compare_kind' value='16'/> + <enumerator name='Call_kind' value='17'/> + <enumerator name='FormattedValue_kind' value='18'/> + <enumerator name='JoinedStr_kind' value='19'/> + <enumerator name='Constant_kind' value='20'/> + <enumerator name='Attribute_kind' value='21'/> + <enumerator name='Subscript_kind' value='22'/> + <enumerator name='Starred_kind' value='23'/> + <enumerator name='Name_kind' value='24'/> + <enumerator name='List_kind' value='25'/> + <enumerator name='Tuple_kind' value='26'/> + <enumerator name='Slice_kind' value='27'/> + </enum-decl> + <class-decl name='_expr' size-in-bits='384' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='367' column='1' id='type-id-960'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-1224' visibility='default' filepath='./Include/internal/pycore_ast.h' line='368' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='v' type-id='type-id-1225' visibility='default' filepath='./Include/internal/pycore_ast.h' line='509' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='510' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='511' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='512' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='513' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__1' size-in-bits='192' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='369' column='1' id='type-id-1225'> + <data-member access='public'> + <var-decl name='BoolOp' type-id='type-id-1226' visibility='default' filepath='./Include/internal/pycore_ast.h' line='373' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='NamedExpr' type-id='type-id-1227' visibility='default' filepath='./Include/internal/pycore_ast.h' line='378' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='BinOp' type-id='type-id-1228' visibility='default' filepath='./Include/internal/pycore_ast.h' line='384' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='UnaryOp' type-id='type-id-1229' visibility='default' filepath='./Include/internal/pycore_ast.h' line='389' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Lambda' type-id='type-id-1230' visibility='default' filepath='./Include/internal/pycore_ast.h' line='394' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='IfExp' type-id='type-id-1231' visibility='default' filepath='./Include/internal/pycore_ast.h' line='400' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Dict' type-id='type-id-1232' visibility='default' filepath='./Include/internal/pycore_ast.h' line='405' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Set' type-id='type-id-1233' visibility='default' filepath='./Include/internal/pycore_ast.h' line='409' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='ListComp' type-id='type-id-1234' visibility='default' filepath='./Include/internal/pycore_ast.h' line='414' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='SetComp' type-id='type-id-1234' visibility='default' filepath='./Include/internal/pycore_ast.h' line='419' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='DictComp' type-id='type-id-1235' visibility='default' filepath='./Include/internal/pycore_ast.h' line='425' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='GeneratorExp' type-id='type-id-1234' visibility='default' filepath='./Include/internal/pycore_ast.h' line='430' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Await' type-id='type-id-509' visibility='default' filepath='./Include/internal/pycore_ast.h' line='434' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Yield' type-id='type-id-509' visibility='default' filepath='./Include/internal/pycore_ast.h' line='438' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='YieldFrom' type-id='type-id-509' visibility='default' filepath='./Include/internal/pycore_ast.h' line='442' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Compare' type-id='type-id-1236' visibility='default' filepath='./Include/internal/pycore_ast.h' line='448' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Call' type-id='type-id-1237' visibility='default' filepath='./Include/internal/pycore_ast.h' line='454' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='FormattedValue' type-id='type-id-1238' visibility='default' filepath='./Include/internal/pycore_ast.h' line='460' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='JoinedStr' type-id='type-id-1239' visibility='default' filepath='./Include/internal/pycore_ast.h' line='464' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Constant' type-id='type-id-1240' visibility='default' filepath='./Include/internal/pycore_ast.h' line='469' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Attribute' type-id='type-id-1241' visibility='default' filepath='./Include/internal/pycore_ast.h' line='475' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Subscript' type-id='type-id-1242' visibility='default' filepath='./Include/internal/pycore_ast.h' line='481' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Starred' type-id='type-id-1243' visibility='default' filepath='./Include/internal/pycore_ast.h' line='486' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Name' type-id='type-id-1244' visibility='default' filepath='./Include/internal/pycore_ast.h' line='491' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='List' type-id='type-id-1245' visibility='default' filepath='./Include/internal/pycore_ast.h' line='496' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Tuple' type-id='type-id-1245' visibility='default' filepath='./Include/internal/pycore_ast.h' line='501' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='Slice' type-id='type-id-1246' visibility='default' filepath='./Include/internal/pycore_ast.h' line='507' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__1' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='370' column='1' id='type-id-1226'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='op' type-id='type-id-1136' visibility='default' filepath='./Include/internal/pycore_ast.h' line='371' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='values' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='372' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__2' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='375' column='1' id='type-id-1227'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='target' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='376' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='377' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__3' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='380' column='1' id='type-id-1228'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='left' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='381' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='op' type-id='type-id-530' visibility='default' filepath='./Include/internal/pycore_ast.h' line='382' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='right' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='383' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__4' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='386' column='1' id='type-id-1229'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='op' type-id='type-id-1137' visibility='default' filepath='./Include/internal/pycore_ast.h' line='387' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='operand' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='388' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__5' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='391' column='1' id='type-id-1230'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='args' type-id='type-id-527' visibility='default' filepath='./Include/internal/pycore_ast.h' line='392' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='body' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='393' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__6' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='396' column='1' id='type-id-1231'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='test' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='397' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='body' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='398' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='orelse' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='399' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__7' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='402' column='1' id='type-id-1232'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='keys' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='403' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='values' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='404' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__8' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='407' column='1' id='type-id-1233'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='elts' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='408' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__9' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='411' column='1' id='type-id-1234'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='elt' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='412' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='generators' type-id='type-id-1138' visibility='default' filepath='./Include/internal/pycore_ast.h' line='413' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__11' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='421' column='1' id='type-id-1235'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='key' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='422' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='423' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='generators' type-id='type-id-1138' visibility='default' filepath='./Include/internal/pycore_ast.h' line='424' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__13' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='432' column='1' id='type-id-509'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='433' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__16' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='444' column='1' id='type-id-1236'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='left' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='445' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ops' type-id='type-id-564' visibility='default' filepath='./Include/internal/pycore_ast.h' line='446' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='comparators' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='447' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__17' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='450' column='1' id='type-id-1237'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='func' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='451' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='args' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='452' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='keywords' type-id='type-id-529' visibility='default' filepath='./Include/internal/pycore_ast.h' line='453' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__18' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='456' column='1' id='type-id-1238'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='457' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='conversion' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='458' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='format_spec' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='459' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__19' size-in-bits='64' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='462' column='1' id='type-id-1239'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='values' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='463' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__20' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='466' column='1' id='type-id-1240'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-552' visibility='default' filepath='./Include/internal/pycore_ast.h' line='467' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='kind' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='468' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__21' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='471' column='1' id='type-id-1241'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='472' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='attr' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='473' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ctx' type-id='type-id-566' visibility='default' filepath='./Include/internal/pycore_ast.h' line='474' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__22' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='477' column='1' id='type-id-1242'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='478' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='slice' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='479' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ctx' type-id='type-id-566' visibility='default' filepath='./Include/internal/pycore_ast.h' line='480' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__23' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='483' column='1' id='type-id-1243'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='484' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ctx' type-id='type-id-566' visibility='default' filepath='./Include/internal/pycore_ast.h' line='485' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__24' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='488' column='1' id='type-id-1244'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='id' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='489' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ctx' type-id='type-id-566' visibility='default' filepath='./Include/internal/pycore_ast.h' line='490' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__25' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='493' column='1' id='type-id-1245'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='elts' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='494' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ctx' type-id='type-id-566' visibility='default' filepath='./Include/internal/pycore_ast.h' line='495' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__27' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='503' column='1' id='type-id-1246'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='lower' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='504' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='upper' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='505' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='step' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='506' column='1'/> + </data-member> + </class-decl> + <class-decl name='_comprehension' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='516' column='1' id='type-id-1247'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='target' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='517' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='iter' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='518' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ifs' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='519' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='is_async' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='520' column='1'/> + </data-member> + </class-decl> + <class-decl name='_arguments' size-in-bits='448' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='540' column='1' id='type-id-1248'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='posonlyargs' type-id='type-id-565' visibility='default' filepath='./Include/internal/pycore_ast.h' line='541' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='args' type-id='type-id-565' visibility='default' filepath='./Include/internal/pycore_ast.h' line='542' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='vararg' type-id='type-id-567' visibility='default' filepath='./Include/internal/pycore_ast.h' line='543' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='kwonlyargs' type-id='type-id-565' visibility='default' filepath='./Include/internal/pycore_ast.h' line='544' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='kw_defaults' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='545' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='kwarg' type-id='type-id-567' visibility='default' filepath='./Include/internal/pycore_ast.h' line='546' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='defaults' type-id='type-id-503' visibility='default' filepath='./Include/internal/pycore_ast.h' line='547' column='1'/> + </data-member> + </class-decl> + <class-decl name='_arg' size-in-bits='320' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='550' column='1' id='type-id-1249'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='arg' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='551' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='annotation' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='552' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='type_comment' type-id='type-id-528' visibility='default' filepath='./Include/internal/pycore_ast.h' line='553' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='554' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='555' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='556' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='557' column='1'/> + </data-member> + </class-decl> + <class-decl name='_keyword' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_ast.h' line='560' column='1' id='type-id-1250'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='arg' type-id='type-id-525' visibility='default' filepath='./Include/internal/pycore_ast.h' line='561' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='value' type-id='type-id-502' visibility='default' filepath='./Include/internal/pycore_ast.h' line='562' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='563' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='564' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='565' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_ast.h' line='566' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyArena' type-id='type-id-1149' filepath='./Include/internal/pycore_pyarena.h' line='14' column='1' id='type-id-1251'/> + <typedef-decl name='PyCFunction' type-id='type-id-1252' filepath='./Include/methodobject.h' line='19' column='1' id='type-id-388'/> + <class-decl name='PyMethodDef' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/methodobject.h' line='54' column='1' id='type-id-1253'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ml_name' type-id='type-id-12' visibility='default' filepath='./Include/methodobject.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ml_meth' type-id='type-id-388' visibility='default' filepath='./Include/methodobject.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ml_flags' type-id='type-id-8' visibility='default' filepath='./Include/methodobject.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ml_doc' type-id='type-id-12' visibility='default' filepath='./Include/methodobject.h' line='59' column='1'/> + </data-member> + </class-decl> + <class-decl name='_object' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/object.h' line='166' column='1' id='type-id-1254'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='' type-id='type-id-1255' visibility='default'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='ob_type' type-id='type-id-1' visibility='default' filepath='./Include/object.h' line='174' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__' size-in-bits='64' is-anonymous='yes' visibility='default' filepath='./Include/object.h' line='168' column='1' id='type-id-1255'> + <data-member access='public'> + <var-decl name='ob_refcnt' type-id='type-id-14' visibility='default' filepath='./Include/object.h' line='169' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='ob_refcnt_split' type-id='type-id-1157' visibility='default' filepath='./Include/object.h' line='171' column='1'/> + </data-member> + </union-decl> + <class-decl name='PyVarObject' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-321' visibility='default' filepath='./Include/object.h' line='180' column='1' id='type-id-1256'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/object.h' line='181' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ob_size' type-id='type-id-14' visibility='default' filepath='./Include/object.h' line='182' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyVarObject' type-id='type-id-1256' filepath='./Include/object.h' line='183' column='1' id='type-id-321'/> + <typedef-decl name='unaryfunc' type-id='type-id-1257' filepath='./Include/object.h' line='289' column='1' id='type-id-1163'/> + <typedef-decl name='binaryfunc' type-id='type-id-1252' filepath='./Include/object.h' line='290' column='1' id='type-id-1161'/> + <typedef-decl name='ternaryfunc' type-id='type-id-1258' filepath='./Include/object.h' line='291' column='1' id='type-id-1162'/> + <typedef-decl name='inquiry' type-id='type-id-339' filepath='./Include/object.h' line='292' column='1' id='type-id-396'/> + <typedef-decl name='lenfunc' type-id='type-id-1259' filepath='./Include/object.h' line='293' column='1' id='type-id-1166'/> + <typedef-decl name='ssizeargfunc' type-id='type-id-1260' filepath='./Include/object.h' line='294' column='1' id='type-id-1167'/> + <typedef-decl name='ssizeobjargproc' type-id='type-id-1261' filepath='./Include/object.h' line='296' column='1' id='type-id-1168'/> + <typedef-decl name='objobjargproc' type-id='type-id-1262' filepath='./Include/object.h' line='298' column='1' id='type-id-1172'/> + <typedef-decl name='objobjproc' type-id='type-id-1263' filepath='./Include/object.h' line='300' column='1' id='type-id-1169'/> + <typedef-decl name='visitproc' type-id='type-id-236' filepath='./Include/object.h' line='301' column='1' id='type-id-341'/> + <typedef-decl name='traverseproc' type-id='type-id-1264' filepath='./Include/object.h' line='302' column='1' id='type-id-395'/> + <typedef-decl name='freefunc' type-id='type-id-758' filepath='./Include/object.h' line='305' column='1' id='type-id-397'/> + <typedef-decl name='destructor' type-id='type-id-312' filepath='./Include/object.h' line='306' column='1' id='type-id-335'/> + <typedef-decl name='getattrfunc' type-id='type-id-1265' filepath='./Include/object.h' line='307' column='1' id='type-id-1181'/> + <typedef-decl name='getattrofunc' type-id='type-id-1252' filepath='./Include/object.h' line='308' column='1' id='type-id-1189'/> + <typedef-decl name='setattrfunc' type-id='type-id-1266' filepath='./Include/object.h' line='309' column='1' id='type-id-1182'/> + <typedef-decl name='setattrofunc' type-id='type-id-1262' filepath='./Include/object.h' line='310' column='1' id='type-id-1190'/> + <typedef-decl name='reprfunc' type-id='type-id-1257' filepath='./Include/object.h' line='311' column='1' id='type-id-1184'/> + <typedef-decl name='hashfunc' type-id='type-id-1267' filepath='./Include/object.h' line='312' column='1' id='type-id-1188'/> + <typedef-decl name='richcmpfunc' type-id='type-id-1268' filepath='./Include/object.h' line='313' column='1' id='type-id-1192'/> + <typedef-decl name='getiterfunc' type-id='type-id-1257' filepath='./Include/object.h' line='314' column='1' id='type-id-1193'/> + <typedef-decl name='iternextfunc' type-id='type-id-1257' filepath='./Include/object.h' line='315' column='1' id='type-id-1194'/> + <typedef-decl name='descrgetfunc' type-id='type-id-1258' filepath='./Include/object.h' line='316' column='1' id='type-id-1195'/> + <typedef-decl name='descrsetfunc' type-id='type-id-1262' filepath='./Include/object.h' line='317' column='1' id='type-id-1196'/> + <typedef-decl name='initproc' type-id='type-id-1262' filepath='./Include/object.h' line='318' column='1' id='type-id-1197'/> + <typedef-decl name='newfunc' type-id='type-id-1269' filepath='./Include/object.h' line='319' column='1' id='type-id-1199'/> + <typedef-decl name='allocfunc' type-id='type-id-1270' filepath='./Include/object.h' line='320' column='1' id='type-id-1198'/> + <typedef-decl name='vectorcallfunc' type-id='type-id-1271' filepath='./Include/object.h' line='323' column='1' id='type-id-311'/> + <enum-decl name='PySendResult' naming-typedef-id='type-id-255' filepath='./Include/object.h' line='856' column='1' id='type-id-1272'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PYGEN_RETURN' value='0'/> + <enumerator name='PYGEN_ERROR' value='-1'/> + <enumerator name='PYGEN_NEXT' value='1'/> + </enum-decl> + <typedef-decl name='PySendResult' type-id='type-id-1272' filepath='./Include/object.h' line='860' column='1' id='type-id-255'/> + <class-decl name='Py_buffer' size-in-bits='640' is-struct='yes' naming-typedef-id='type-id-243' visibility='default' filepath='./Include/pybuffer.h' line='20' column='1' id='type-id-1273'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='buf' type-id='type-id-22' visibility='default' filepath='./Include/pybuffer.h' line='21' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='obj' type-id='type-id-2' visibility='default' filepath='./Include/pybuffer.h' line='22' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='len' type-id='type-id-14' visibility='default' filepath='./Include/pybuffer.h' line='23' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='itemsize' type-id='type-id-14' visibility='default' filepath='./Include/pybuffer.h' line='24' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='readonly' type-id='type-id-8' visibility='default' filepath='./Include/pybuffer.h' line='26' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='ndim' type-id='type-id-8' visibility='default' filepath='./Include/pybuffer.h' line='27' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='format' type-id='type-id-15' visibility='default' filepath='./Include/pybuffer.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='shape' type-id='type-id-13' visibility='default' filepath='./Include/pybuffer.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='strides' type-id='type-id-13' visibility='default' filepath='./Include/pybuffer.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='suboffsets' type-id='type-id-13' visibility='default' filepath='./Include/pybuffer.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='internal' type-id='type-id-22' visibility='default' filepath='./Include/pybuffer.h' line='32' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Py_buffer' type-id='type-id-1273' filepath='./Include/pybuffer.h' line='33' column='1' id='type-id-243'/> + <typedef-decl name='getbufferproc' type-id='type-id-1274' filepath='./Include/pybuffer.h' line='35' column='1' id='type-id-434'/> + <typedef-decl name='releasebufferproc' type-id='type-id-1275' filepath='./Include/pybuffer.h' line='36' column='1' id='type-id-1179'/> + <typedef-decl name='Py_ssize_t' type-id='type-id-185' filepath='./Include/pyport.h' line='131' column='1' id='type-id-14'/> + <typedef-decl name='Py_hash_t' type-id='type-id-14' filepath='./Include/pyport.h' line='145' column='1' id='type-id-305'/> + <typedef-decl name='PyMethodDef' type-id='type-id-1253' filepath='./Include/pytypedefs.h' line='14' column='1' id='type-id-1276'/> + <typedef-decl name='PyGetSetDef' type-id='type-id-1203' filepath='./Include/pytypedefs.h' line='15' column='1' id='type-id-1277'/> + <typedef-decl name='PyMemberDef' type-id='type-id-1204' filepath='./Include/pytypedefs.h' line='16' column='1' id='type-id-1278'/> + <typedef-decl name='PyObject' type-id='type-id-1254' filepath='./Include/pytypedefs.h' line='18' column='1' id='type-id-345'/> + <typedef-decl name='PyTypeObject' type-id='type-id-1180' filepath='./Include/pytypedefs.h' line='20' column='1' id='type-id-256'/> + <typedef-decl name='uint32_t' type-id='type-id-1051' filepath='/usr/include/x86_64-linux-gnu/bits/stdint-uintn.h' line='26' column='1' id='type-id-352'/> + <typedef-decl name='__uint32_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='42' column='1' id='type-id-1051'/> + <typedef-decl name='__off_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='152' column='1' id='type-id-1279'/> + <typedef-decl name='__off64_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='153' column='1' id='type-id-9'/> + <typedef-decl name='__ssize_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='194' column='1' id='type-id-186'/> + <typedef-decl name='FILE' type-id='type-id-1280' filepath='/usr/include/x86_64-linux-gnu/bits/types/FILE.h' line='7' column='1' id='type-id-1281'/> + <typedef-decl name='_IO_lock_t' type-id='type-id-46' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='43' column='1' id='type-id-1282'/> + <class-decl name='_IO_FILE' size-in-bits='1728' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='49' column='1' id='type-id-1280'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_flags' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='_IO_read_ptr' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='_IO_read_end' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='_IO_read_base' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='_IO_write_base' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='_IO_write_ptr' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='_IO_write_end' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='_IO_buf_base' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='_IO_buf_end' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='_IO_save_base' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='_IO_backup_base' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='_IO_save_end' type-id='type-id-15' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='_markers' type-id='type-id-1283' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='_chain' type-id='type-id-1284' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='_fileno' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='928'> + <var-decl name='_flags2' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='_old_offset' type-id='type-id-1279' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1024'> + <var-decl name='_cur_column' type-id='type-id-84' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1040'> + <var-decl name='_vtable_offset' type-id='type-id-1034' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1048'> + <var-decl name='_shortbuf' type-id='type-id-702' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='_lock' type-id='type-id-1285' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='_offset' type-id='type-id-9' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='_codecvt' type-id='type-id-1286' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1280'> + <var-decl name='_wide_data' type-id='type-id-1287' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='_freeres_list' type-id='type-id-1284' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1408'> + <var-decl name='_freeres_buf' type-id='type-id-22' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='94' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1472'> + <var-decl name='__pad5' type-id='type-id-19' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1536'> + <var-decl name='_mode' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1568'> + <var-decl name='_unused2' type-id='type-id-1144' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h' line='98' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='ssize_t' type-id='type-id-186' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='108' column='1' id='type-id-185'/> + <class-decl name='_memo' size-in-bits='256' is-struct='yes' visibility='default' filepath='Parser/pegen.h' line='29' column='1' id='type-id-1288'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='type' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='30' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='node' type-id='type-id-22' visibility='default' filepath='Parser/pegen.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='mark' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='next' type-id='type-id-1289' visibility='default' filepath='Parser/pegen.h' line='33' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Memo' type-id='type-id-1288' filepath='Parser/pegen.h' line='34' column='1' id='type-id-1290'/> + <class-decl name='Token' size-in-bits='448' is-struct='yes' naming-typedef-id='type-id-1291' visibility='default' filepath='Parser/pegen.h' line='36' column='1' id='type-id-1292'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='type' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='bytes' type-id='type-id-2' visibility='default' filepath='Parser/pegen.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='memo' type-id='type-id-1293' visibility='default' filepath='Parser/pegen.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='metadata' type-id='type-id-2' visibility='default' filepath='Parser/pegen.h' line='42' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Token' type-id='type-id-1292' filepath='Parser/pegen.h' line='43' column='1' id='type-id-1291'/> + <class-decl name='KeywordToken' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1294' visibility='default' filepath='Parser/pegen.h' line='45' column='1' id='type-id-1295'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='str' type-id='type-id-12' visibility='default' filepath='Parser/pegen.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='type' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='47' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='KeywordToken' type-id='type-id-1295' filepath='Parser/pegen.h' line='48' column='1' id='type-id-1294'/> + <class-decl name='growable_comment_array' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1296' visibility='default' filepath='Parser/pegen.h' line='51' column='1' id='type-id-1297'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='items' type-id='type-id-1298' visibility='default' filepath='Parser/pegen.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='size' type-id='type-id-19' visibility='default' filepath='Parser/pegen.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='num_items' type-id='type-id-19' visibility='default' filepath='Parser/pegen.h' line='57' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__2' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='Parser/pegen.h' line='52' column='1' id='type-id-1299'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='comment' type-id='type-id-15' visibility='default' filepath='Parser/pegen.h' line='54' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='growable_comment_array' type-id='type-id-1297' filepath='Parser/pegen.h' line='58' column='1' id='type-id-1296'/> + <class-decl name='Parser' size-in-bits='1280' is-struct='yes' naming-typedef-id='type-id-1300' visibility='default' filepath='Parser/pegen.h' line='60' column='1' id='type-id-1301'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tok' type-id='type-id-1302' visibility='default' filepath='Parser/pegen.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='tokens' type-id='type-id-1303' visibility='default' filepath='Parser/pegen.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='mark' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='fill' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='size' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='arena' type-id='type-id-563' visibility='default' filepath='Parser/pegen.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='keywords' type-id='type-id-1304' visibility='default' filepath='Parser/pegen.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='soft_keywords' type-id='type-id-239' visibility='default' filepath='Parser/pegen.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='n_keyword_lists' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='480'> + <var-decl name='start_rule' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='errcode' type-id='type-id-179' visibility='default' filepath='Parser/pegen.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='parsing_started' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='normalize' type-id='type-id-2' visibility='default' filepath='Parser/pegen.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='starting_lineno' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='736'> + <var-decl name='starting_col_offset' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='error_indicator' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='800'> + <var-decl name='flags' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='feature_version' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='type_ignore_comments' type-id='type-id-1296' visibility='default' filepath='Parser/pegen.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1088'> + <var-decl name='known_err_token' type-id='type-id-569' visibility='default' filepath='Parser/pegen.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1152'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1184'> + <var-decl name='call_invalid_rules' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1216'> + <var-decl name='debug' type-id='type-id-8' visibility='default' filepath='Parser/pegen.h' line='82' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='Parser' type-id='type-id-1301' filepath='Parser/pegen.h' line='83' column='1' id='type-id-1300'/> + <enum-decl name='decoding_state' filepath='Parser/tokenizer.h' line='17' column='1' id='type-id-1133'> + <underlying-type type-id='type-id-24'/> + <enumerator name='STATE_INIT' value='0'/> + <enumerator name='STATE_SEEK_CODING' value='1'/> + <enumerator name='STATE_NORMAL' value='2'/> + </enum-decl> + <enum-decl name='interactive_underflow_t' filepath='Parser/tokenizer.h' line='23' column='1' id='type-id-1134'> + <underlying-type type-id='type-id-24'/> + <enumerator name='IUNDERFLOW_NORMAL' value='0'/> + <enumerator name='IUNDERFLOW_STOP' value='1'/> + </enum-decl> + <class-decl name='token' size-in-bits='384' is-struct='yes' visibility='default' filepath='Parser/tokenizer.h' line='31' column='1' id='type-id-1305'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='32' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='end' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='metadata' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='35' column='1'/> + </data-member> + </class-decl> + <enum-decl name='tokenizer_mode_kind_t' filepath='Parser/tokenizer.h' line='38' column='1' id='type-id-1306'> + <underlying-type type-id='type-id-24'/> + <enumerator name='TOK_REGULAR_MODE' value='0'/> + <enumerator name='TOK_FSTRING_MODE' value='1'/> + </enum-decl> + <class-decl name='_tokenizer_mode' size-in-bits='768' is-struct='yes' visibility='default' filepath='Parser/tokenizer.h' line='45' column='1' id='type-id-1307'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='kind' type-id='type-id-1306' visibility='default' filepath='Parser/tokenizer.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='curly_bracket_depth' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='curly_bracket_expr_start_depth' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='f_string_quote' type-id='type-id-48' visibility='default' filepath='Parser/tokenizer.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='f_string_quote_size' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='f_string_raw' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='f_string_start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='f_string_multi_line_start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='f_string_line_start' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='f_string_start_offset' type-id='type-id-14' visibility='default' filepath='Parser/tokenizer.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='f_string_multi_line_start_offset' type-id='type-id-14' visibility='default' filepath='Parser/tokenizer.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='last_expr_size' type-id='type-id-14' visibility='default' filepath='Parser/tokenizer.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='last_expr_end' type-id='type-id-14' visibility='default' filepath='Parser/tokenizer.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='last_expr_buffer' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='f_string_debug' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='64' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='tokenizer_mode' type-id='type-id-1307' filepath='Parser/tokenizer.h' line='65' column='1' id='type-id-1155'/> + <class-decl name='tok_state' size-in-bits='138176' is-struct='yes' visibility='default' filepath='Parser/tokenizer.h' line='68' column='1' id='type-id-1129'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='buf' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='cur' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='inp' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='fp_interactive' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='interactive_src_start' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='interactive_src_end' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='end' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='done' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='fp' type-id='type-id-229' visibility='default' filepath='Parser/tokenizer.h' line='81' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='tabsize' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='672'> + <var-decl name='indent' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='indstack' type-id='type-id-1130' visibility='default' filepath='Parser/tokenizer.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3904'> + <var-decl name='atbol' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3936'> + <var-decl name='pendin' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='3968'> + <var-decl name='prompt' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4032'> + <var-decl name='nextprompt' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4096'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4128'> + <var-decl name='first_lineno' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4160'> + <var-decl name='starting_col_offset' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4192'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4224'> + <var-decl name='level' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='93' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='4256'> + <var-decl name='parenstack' type-id='type-id-1131' visibility='default' filepath='Parser/tokenizer.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='5856'> + <var-decl name='parenlinenostack' type-id='type-id-1132' visibility='default' filepath='Parser/tokenizer.h' line='96' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='12256'> + <var-decl name='parencolstack' type-id='type-id-1132' visibility='default' filepath='Parser/tokenizer.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18688'> + <var-decl name='filename' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='18752'> + <var-decl name='altindstack' type-id='type-id-1130' visibility='default' filepath='Parser/tokenizer.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21952'> + <var-decl name='decoding_state' type-id='type-id-1133' visibility='default' filepath='Parser/tokenizer.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='21984'> + <var-decl name='decoding_erred' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='103' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22016'> + <var-decl name='encoding' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='104' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22080'> + <var-decl name='cont_line' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='105' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22144'> + <var-decl name='line_start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='106' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22208'> + <var-decl name='multi_line_start' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='107' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22272'> + <var-decl name='decoding_readline' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='110' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22336'> + <var-decl name='decoding_buffer' type-id='type-id-2' visibility='default' filepath='Parser/tokenizer.h' line='111' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22400'> + <var-decl name='enc' type-id='type-id-12' visibility='default' filepath='Parser/tokenizer.h' line='112' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22464'> + <var-decl name='str' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='113' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22528'> + <var-decl name='input' type-id='type-id-15' visibility='default' filepath='Parser/tokenizer.h' line='114' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22592'> + <var-decl name='type_comments' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='116' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22624'> + <var-decl name='async_hacks' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='119' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22656'> + <var-decl name='async_def' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='120' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22688'> + <var-decl name='async_def_indent' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='121' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22720'> + <var-decl name='async_def_nl' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='122' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22752'> + <var-decl name='interactive_underflow' type-id='type-id-1134' visibility='default' filepath='Parser/tokenizer.h' line='125' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22784'> + <var-decl name='report_warnings' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='126' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='22848'> + <var-decl name='tok_mode_stack' type-id='type-id-1135' visibility='default' filepath='Parser/tokenizer.h' line='128' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138048'> + <var-decl name='tok_mode_stack_index' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='129' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138080'> + <var-decl name='tok_report_warnings' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='130' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138112'> + <var-decl name='tok_extra_tokens' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='131' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='138144'> + <var-decl name='comment_newline' type-id='type-id-8' visibility='default' filepath='Parser/tokenizer.h' line='132' column='1'/> + </data-member> + </class-decl> + <pointer-type-def type-id='type-id-1281' size-in-bits='64' id='type-id-229'/> + <pointer-type-def type-id='type-id-1294' size-in-bits='64' id='type-id-1308'/> + <pointer-type-def type-id='type-id-1308' size-in-bits='64' id='type-id-1304'/> + <pointer-type-def type-id='type-id-1290' size-in-bits='64' id='type-id-1293'/> + <pointer-type-def type-id='type-id-1300' size-in-bits='64' id='type-id-568'/> + <pointer-type-def type-id='type-id-1251' size-in-bits='64' id='type-id-563'/> + <pointer-type-def type-id='type-id-1175' size-in-bits='64' id='type-id-1183'/> + <pointer-type-def type-id='type-id-1177' size-in-bits='64' id='type-id-1191'/> + <pointer-type-def type-id='type-id-1277' size-in-bits='64' id='type-id-338'/> + <pointer-type-def type-id='type-id-1170' size-in-bits='64' id='type-id-1187'/> + <pointer-type-def type-id='type-id-1278' size-in-bits='64' id='type-id-336'/> + <pointer-type-def type-id='type-id-1276' size-in-bits='64' id='type-id-337'/> + <pointer-type-def type-id='type-id-1159' size-in-bits='64' id='type-id-1185'/> + <pointer-type-def type-id='type-id-345' size-in-bits='64' id='type-id-2'/> + <pointer-type-def type-id='type-id-1309' size-in-bits='64' id='type-id-1257'/> + <pointer-type-def type-id='type-id-1310' size-in-bits='64' id='type-id-1271'/> + <pointer-type-def type-id='type-id-1311' size-in-bits='64' id='type-id-1252'/> + <pointer-type-def type-id='type-id-1312' size-in-bits='64' id='type-id-1258'/> + <pointer-type-def type-id='type-id-1313' size-in-bits='64' id='type-id-1268'/> + <pointer-type-def type-id='type-id-1314' size-in-bits='64' id='type-id-1265'/> + <pointer-type-def type-id='type-id-1315' size-in-bits='64' id='type-id-1260'/> + <pointer-type-def type-id='type-id-1085' size-in-bits='64' id='type-id-730'/> + <pointer-type-def type-id='type-id-1316' size-in-bits='64' id='type-id-1269'/> + <pointer-type-def type-id='type-id-1317' size-in-bits='64' id='type-id-1270'/> + <qualified-type-def type-id='type-id-2' const='yes' id='type-id-1318'/> + <pointer-type-def type-id='type-id-1318' size-in-bits='64' id='type-id-248'/> + <pointer-type-def type-id='type-id-2' size-in-bits='64' id='type-id-233'/> + <pointer-type-def type-id='type-id-1164' size-in-bits='64' id='type-id-1186'/> + <pointer-type-def type-id='type-id-256' size-in-bits='64' id='type-id-1'/> + <pointer-type-def type-id='type-id-243' size-in-bits='64' id='type-id-254'/> + <pointer-type-def type-id='type-id-14' size-in-bits='64' id='type-id-13'/> + <pointer-type-def type-id='type-id-1291' size-in-bits='64' id='type-id-569'/> + <pointer-type-def type-id='type-id-569' size-in-bits='64' id='type-id-1303'/> + <pointer-type-def type-id='type-id-1280' size-in-bits='64' id='type-id-1284'/> + <pointer-type-def type-id='type-id-1145' size-in-bits='64' id='type-id-1286'/> + <pointer-type-def type-id='type-id-1282' size-in-bits='64' id='type-id-1285'/> + <pointer-type-def type-id='type-id-1146' size-in-bits='64' id='type-id-1283'/> + <pointer-type-def type-id='type-id-1147' size-in-bits='64' id='type-id-1287'/> + <pointer-type-def type-id='type-id-1299' size-in-bits='64' id='type-id-1298'/> + <pointer-type-def type-id='type-id-1148' size-in-bits='64' id='type-id-306'/> + <pointer-type-def type-id='type-id-1249' size-in-bits='64' id='type-id-1214'/> + <pointer-type-def type-id='type-id-1248' size-in-bits='64' id='type-id-1213'/> + <pointer-type-def type-id='type-id-1247' size-in-bits='64' id='type-id-1212'/> + <pointer-type-def type-id='type-id-960' size-in-bits='64' id='type-id-1207'/> + <pointer-type-def type-id='type-id-1250' size-in-bits='64' id='type-id-1215'/> + <pointer-type-def type-id='type-id-1288' size-in-bits='64' id='type-id-1289'/> + <pointer-type-def type-id='type-id-1220' size-in-bits='64' id='type-id-565'/> + <pointer-type-def type-id='type-id-1218' size-in-bits='64' id='type-id-1138'/> + <pointer-type-def type-id='type-id-1216' size-in-bits='64' id='type-id-503'/> + <pointer-type-def type-id='type-id-1205' size-in-bits='64' id='type-id-564'/> + <pointer-type-def type-id='type-id-1222' size-in-bits='64' id='type-id-529'/> + <pointer-type-def type-id='type-id-15' size-in-bits='64' id='type-id-239'/> + <pointer-type-def type-id='type-id-354' size-in-bits='64' id='type-id-339'/> + <pointer-type-def type-id='type-id-1319' size-in-bits='64' id='type-id-1263'/> + <pointer-type-def type-id='type-id-1320' size-in-bits='64' id='type-id-1262'/> + <pointer-type-def type-id='type-id-1321' size-in-bits='64' id='type-id-1201'/> + <pointer-type-def type-id='type-id-1322' size-in-bits='64' id='type-id-1274'/> + <pointer-type-def type-id='type-id-1323' size-in-bits='64' id='type-id-1266'/> + <pointer-type-def type-id='type-id-1324' size-in-bits='64' id='type-id-1261'/> + <pointer-type-def type-id='type-id-1325' size-in-bits='64' id='type-id-1264'/> + <pointer-type-def type-id='type-id-238' size-in-bits='64' id='type-id-236'/> + <pointer-type-def type-id='type-id-8' size-in-bits='64' id='type-id-179'/> + <pointer-type-def type-id='type-id-1129' size-in-bits='64' id='type-id-1302'/> + <pointer-type-def type-id='type-id-1305' size-in-bits='64' id='type-id-1326'/> + <pointer-type-def type-id='type-id-1327' size-in-bits='64' id='type-id-1173'/> + <pointer-type-def type-id='type-id-1328' size-in-bits='64' id='type-id-1267'/> + <pointer-type-def type-id='type-id-1329' size-in-bits='64' id='type-id-1259'/> + <pointer-type-def type-id='type-id-314' size-in-bits='64' id='type-id-312'/> + <pointer-type-def type-id='type-id-1330' size-in-bits='64' id='type-id-1275'/> + <pointer-type-def type-id='type-id-1086' size-in-bits='64' id='type-id-758'/> + <pointer-type-def type-id='type-id-46' size-in-bits='64' id='type-id-22'/> + <pointer-type-def type-id='type-id-22' size-in-bits='64' id='type-id-253'/> + <class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1145'/> + <class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1146'/> + <class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1147'/> + <class-decl name='_arena' is-struct='yes' visibility='default' is-declaration-only='yes' id='type-id-1149'/> + <function-decl name='PyBytes_FromStringAndSize' mangled-name='PyBytes_FromStringAndSize' filepath='./Include/bytesobject.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_FromStringAndSize'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyBytes_AsString' mangled-name='PyBytes_AsString' filepath='./Include/bytesobject.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_AsString'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='PyBytes_AsStringAndSize' mangled-name='PyBytes_AsStringAndSize' filepath='./Include/bytesobject.h' line='54' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyBytes_AsStringAndSize'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-239'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_FastCall' mangled-name='_PyObject_FastCall' filepath='./Include/cpython/abstract.h' line='83' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_FastCall'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyComplex_FromCComplex' mangled-name='PyComplex_FromCComplex' filepath='./Include/cpython/complexobject.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyComplex_FromCComplex'> + <parameter type-id='type-id-327'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_GetModuleAttrString' mangled-name='_PyImport_GetModuleAttrString' filepath='./Include/cpython/import.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_GetModuleAttrString'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyType_Name' mangled-name='_PyType_Name' filepath='./Include/cpython/object.h' line='273' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyType_Name'> + <parameter type-id='type-id-1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyUnicode_AsUTF8' mangled-name='PyUnicode_AsUTF8' filepath='./Include/cpython/unicodeobject.h' line='625' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUTF8'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyFloat_FromDouble' mangled-name='PyFloat_FromDouble' filepath='./Include/floatobject.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyFloat_FromDouble'> + <parameter type-id='type-id-251'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyAST_Constant' filepath='./Include/internal/pycore_ast.h' line='822' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-552'/> + <parameter type-id='type-id-528'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyAST_Name' filepath='./Include/internal/pycore_ast.h' line='834' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-525'/> + <parameter type-id='type-id-566'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-502'/> + </function-decl> + <function-decl name='_PyArena_Malloc' mangled-name='_PyArena_Malloc' filepath='./Include/internal/pycore_pyarena.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArena_Malloc'> + <parameter type-id='type-id-563'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyArena_AddPyObject' mangled-name='_PyArena_AddPyObject' filepath='./Include/internal/pycore_pyarena.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArena_AddPyObject'> + <parameter type-id='type-id-563'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyLong_FromLong' mangled-name='PyLong_FromLong' filepath='./Include/longobject.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromLong'> + <parameter type-id='type-id-47'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyLong_FromString' mangled-name='PyLong_FromString' filepath='./Include/longobject.h' line='74' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyLong_FromString'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyOS_strtoul' mangled-name='PyOS_strtoul' filepath='./Include/longobject.h' line='79' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_strtoul'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyOS_strtol' mangled-name='PyOS_strtol' filepath='./Include/longobject.h' line='80' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_strtol'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='_Py_Dealloc' mangled-name='_Py_Dealloc' filepath='./Include/object.h' line='603' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_Dealloc'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_Occurred' mangled-name='PyErr_Occurred' filepath='./Include/pyerrors.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Occurred'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_Clear' mangled-name='PyErr_Clear' filepath='./Include/pyerrors.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Clear'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_GetRaisedException' mangled-name='PyErr_GetRaisedException' filepath='./Include/pyerrors.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_GetRaisedException'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_ExceptionMatches' mangled-name='PyErr_ExceptionMatches' filepath='./Include/pyerrors.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_ExceptionMatches'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_NoMemory' mangled-name='PyErr_NoMemory' filepath='./Include/pyerrors.h' line='169' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_NoMemory'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_Format' mangled-name='PyErr_Format' filepath='./Include/pyerrors.h' line='182' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Format'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMem_Malloc' mangled-name='PyMem_Malloc' filepath='./Include/pymem.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_Malloc'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyMem_Calloc' mangled-name='PyMem_Calloc' filepath='./Include/pymem.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_Calloc'> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyMem_Realloc' mangled-name='PyMem_Realloc' filepath='./Include/pymem.h' line='54' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_Realloc'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyMem_Free' mangled-name='PyMem_Free' filepath='./Include/pymem.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMem_Free'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyOS_string_to_double' mangled-name='PyOS_string_to_double' filepath='./Include/pystrtod.h' line='9' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_string_to_double'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-239'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='PyUnicode_InternInPlace' mangled-name='PyUnicode_InternInPlace' filepath='./Include/unicodeobject.h' line='254' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_InternInPlace'> + <parameter type-id='type-id-233'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnicode_InternFromString' mangled-name='PyUnicode_InternFromString' filepath='./Include/unicodeobject.h' line='255' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_InternFromString'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF8' mangled-name='PyUnicode_DecodeUTF8' filepath='./Include/unicodeobject.h' line='437' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF8'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_CompareWithASCIIString' mangled-name='PyUnicode_CompareWithASCIIString' filepath='./Include/unicodeobject.h' line='963' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_CompareWithASCIIString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='__errno_location' filepath='/usr/include/errno.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-179'/> + </function-decl> + <function-decl name='strncpy' filepath='/usr/include/string.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='strncmp' filepath='/usr/include/string.h' line='159' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='strchr' filepath='/usr/include/string.h' line='246' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='strlen' filepath='/usr/include/string.h' line='407' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='_Pypegen_raise_decode_error' filepath='Parser/pegen.h' line='162' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_raise_tokenizer_init_error' filepath='Parser/pegen.h' line='163' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Pypegen_tokenizer_error' filepath='Parser/pegen.h' line='164' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_raise_error' filepath='Parser/pegen.h' line='165' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_raise_error_known_location' filepath='Parser/pegen.h' line='166' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-306'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_Pypegen_set_syntax_error' filepath='Parser/pegen.h' line='170' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <parameter type-id='type-id-569'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPegen_parse' filepath='Parser/pegen.h' line='361' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyTokenizer_FromString' filepath='Parser/tokenizer.h' line='138' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-1302'/> + </function-decl> + <function-decl name='_PyTokenizer_FromUTF8' filepath='Parser/tokenizer.h' line='139' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-1302'/> + </function-decl> + <function-decl name='_PyTokenizer_FromFile' filepath='Parser/tokenizer.h' line='140' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-1302'/> + </function-decl> + <function-decl name='_PyTokenizer_Free' filepath='Parser/tokenizer.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1302'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyToken_Free' filepath='Parser/tokenizer.h' line='143' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1326'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyToken_Init' filepath='Parser/tokenizer.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1326'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTokenizer_Get' filepath='Parser/tokenizer.h' line='145' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1302'/> + <parameter type-id='type-id-1326'/> + <return type-id='type-id-8'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1309'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1310'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1311'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1312'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1313'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1314'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-15'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1315'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1316'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1317'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1319'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1320'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1321'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1322'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-254'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1323'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1324'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1325'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-341'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1327'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-255'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1328'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-305'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1329'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-14'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1330'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-254'/> + <return type-id='type-id-46'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Parser/pegen_errors.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyErr_ProgramDecodedTextObject' mangled-name='_PyErr_ProgramDecodedTextObject' filepath='./Include/cpython/pyerrors.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_ProgramDecodedTextObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_BuildValue' mangled-name='Py_BuildValue' filepath='./Include/modsupport.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_BuildValue'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_Str' mangled-name='PyObject_Str' filepath='./Include/object.h' line='387' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_Str'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SetNone' mangled-name='PyErr_SetNone' filepath='./Include/pyerrors.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetNone'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_SetObject' mangled-name='PyErr_SetObject' filepath='./Include/pyerrors.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_Fetch' mangled-name='PyErr_Fetch' filepath='./Include/pyerrors.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Fetch'> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_Restore' mangled-name='PyErr_Restore' filepath='./Include/pyerrors.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Restore'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyTuple_Pack' mangled-name='PyTuple_Pack' filepath='./Include/tupleobject.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTuple_Pack'> + <parameter type-id='type-id-14'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_FromStringAndSize' mangled-name='PyUnicode_FromStringAndSize' filepath='./Include/unicodeobject.h' line='130' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromStringAndSize'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_FromFormatV' mangled-name='PyUnicode_FromFormatV' filepath='./Include/unicodeobject.h' line='245' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromFormatV'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-306'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='memcpy' filepath='/usr/include/string.h' line='43' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyPegen_fill_token' filepath='Parser/pegen.h' line='149' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-568'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPegen_byte_offset_to_character_offset' filepath='Parser/pegen.h' line='153' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-14'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Parser/string_parser.c' comp-dir-path='/src' language='LANG_C11'> + <pointer-type-def type-id='type-id-12' size-in-bits='64' id='type-id-252'/> + <function-decl name='_PyBytes_DecodeEscape' mangled-name='_PyBytes_DecodeEscape' filepath='./Include/cpython/bytesobject.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyBytes_DecodeEscape'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-252'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_DecodeUnicodeEscapeInternal' mangled-name='_PyUnicode_DecodeUnicodeEscapeInternal' filepath='./Include/cpython/unicodeobject.h' line='685' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_DecodeUnicodeEscapeInternal'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-13'/> + <parameter type-id='type-id-252'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_WarnExplicitObject' mangled-name='PyErr_WarnExplicitObject' filepath='./Include/cpython/warnings.h' line='5' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_WarnExplicitObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_SetString' mangled-name='PyErr_SetString' filepath='./Include/pyerrors.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_BadInternalCall' mangled-name='_PyErr_BadInternalCall' filepath='./Include/pyerrors.h' line='225' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_BadInternalCall'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnicode_FromFormat' mangled-name='PyUnicode_FromFormat' filepath='./Include/unicodeobject.h' line='249' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_FromFormat'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_DecodeUTF8Stateful' mangled-name='PyUnicode_DecodeUTF8Stateful' filepath='./Include/unicodeobject.h' line='443' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_DecodeUTF8Stateful'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='sprintf' filepath='/usr/include/stdio.h' line='358' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Parser/token.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-430' size-in-bits='4416' id='type-id-1331'> + <subrange length='69' type-id='type-id-28' id='type-id-1332'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-430' size-in-bits='infinite' id='type-id-1333'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <qualified-type-def type-id='type-id-12' const='yes' id='type-id-430'/> + <var-decl name='_PyParser_TokenNames' type-id='type-id-1333' mangled-name='_PyParser_TokenNames' visibility='default' filepath='./Include/internal/pycore_token.h' line='100' column='1' elf-symbol-id='_PyParser_TokenNames'/> + <function-decl name='_PyToken_OneChar' mangled-name='_PyToken_OneChar' filepath='Parser/token.c' line='83' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyToken_OneChar'> + <parameter type-id='type-id-8' name='c1' filepath='Parser/token.c' line='83' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyToken_TwoChars' mangled-name='_PyToken_TwoChars' filepath='Parser/token.c' line='115' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyToken_TwoChars'> + <parameter type-id='type-id-8' name='c1' filepath='Parser/token.c' line='115' column='1'/> + <parameter type-id='type-id-8' name='c2' filepath='Parser/token.c' line='115' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyToken_ThreeChars' mangled-name='_PyToken_ThreeChars' filepath='Parser/token.c' line='199' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyToken_ThreeChars'> + <parameter type-id='type-id-8' name='c1' filepath='Parser/token.c' line='199' column='1'/> + <parameter type-id='type-id-8' name='c2' filepath='Parser/token.c' line='199' column='1'/> + <parameter type-id='type-id-8' name='c3' filepath='Parser/token.c' line='199' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Parser/tokenizer.c' comp-dir-path='/src' language='LANG_C11'> + <qualified-type-def type-id='type-id-84' const='yes' id='type-id-1334'/> + <pointer-type-def type-id='type-id-1334' size-in-bits='64' id='type-id-1335'/> + <pointer-type-def type-id='type-id-1335' size-in-bits='64' id='type-id-1336'/> + <pointer-type-def type-id='type-id-19' size-in-bits='64' id='type-id-441'/> + <function-decl name='PyObject_CallNoArgs' mangled-name='PyObject_CallNoArgs' filepath='./Include/abstract.h' line='146' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_CallNoArgs'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_CallFunction_SizeT' mangled-name='_PyObject_CallFunction_SizeT' filepath='./Include/abstract.h' line='198' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CallFunction_SizeT'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_CheckFunctionResult' mangled-name='_Py_CheckFunctionResult' filepath='./Include/cpython/abstract.h' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_CheckFunctionResult'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyObject_MakeTpCall' mangled-name='_PyObject_MakeTpCall' filepath='./Include/cpython/abstract.h' line='47' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_MakeTpCall'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_UniversalNewlineFgetsWithSize' mangled-name='_Py_UniversalNewlineFgetsWithSize' filepath='./Include/cpython/fileobject.h' line='6' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_UniversalNewlineFgetsWithSize'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-441'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_Py_FatalErrorFunc' mangled-name='_Py_FatalErrorFunc' filepath='./Include/cpython/pyerrors.h' line='158' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_FatalErrorFunc'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_IsPrintable' mangled-name='_PyUnicode_IsPrintable' filepath='./Include/cpython/unicodeobject.h' line='894' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_IsPrintable'> + <parameter type-id='type-id-250'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyUnicode_ScanIdentifier' mangled-name='_PyUnicode_ScanIdentifier' filepath='./Include/cpython/unicodeobject.h' line='961' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyUnicode_ScanIdentifier'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_Py_dup' mangled-name='_Py_dup' filepath='./Include/internal/pycore_fileutils.h' line='164' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_dup'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_BuildValue_SizeT' mangled-name='_Py_BuildValue_SizeT' filepath='./Include/modsupport.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_BuildValue_SizeT'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyObject_GetAttr' mangled-name='PyObject_GetAttr' filepath='./Include/object.h' line='395' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyObject_GetAttr'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SetFromErrnoWithFilename' mangled-name='PyErr_SetFromErrnoWithFilename' filepath='./Include/pyerrors.h' line='177' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetFromErrnoWithFilename'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PySys_WriteStderr' mangled-name='PySys_WriteStderr' filepath='./Include/sysmodule.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_WriteStderr'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyUnicode_Substring' mangled-name='PyUnicode_Substring' filepath='./Include/unicodeobject.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Substring'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_Decode' mangled-name='PyUnicode_Decode' filepath='./Include/unicodeobject.h' line='345' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_Decode'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsUTF8String' mangled-name='PyUnicode_AsUTF8String' filepath='./Include/unicodeobject.h' line='450' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUTF8String'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnicode_AsUTF8AndSize' mangled-name='PyUnicode_AsUTF8AndSize' filepath='./Include/unicodeobject.h' line='466' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnicode_AsUTF8AndSize'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-13'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='__ctype_b_loc' filepath='/usr/include/ctype.h' line='79' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-1336'/> + </function-decl> + <function-decl name='tolower' filepath='/usr/include/ctype.h' line='122' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fclose' filepath='/usr/include/stdio.h' line='178' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fdopen' filepath='/usr/include/stdio.h' line='293' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-229'/> + </function-decl> + <function-decl name='getc' filepath='/usr/include/stdio.h' line='514' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='ungetc' filepath='/usr/include/stdio.h' line='668' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-229'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='ftell' filepath='/usr/include/stdio.h' line='718' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='memcmp' filepath='/usr/include/string.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='memchr' filepath='/usr/include/string.h' line='107' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='strcspn' filepath='/usr/include/string.h' line='293' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-19'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/Python-ast.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyModule_AddIntConstant' mangled-name='PyModule_AddIntConstant' filepath='./Include/modsupport.h' line='51' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_AddIntConstant'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-47'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyInit__ast' mangled-name='PyInit__ast' filepath='Python/Python-ast.c' line='12916' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__ast'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/Python-tokenize.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyModule_AddType' mangled-name='PyModule_AddType' filepath='./Include/modsupport.h' line='56' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_AddType'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyInit__tokenize' mangled-name='PyInit__tokenize' filepath='Python/Python-tokenize.c' line='322' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__tokenize'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/_warnings.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_IsInterpreterFinalizing' mangled-name='_Py_IsInterpreterFinalizing' filepath='./Include/cpython/pylifecycle.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_IsInterpreterFinalizing'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySys_GetAttr' mangled-name='_PySys_GetAttr' filepath='./Include/cpython/sysmodule.h' line='5' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PySys_GetAttr'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_DisplaySourceLine' mangled-name='_Py_DisplaySourceLine' filepath='./Include/cpython/traceback.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DisplaySourceLine'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_GetModules' filepath='./Include/internal/pycore_import.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_BlessMyLoader' filepath='./Include/internal/pycore_import.h' line='135' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_AddObjectRef' mangled-name='PyModule_AddObjectRef' filepath='./Include/modsupport.h' line='45' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_AddObjectRef'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThreadState_GetFrame' mangled-name='PyThreadState_GetFrame' filepath='./Include/pystate.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetFrame'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-365'/> + </function-decl> + <function-decl name='PyErr_ResourceWarning' mangled-name='PyErr_ResourceWarning' filepath='Python/_warnings.c' line='1240' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_ResourceWarning'> + <parameter type-id='type-id-2' name='source' filepath='Python/_warnings.c' line='1240' column='1'/> + <parameter type-id='type-id-14' name='stack_level' filepath='Python/_warnings.c' line='1240' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/_warnings.c' line='1241' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_WarnExplicit' mangled-name='PyErr_WarnExplicit' filepath='Python/_warnings.c' line='1299' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_WarnExplicit'> + <parameter type-id='type-id-2' name='category' filepath='Python/_warnings.c' line='1299' column='1'/> + <parameter type-id='type-id-12' name='text' filepath='Python/_warnings.c' line='1299' column='1'/> + <parameter type-id='type-id-12' name='filename_str' filepath='Python/_warnings.c' line='1300' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/_warnings.c' line='1300' column='1'/> + <parameter type-id='type-id-12' name='module_str' filepath='Python/_warnings.c' line='1301' column='1'/> + <parameter type-id='type-id-2' name='registry' filepath='Python/_warnings.c' line='1301' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_WarnExplicitFormat' mangled-name='PyErr_WarnExplicitFormat' filepath='Python/_warnings.c' line='1327' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_WarnExplicitFormat'> + <parameter type-id='type-id-2' name='category' filepath='Python/_warnings.c' line='1327' column='1'/> + <parameter type-id='type-id-12' name='filename_str' filepath='Python/_warnings.c' line='1328' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/_warnings.c' line='1328' column='1'/> + <parameter type-id='type-id-12' name='module_str' filepath='Python/_warnings.c' line='1329' column='1'/> + <parameter type-id='type-id-2' name='registry' filepath='Python/_warnings.c' line='1329' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/_warnings.c' line='1330' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyWarnings_Init' mangled-name='_PyWarnings_Init' filepath='Python/_warnings.c' line='1467' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWarnings_Init'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/assemble.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyCompile_ConstCacheMergeOne' filepath='./Include/internal/pycore_compile.h' line='93' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCompile_InstrSize' filepath='./Include/internal/pycore_compile.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_set_localsplus_info' filepath='Python/assemble.c' line='445' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-85'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/ast_opt.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyAST_GetDocString' filepath='./Include/internal/pycore_ast.h' line='917' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-500'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='snprintf' filepath='/usr/include/stdio.h' line='378' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/bltinmodule.c' comp-dir-path='/src' language='LANG_C11'> + <pointer-type-def type-id='type-id-1149' size-in-bits='64' id='type-id-1337'/> + <var-decl name='PyFilter_Type' type-id='type-id-256' mangled-name='PyFilter_Type' visibility='default' filepath='./Include/bltinmodule.h' line='7' column='1' elf-symbol-id='PyFilter_Type'/> + <var-decl name='PyMap_Type' type-id='type-id-256' mangled-name='PyMap_Type' visibility='default' filepath='./Include/bltinmodule.h' line='8' column='1' elf-symbol-id='PyMap_Type'/> + <var-decl name='PyZip_Type' type-id='type-id-256' mangled-name='PyZip_Type' visibility='default' filepath='./Include/bltinmodule.h' line='9' column='1' elf-symbol-id='PyZip_Type'/> + <function-decl name='PyEval_EvalCode' mangled-name='PyEval_EvalCode' filepath='./Include/ceval.h' line='10' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_EvalCode'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_EvalCodeEx' mangled-name='PyEval_EvalCodeEx' filepath='./Include/ceval.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_EvalCodeEx'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_GetBuiltins' mangled-name='PyEval_GetBuiltins' filepath='./Include/ceval.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_GetBuiltins'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_MergeCompilerFlags' mangled-name='PyEval_MergeCompilerFlags' filepath='./Include/cpython/ceval.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_MergeCompilerFlags'> + <parameter type-id='type-id-208'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_StringFlags' mangled-name='PyRun_StringFlags' filepath='./Include/cpython/pythonrun.h' line='44' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_StringFlags'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-208'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_CompileStringObject' mangled-name='Py_CompileStringObject' filepath='./Include/cpython/pythonrun.h' line='63' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_CompileStringObject'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_SourceAsString' mangled-name='_Py_SourceAsString' filepath='./Include/cpython/pythonrun.h' line='73' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_SourceAsString'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyImport_ImportModuleLevelObject' mangled-name='PyImport_ImportModuleLevelObject' filepath='./Include/import.h' line='60' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ImportModuleLevelObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyAST_obj2mod' filepath='./Include/internal/pycore_ast.h' line='906' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-563'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-468'/> + </function-decl> + <function-decl name='PyAST_Check' filepath='./Include/internal/pycore_ast.h' line='907' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyAST_Validate' filepath='./Include/internal/pycore_ast.h' line='909' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-468'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyAST_Compile' mangled-name='_PyAST_Compile' filepath='./Include/internal/pycore_compile.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyAST_Compile'> + <parameter type-id='type-id-467'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1337'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='_PyFloat_ExactDealloc' filepath='./Include/internal/pycore_floatobject.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyArena_New' mangled-name='_PyArena_New' filepath='./Include/internal/pycore_pyarena.h' line='38' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArena_New'> + <return type-id='type-id-563'/> + </function-decl> + <function-decl name='_PyArena_Free' mangled-name='_PyArena_Free' filepath='./Include/internal/pycore_pyarena.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArena_Free'> + <parameter type-id='type-id-563'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_GetObject' mangled-name='PySys_GetObject' filepath='./Include/sysmodule.h' line='10' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_GetObject'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyAnextAwaitable_New' filepath='Python/bltinmodule.c' line='1642' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/bootstrap_hash.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_fstat' mangled-name='_Py_fstat' filepath='./Include/internal/pycore_fileutils.h' line='93' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_fstat'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-51'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_open' mangled-name='_Py_open' filepath='./Include/internal/pycore_fileutils.h' line='105' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_open'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_open_noraise' mangled-name='_Py_open_noraise' filepath='./Include/internal/pycore_fileutils.h' line='109' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_open_noraise'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_read' mangled-name='_Py_read' filepath='./Include/internal/pycore_fileutils.h' line='117' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_read'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='close' filepath='/usr/include/unistd.h' line='358' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='read' filepath='/usr/include/unistd.h' line='371' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='getrandom' filepath='/usr/include/x86_64-linux-gnu/sys/random.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-95'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='_PyOS_URandom' mangled-name='_PyOS_URandom' filepath='Python/bootstrap_hash.c' line='527' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyOS_URandom'> + <parameter type-id='type-id-22' name='buffer' filepath='Python/bootstrap_hash.c' line='527' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Python/bootstrap_hash.c' line='527' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyOS_URandomNonblock' mangled-name='_PyOS_URandomNonblock' filepath='Python/bootstrap_hash.c' line='541' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyOS_URandomNonblock'> + <parameter type-id='type-id-22' name='buffer' filepath='Python/bootstrap_hash.c' line='541' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Python/bootstrap_hash.c' line='541' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/ceval.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyEval_SetProfile' mangled-name='_PyEval_SetProfile' filepath='./Include/cpython/ceval.h' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SetProfile'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-764'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_SetTrace' mangled-name='_PyEval_SetTrace' filepath='./Include/cpython/ceval.h' line='10' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SetTrace'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-764'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_GetTopmostException' mangled-name='_PyErr_GetTopmostException' filepath='./Include/cpython/pyerrors.h' line='94' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_GetTopmostException'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-376'/> + </function-decl> + <function-decl name='_PyErr_WriteUnraisableMsg' mangled-name='_PyErr_WriteUnraisableMsg' filepath='./Include/cpython/pyerrors.h' line='154' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_WriteUnraisableMsg'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_SetImportErrorWithNameFrom' filepath='./Include/cpython/pyerrors.h' line='167' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInterpreterState_ThreadHead' mangled-name='PyInterpreterState_ThreadHead' filepath='./Include/cpython/pystate.h' line='316' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_ThreadHead'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='PyThreadState_Next' mangled-name='PyThreadState_Next' filepath='./Include/cpython/pystate.h' line='317' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_Next'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='_PyNumber_PowerNoMod' filepath='./Include/internal/pycore_abstract.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyNumber_InPlacePowerNoMod' filepath='./Include/internal/pycore_abstract.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyStack_UnpackDict' filepath='./Include/internal/pycore_call.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-248'/> + </function-decl> + <function-decl name='_PyStack_UnpackDict_FreeNoDecRef' filepath='./Include/internal/pycore_call.h' line='128' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_MakeCoro' filepath='./Include/internal/pycore_ceval.h' line='152' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-310'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_HandlePending' filepath='./Include/internal/pycore_ceval.h' line='154' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_Specialize_LoadSuperAttr' filepath='./Include/internal/pycore_code.h' line='227' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_LoadAttr' filepath='./Include/internal/pycore_code.h' line='229' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_StoreAttr' filepath='./Include/internal/pycore_code.h' line='231' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_LoadGlobal' filepath='./Include/internal/pycore_code.h' line='233' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_BinarySubscr' filepath='./Include/internal/pycore_code.h' line='235' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_StoreSubscr' filepath='./Include/internal/pycore_code.h' line='237' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_Call' filepath='./Include/internal/pycore_code.h' line='239' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_BinaryOp' filepath='./Include/internal/pycore_code.h' line='241' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_CompareOp' filepath='./Include/internal/pycore_code.h' line='243' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_UnpackSequence' filepath='./Include/internal/pycore_code.h' line='245' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_ForIter' filepath='./Include/internal/pycore_code.h' line='247' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Specialize_Send' filepath='./Include/internal/pycore_code.h' line='248' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Instrument' filepath='./Include/internal/pycore_code.h' line='486' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_LoadGlobal' filepath='./Include/internal/pycore_dict.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-340'/> + <parameter type-id='type-id-340'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyDict_SetItem_Take2' filepath='./Include/internal/pycore_dict.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-340'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDict_SendEvent' filepath='./Include/internal/pycore_dict.h' line='156' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-727'/> + <parameter type-id='type-id-340'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFrame_FastToLocalsWithError' filepath='./Include/internal/pycore_frame.h' line='230' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-374'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyThreadState_PushFrame' filepath='./Include/internal/pycore_frame.h' line='248' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-374'/> + </function-decl> + <function-decl name='_PyThreadState_PopFrame' filepath='./Include/internal/pycore_frame.h' line='250' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-374'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGen_yf' filepath='./Include/internal/pycore_genobject.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-373'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_IsDefaultImportFunc' filepath='./Include/internal/pycore_import.h' line='125' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_call_instrumentation' filepath='./Include/internal/pycore_instruments.h' line='67' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_line' filepath='./Include/internal/pycore_instruments.h' line='71' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_instruction' filepath='./Include/internal/pycore_instruments.h' line='75' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_jump' filepath='./Include/internal/pycore_instruments.h' line='79' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-848'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_arg' filepath='./Include/internal/pycore_instruments.h' line='84' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_2args' filepath='./Include/internal/pycore_instruments.h' line='88' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_exc0' filepath='./Include/internal/pycore_instruments.h' line='92' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_call_instrumentation_exc2' filepath='./Include/internal/pycore_instruments.h' line='96' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-848'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyList_AppendTakeRefListResize' filepath='./Include/internal/pycore_list.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-249'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyList_FromArraySteal' filepath='./Include/internal/pycore_list.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_Add' filepath='./Include/internal/pycore_long.h' line='81' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-241'/> + <parameter type-id='type-id-241'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_Multiply' filepath='./Include/internal/pycore_long.h' line='82' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-241'/> + <parameter type-id='type-id-241'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyLong_Subtract' filepath='./Include/internal/pycore_long.h' line='83' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-241'/> + <parameter type-id='type-id-241'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_SetObject' mangled-name='_PyErr_SetObject' filepath='./Include/internal/pycore_pyerrors.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_SetObject'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyBuildSlice_ConsumeRefs' filepath='./Include/internal/pycore_sliceobject.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PySys_Audit' filepath='./Include/internal/pycore_sysmodule.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTuple_FromArraySteal' filepath='./Include/internal/pycore_tuple.h' line='67' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-248'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PySuper_Lookup' filepath='./Include/internal/pycore_typeobject.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyUnicode_ExactDealloc' filepath='./Include/internal/pycore_unicodeobject.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_SetHandledException' mangled-name='PyErr_SetHandledException' filepath='./Include/pyerrors.h' line='25' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetHandledException'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyTraceBack_Here' mangled-name='PyTraceBack_Here' filepath='./Include/traceback.h' line='9' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTraceBack_Here'> + <parameter type-id='type-id-365'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_GetRecursionLimit' mangled-name='Py_GetRecursionLimit' filepath='Python/ceval.c' line='233' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetRecursionLimit'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_SetRecursionLimit' mangled-name='Py_SetRecursionLimit' filepath='Python/ceval.c' line='240' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_SetRecursionLimit'> + <parameter type-id='type-id-8' name='new_limit' filepath='Python/ceval.c' line='240' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_EvalFrame' mangled-name='PyEval_EvalFrame' filepath='Python/ceval.c' line='576' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_EvalFrame'> + <parameter type-id='type-id-365' name='f' filepath='Python/ceval.c' line='576' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_EvalFrameEx' mangled-name='PyEval_EvalFrameEx' filepath='Python/ceval.c' line='584' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_EvalFrameEx'> + <parameter type-id='type-id-365' name='f' filepath='Python/ceval.c' line='584' column='1'/> + <parameter type-id='type-id-8' name='throwflag' filepath='Python/ceval.c' line='584' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyThreadState_EnterTracing' mangled-name='PyThreadState_EnterTracing' filepath='Python/ceval.c' line='2030' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_EnterTracing'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/ceval.c' line='2030' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThreadState_LeaveTracing' mangled-name='PyThreadState_LeaveTracing' filepath='Python/ceval.c' line='2037' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_LeaveTracing'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/ceval.c' line='2037' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_SetProfile' mangled-name='PyEval_SetProfile' filepath='Python/ceval.c' line='2061' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_SetProfile'> + <parameter type-id='type-id-764' name='func' filepath='Python/ceval.c' line='2061' column='1'/> + <parameter type-id='type-id-2' name='arg' filepath='Python/ceval.c' line='2061' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_SetProfileAllThreads' mangled-name='PyEval_SetProfileAllThreads' filepath='Python/ceval.c' line='2071' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_SetProfileAllThreads'> + <parameter type-id='type-id-764' name='func' filepath='Python/ceval.c' line='2071' column='1'/> + <parameter type-id='type-id-2' name='arg' filepath='Python/ceval.c' line='2071' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_SetTrace' mangled-name='PyEval_SetTrace' filepath='Python/ceval.c' line='2092' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_SetTrace'> + <parameter type-id='type-id-764' name='func' filepath='Python/ceval.c' line='2092' column='1'/> + <parameter type-id='type-id-2' name='arg' filepath='Python/ceval.c' line='2092' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_SetTraceAllThreads' mangled-name='PyEval_SetTraceAllThreads' filepath='Python/ceval.c' line='2102' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_SetTraceAllThreads'> + <parameter type-id='type-id-764' name='func' filepath='Python/ceval.c' line='2102' column='1'/> + <parameter type-id='type-id-2' name='arg' filepath='Python/ceval.c' line='2102' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_GetFrame' mangled-name='PyEval_GetFrame' filepath='Python/ceval.c' line='2190' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_GetFrame'> + <return type-id='type-id-365'/> + </function-decl> + <function-decl name='_PyEval_GetBuiltinId' mangled-name='_PyEval_GetBuiltinId' filepath='Python/ceval.c' line='2236' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_GetBuiltinId'> + <parameter type-id='type-id-309' name='name' filepath='Python/ceval.c' line='2236' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyEval_GetFuncName' mangled-name='PyEval_GetFuncName' filepath='Python/ceval.c' line='2291' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_GetFuncName'> + <parameter type-id='type-id-2' name='func' filepath='Python/ceval.c' line='2291' column='1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyEval_GetFuncDesc' mangled-name='PyEval_GetFuncDesc' filepath='Python/ceval.c' line='2304' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_GetFuncDesc'> + <parameter type-id='type-id-2' name='func' filepath='Python/ceval.c' line='2304' column='1'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyUnstable_Eval_RequestCodeExtraIndex' mangled-name='PyUnstable_Eval_RequestCodeExtraIndex' filepath='Python/ceval.c' line='2676' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_Eval_RequestCodeExtraIndex'> + <parameter type-id='type-id-397' name='free' filepath='Python/ceval.c' line='2676' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='Py_EnterRecursiveCall' mangled-name='Py_EnterRecursiveCall' filepath='Python/ceval.c' line='2692' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_EnterRecursiveCall'> + <parameter type-id='type-id-12' name='where' filepath='Python/ceval.c' line='2692' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_LeaveRecursiveCall' mangled-name='Py_LeaveRecursiveCall' filepath='Python/ceval.c' line='2697' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_LeaveRecursiveCall'> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/ceval_gil.c' comp-dir-path='/src' language='LANG_C11'> + <union-decl name='pthread_mutexattr_t' size-in-bits='32' naming-typedef-id='type-id-1338' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='32' column='1' id='type-id-1339'> + <data-member access='public'> + <var-decl name='__size' type-id='type-id-619' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='34' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__align' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='35' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='pthread_mutexattr_t' type-id='type-id-1339' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='36' column='1' id='type-id-1338'/> + <typedef-decl name='__time_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='160' column='1' id='type-id-1340'/> + <typedef-decl name='__syscall_slong_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='197' column='1' id='type-id-116'/> + <class-decl name='timespec' size-in-bits='128' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h' line='11' column='1' id='type-id-1341'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tv_sec' type-id='type-id-1340' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='tv_nsec' type-id='type-id-116' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h' line='21' column='1'/> + </data-member> + </class-decl> + <pointer-type-def type-id='type-id-820' size-in-bits='64' id='type-id-1342'/> + <qualified-type-def type-id='type-id-1338' const='yes' id='type-id-1343'/> + <pointer-type-def type-id='type-id-1343' size-in-bits='64' id='type-id-1344'/> + <qualified-type-def type-id='type-id-1341' const='yes' id='type-id-1345'/> + <pointer-type-def type-id='type-id-1345' size-in-bits='64' id='type-id-188'/> + <qualified-type-def type-id='type-id-188' restrict='yes' id='type-id-206'/> + <pointer-type-def type-id='type-id-856' size-in-bits='64' id='type-id-1346'/> + <qualified-type-def type-id='type-id-1346' restrict='yes' id='type-id-1347'/> + <pointer-type-def type-id='type-id-857' size-in-bits='64' id='type-id-1348'/> + <qualified-type-def type-id='type-id-1348' restrict='yes' id='type-id-1349'/> + <pointer-type-def type-id='type-id-1341' size-in-bits='64' id='type-id-180'/> + <function-decl name='_PyThread_at_fork_reinit' mangled-name='_PyThread_at_fork_reinit' filepath='./Include/cpython/pythread.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_at_fork_reinit'> + <parameter type-id='type-id-1342'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyThreadState_SwapNoGIL' filepath='./Include/internal/pycore_ceval.h' line='104' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='_Py_RunGC' filepath='./Include/internal/pycore_gc.h' line='206' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_CheckSignalsTstate' mangled-name='_PyErr_CheckSignalsTstate' filepath='./Include/internal/pycore_pyerrors.h' line='104' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_CheckSignalsTstate'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_Print' mangled-name='_PyErr_Print' filepath='./Include/internal/pycore_pylifecycle.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_Print'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_DeleteExcept' mangled-name='_PyThreadState_DeleteExcept' filepath='./Include/internal/pycore_pystate.h' line='137' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_DeleteExcept'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyGILState_GetThisThreadState' mangled-name='PyGILState_GetThisThreadState' filepath='./Include/pystate.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGILState_GetThisThreadState'> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='PyThread_init_thread' mangled-name='PyThread_init_thread' filepath='./Include/pythread.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_init_thread'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThread_exit_thread' mangled-name='PyThread_exit_thread' filepath='./Include/pythread.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_exit_thread'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThread_get_thread_ident' mangled-name='PyThread_get_thread_ident' filepath='./Include/pythread.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_get_thread_ident'> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyThread_free_lock' mangled-name='PyThread_free_lock' filepath='./Include/pythread.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_free_lock'> + <parameter type-id='type-id-820'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='pthread_mutex_init' filepath='/usr/include/pthread.h' line='781' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1348'/> + <parameter type-id='type-id-1344'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_mutex_destroy' filepath='/usr/include/pthread.h' line='786' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1348'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_mutex_lock' filepath='/usr/include/pthread.h' line='794' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1348'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_mutex_unlock' filepath='/usr/include/pthread.h' line='835' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1348'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_cond_destroy' filepath='/usr/include/pthread.h' line='1117' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1346'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_cond_signal' filepath='/usr/include/pthread.h' line='1121' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1346'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_cond_wait' filepath='/usr/include/pthread.h' line='1133' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1347'/> + <parameter type-id='type-id-1349'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_cond_timedwait' filepath='/usr/include/pthread.h' line='1145' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1347'/> + <parameter type-id='type-id-1349'/> + <parameter type-id='type-id-206'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_SetSwitchInterval' mangled-name='_PyEval_SetSwitchInterval' filepath='Python/ceval_gil.c' line='468' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SetSwitchInterval'> + <parameter type-id='type-id-28' name='microseconds' filepath='Python/ceval_gil.c' line='468' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_GetSwitchInterval' mangled-name='_PyEval_GetSwitchInterval' filepath='Python/ceval_gil.c' line='476' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_GetSwitchInterval'> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyEval_ThreadsInitialized' mangled-name='PyEval_ThreadsInitialized' filepath='Python/ceval_gil.c' line='500' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_ThreadsInitialized'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyEval_InitThreads' mangled-name='PyEval_InitThreads' filepath='Python/ceval_gil.c' line='588' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_InitThreads'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_AcquireLock' mangled-name='PyEval_AcquireLock' filepath='Python/ceval_gil.c' line='601' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_AcquireLock'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_ReleaseLock' mangled-name='PyEval_ReleaseLock' filepath='Python/ceval_gil.c' line='610' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_ReleaseLock'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_AcquireThread' mangled-name='PyEval_AcquireThread' filepath='Python/ceval_gil.c' line='636' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_AcquireThread'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/ceval_gil.c' line='636' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyEval_ReleaseThread' mangled-name='PyEval_ReleaseThread' filepath='Python/ceval_gil.c' line='648' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyEval_ReleaseThread'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/ceval_gil.c' line='648' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_SignalAsyncExc' mangled-name='_PyEval_SignalAsyncExc' filepath='Python/ceval_gil.c' line='692' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SignalAsyncExc'> + <parameter type-id='type-id-20' name='interp' filepath='Python/ceval_gil.c' line='692' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_SignalReceived' mangled-name='_PyEval_SignalReceived' filepath='Python/ceval_gil.c' line='743' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_SignalReceived'> + <parameter type-id='type-id-20' name='interp' filepath='Python/ceval_gil.c' line='743' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_AddPendingCall' mangled-name='_PyEval_AddPendingCall' filepath='Python/ceval_gil.c' line='800' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyEval_AddPendingCall'> + <parameter type-id='type-id-20' name='interp' filepath='Python/ceval_gil.c' line='800' column='1'/> + <parameter type-id='type-id-815' name='func' filepath='Python/ceval_gil.c' line='801' column='1'/> + <parameter type-id='type-id-22' name='arg' filepath='Python/ceval_gil.c' line='801' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_AddPendingCall' mangled-name='Py_AddPendingCall' filepath='Python/ceval_gil.c' line='818' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_AddPendingCall'> + <parameter type-id='type-id-815' name='func' filepath='Python/ceval_gil.c' line='818' column='1'/> + <parameter type-id='type-id-22' name='arg' filepath='Python/ceval_gil.c' line='818' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_MakePendingCalls' mangled-name='Py_MakePendingCalls' filepath='Python/ceval_gil.c' line='937' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_MakePendingCalls'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyThread_cond_init' filepath='Python/condvar.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1346'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyThread_cond_after' filepath='Python/condvar.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-378'/> + <parameter type-id='type-id-180'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/codecs.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='Py_hexdigits' type-id='type-id-12' mangled-name='Py_hexdigits' visibility='default' filepath='./Include/codecs.h' line='242' column='1' elf-symbol-id='Py_hexdigits'/> + <function-decl name='PyCodec_Register' mangled-name='PyCodec_Register' filepath='Python/codecs.c' line='36' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_Register'> + <parameter type-id='type-id-2' name='search_function' filepath='Python/codecs.c' line='36' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCodec_Unregister' mangled-name='PyCodec_Unregister' filepath='Python/codecs.c' line='56' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_Unregister'> + <parameter type-id='type-id-2' name='search_function' filepath='Python/codecs.c' line='56' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_normalize_encoding' filepath='Python/codecs.c' line='80' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCodec_KnownEncoding' mangled-name='PyCodec_KnownEncoding' filepath='Python/codecs.c' line='215' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_KnownEncoding'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='215' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCodecInfo_GetIncrementalDecoder' mangled-name='_PyCodecInfo_GetIncrementalDecoder' filepath='Python/codecs.c' line='329' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCodecInfo_GetIncrementalDecoder'> + <parameter type-id='type-id-2' name='codec_info' filepath='Python/codecs.c' line='329' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/codecs.c' line='330' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCodecInfo_GetIncrementalEncoder' mangled-name='_PyCodecInfo_GetIncrementalEncoder' filepath='Python/codecs.c' line='336' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCodecInfo_GetIncrementalEncoder'> + <parameter type-id='type-id-2' name='codec_info' filepath='Python/codecs.c' line='336' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/codecs.c' line='337' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_Encoder' mangled-name='PyCodec_Encoder' filepath='Python/codecs.c' line='350' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_Encoder'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='350' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_Decoder' mangled-name='PyCodec_Decoder' filepath='Python/codecs.c' line='355' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_Decoder'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='355' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_IncrementalEncoder' mangled-name='PyCodec_IncrementalEncoder' filepath='Python/codecs.c' line='360' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_IncrementalEncoder'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='360' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/codecs.c' line='361' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_IncrementalDecoder' mangled-name='PyCodec_IncrementalDecoder' filepath='Python/codecs.c' line='366' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_IncrementalDecoder'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='366' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/codecs.c' line='367' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_StreamReader' mangled-name='PyCodec_StreamReader' filepath='Python/codecs.c' line='372' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_StreamReader'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='372' column='1'/> + <parameter type-id='type-id-2' name='stream' filepath='Python/codecs.c' line='373' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/codecs.c' line='374' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_StreamWriter' mangled-name='PyCodec_StreamWriter' filepath='Python/codecs.c' line='379' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_StreamWriter'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='379' column='1'/> + <parameter type-id='type-id-2' name='stream' filepath='Python/codecs.c' line='380' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/codecs.c' line='381' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCodec_LookupTextEncoding' mangled-name='_PyCodec_LookupTextEncoding' filepath='Python/codecs.c' line='503' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCodec_LookupTextEncoding'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/codecs.c' line='503' column='1'/> + <parameter type-id='type-id-12' name='alternate_command' filepath='Python/codecs.c' line='504' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_RegisterError' mangled-name='PyCodec_RegisterError' filepath='Python/codecs.c' line='602' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_RegisterError'> + <parameter type-id='type-id-12' name='name' filepath='Python/codecs.c' line='602' column='1'/> + <parameter type-id='type-id-2' name='error' filepath='Python/codecs.c' line='602' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCodec_IgnoreErrors' mangled-name='PyCodec_IgnoreErrors' filepath='Python/codecs.c' line='655' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_IgnoreErrors'> + <parameter type-id='type-id-2' name='exc' filepath='Python/codecs.c' line='655' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_ReplaceErrors' mangled-name='PyCodec_ReplaceErrors' filepath='Python/codecs.c' line='679' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_ReplaceErrors'> + <parameter type-id='type-id-2' name='exc' filepath='Python/codecs.c' line='679' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_XMLCharRefReplaceErrors' mangled-name='PyCodec_XMLCharRefReplaceErrors' filepath='Python/codecs.c' line='732' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_XMLCharRefReplaceErrors'> + <parameter type-id='type-id-2' name='exc' filepath='Python/codecs.c' line='732' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_BackslashReplaceErrors' mangled-name='PyCodec_BackslashReplaceErrors' filepath='Python/codecs.c' line='830' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_BackslashReplaceErrors'> + <parameter type-id='type-id-2' name='exc' filepath='Python/codecs.c' line='830' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyCodec_NameReplaceErrors' mangled-name='PyCodec_NameReplaceErrors' filepath='Python/codecs.c' line='939' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCodec_NameReplaceErrors'> + <parameter type-id='type-id-2' name='exc' filepath='Python/codecs.c' line='939' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/compile.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-1350' size-in-bits='1344' id='type-id-1351'> + <subrange length='21' type-id='type-id-28' id='type-id-670'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-1352' size-in-bits='288' id='type-id-1353'> + <subrange length='9' type-id='type-id-28' id='type-id-695'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-326' size-in-bits='2048' id='type-id-1354'> + <subrange length='256' type-id='type-id-28' id='type-id-62'/> + </array-type-def> + <class-decl name='_PyCompilerSrcLocation' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1355' visibility='default' filepath='./Include/cpython/compile.h' line='35' column='1' id='type-id-1356'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='lineno' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='col_offset' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='39' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCompilerSrcLocation' type-id='type-id-1356' filepath='./Include/cpython/compile.h' line='40' column='1' id='type-id-1355'/> + <class-decl name='PyFutureFeatures' size-in-bits='160' is-struct='yes' naming-typedef-id='type-id-1357' visibility='default' filepath='./Include/cpython/compile.h' line='51' column='1' id='type-id-1358'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ff_features' type-id='type-id-8' visibility='default' filepath='./Include/cpython/compile.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='ff_location' type-id='type-id-1355' visibility='default' filepath='./Include/cpython/compile.h' line='53' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyFutureFeatures' type-id='type-id-1358' filepath='./Include/cpython/compile.h' line='54' column='1' id='type-id-1357'/> + <class-decl name='_PyASTOptimizeState' size-in-bits='128' is-struct='yes' naming-typedef-id='type-id-1359' visibility='default' filepath='./Include/internal/pycore_compile.h' line='24' column='1' id='type-id-1360'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='optimize' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='25' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='ff_features' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='26' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='recursion_depth' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='28' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='recursion_limit' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='29' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyASTOptimizeState' type-id='type-id-1360' filepath='./Include/internal/pycore_compile.h' line='30' column='1' id='type-id-1359'/> + <class-decl name='_PyCompile_ExceptHandlerInfo' size-in-bits='96' is-struct='yes' naming-typedef-id='type-id-1361' visibility='default' filepath='./Include/internal/pycore_compile.h' line='37' column='1' id='type-id-1362'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='h_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='h_startdepth' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='h_preserve_lasti' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='40' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCompile_ExceptHandlerInfo' type-id='type-id-1362' filepath='./Include/internal/pycore_compile.h' line='41' column='1' id='type-id-1361'/> + <class-decl name='_PyCompile_Instruction' size-in-bits='288' is-struct='yes' naming-typedef-id='type-id-1363' visibility='default' filepath='./Include/internal/pycore_compile.h' line='43' column='1' id='type-id-1364'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='i_opcode' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='i_oparg' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='i_loc' type-id='type-id-1355' visibility='default' filepath='./Include/internal/pycore_compile.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='i_except_handler_info' type-id='type-id-1361' visibility='default' filepath='./Include/internal/pycore_compile.h' line='47' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCompile_Instruction' type-id='type-id-1364' filepath='./Include/internal/pycore_compile.h' line='48' column='1' id='type-id-1363'/> + <class-decl name='_PyCompile_InstructionSequence' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-1365' visibility='default' filepath='./Include/internal/pycore_compile.h' line='50' column='1' id='type-id-1366'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='s_instrs' type-id='type-id-1367' visibility='default' filepath='./Include/internal/pycore_compile.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='s_allocated' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='s_used' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='s_labelmap' type-id='type-id-179' visibility='default' filepath='./Include/internal/pycore_compile.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='s_labelmap_size' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='s_next_free_label' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='57' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCompile_InstructionSequence' type-id='type-id-1366' filepath='./Include/internal/pycore_compile.h' line='58' column='1' id='type-id-1365'/> + <class-decl name='_PyCompile_CodeUnitMetadata' size-in-bits='768' is-struct='yes' naming-typedef-id='type-id-1368' visibility='default' filepath='./Include/internal/pycore_compile.h' line='60' column='1' id='type-id-1369'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='u_name' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='u_qualname' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='u_consts' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='u_names' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='u_varnames' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='u_cellvars' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='u_freevars' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='u_fasthidden' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_compile.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='u_argcount' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_compile.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='u_posonlyargcount' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_compile.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='u_kwonlyargcount' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_compile.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='u_firstlineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_compile.h' line='81' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCompile_CodeUnitMetadata' type-id='type-id-1369' filepath='./Include/internal/pycore_compile.h' line='82' column='1' id='type-id-1368'/> + <class-decl name='_PyCfgInstruction' size-in-bits='320' is-struct='yes' naming-typedef-id='type-id-1370' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='15' column='1' id='type-id-1371'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='i_opcode' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='i_oparg' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='i_loc' type-id='type-id-1355' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='18' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='i_target' type-id='type-id-1350' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='19' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='i_except' type-id='type-id-1350' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='20' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCfgInstruction' type-id='type-id-1371' filepath='./Include/internal/pycore_flowgraph.h' line='21' column='1' id='type-id-1370'/> + <class-decl name='_PyCfgJumpTargetLabel' size-in-bits='32' is-struct='yes' naming-typedef-id='type-id-1372' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='23' column='1' id='type-id-1373'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='id' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='24' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCfgJumpTargetLabel' type-id='type-id-1373' filepath='./Include/internal/pycore_flowgraph.h' line='25' column='1' id='type-id-1372'/> + <class-decl name='_PyCfgExceptStack' size-in-bits='1408' is-struct='yes' naming-typedef-id='type-id-1374' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='28' column='1' id='type-id-1375'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='handlers' type-id='type-id-1351' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='29' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='1344'> + <var-decl name='depth' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='30' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCfgExceptStack' type-id='type-id-1375' filepath='./Include/internal/pycore_flowgraph.h' line='31' column='1' id='type-id-1374'/> + <class-decl name='_PyCfgBasicblock_' size-in-bits='576' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='33' column='1' id='type-id-1376'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='b_list' type-id='type-id-1350' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='b_label' type-id='type-id-1372' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='40' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='b_exceptstack' type-id='type-id-1377' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='b_instr' type-id='type-id-1378' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='b_next' type-id='type-id-1350' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='b_iused' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='b_ialloc' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='51' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='b_unsafe_locals_mask' type-id='type-id-117' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='53' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='b_predecessors' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='480'> + <var-decl name='b_startdepth' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='b_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='544'> + <var-decl name='b_preserve_lasti' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='545'> + <var-decl name='b_visited' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='546'> + <var-decl name='b_except_handler' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='547'> + <var-decl name='b_cold' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='548'> + <var-decl name='b_warm' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='69' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCfgBasicblock' type-id='type-id-1376' filepath='./Include/internal/pycore_flowgraph.h' line='70' column='1' id='type-id-1379'/> + <class-decl name='cfg_builder_' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='74' column='1' id='type-id-1380'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='g_entryblock' type-id='type-id-1381' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='77' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='g_block_list' type-id='type-id-1381' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='g_curblock' type-id='type-id-1381' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='g_current_label' type-id='type-id-1372' visibility='default' filepath='./Include/internal/pycore_flowgraph.h' line='84' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyCfgBuilder' type-id='type-id-1380' filepath='./Include/internal/pycore_flowgraph.h' line='85' column='1' id='type-id-1382'/> + <enum-decl name='_block_type' filepath='./Include/internal/pycore_symtable.h' line='13' column='1' id='type-id-1383'> + <underlying-type type-id='type-id-24'/> + <enumerator name='FunctionBlock' value='0'/> + <enumerator name='ClassBlock' value='1'/> + <enumerator name='ModuleBlock' value='2'/> + <enumerator name='AnnotationBlock' value='3'/> + <enumerator name='TypeVarBoundBlock' value='4'/> + <enumerator name='TypeAliasBlock' value='5'/> + <enumerator name='TypeParamBlock' value='6'/> + </enum-decl> + <typedef-decl name='_Py_block_ty' type-id='type-id-1383' filepath='./Include/internal/pycore_symtable.h' line='23' column='1' id='type-id-1384'/> + <enum-decl name='_comprehension_type' filepath='./Include/internal/pycore_symtable.h' line='25' column='1' id='type-id-1385'> + <underlying-type type-id='type-id-24'/> + <enumerator name='NoComprehension' value='0'/> + <enumerator name='ListComprehension' value='1'/> + <enumerator name='DictComprehension' value='2'/> + <enumerator name='SetComprehension' value='3'/> + <enumerator name='GeneratorExpression' value='4'/> + </enum-decl> + <typedef-decl name='_Py_comprehension_ty' type-id='type-id-1385' filepath='./Include/internal/pycore_symtable.h' line='30' column='1' id='type-id-1386'/> + <class-decl name='symtable' size-in-bits='640' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='34' column='1' id='type-id-1387'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='st_filename' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='st_cur' type-id='type-id-1388' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='37' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='st_top' type-id='type-id-1388' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='38' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='st_blocks' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='39' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='st_stack' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='41' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='st_global' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='42' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='st_nblocks' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='43' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='st_private' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='46' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='st_future' type-id='type-id-1389' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='recursion_depth' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='49' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='608'> + <var-decl name='recursion_limit' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='50' column='1'/> + </data-member> + </class-decl> + <class-decl name='_symtable_entry' size-in-bits='960' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='53' column='1' id='type-id-1390'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='ob_base' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='54' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='ste_id' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='ste_symbols' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='ste_name' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='ste_varnames' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='58' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='ste_children' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='59' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='ste_directives' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='ste_type' type-id='type-id-1384' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='544'> + <var-decl name='ste_nested' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='ste_free' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='577'> + <var-decl name='ste_child_free' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='578'> + <var-decl name='ste_generator' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='579'> + <var-decl name='ste_coroutine' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='608'> + <var-decl name='ste_comprehension' type-id='type-id-1386' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='ste_varargs' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='641'> + <var-decl name='ste_varkeywords' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='642'> + <var-decl name='ste_returns_value' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='643'> + <var-decl name='ste_needs_class_closure' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='644'> + <var-decl name='ste_needs_classdict' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='645'> + <var-decl name='ste_comp_inlined' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='646'> + <var-decl name='ste_comp_iter_target' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='79' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='647'> + <var-decl name='ste_can_see_class_scope' type-id='type-id-95' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='672'> + <var-decl name='ste_comp_iter_expr' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='ste_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='83' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='736'> + <var-decl name='ste_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='768'> + <var-decl name='ste_end_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='85' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='800'> + <var-decl name='ste_end_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='86' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='ste_opt_lineno' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='864'> + <var-decl name='ste_opt_col_offset' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='896'> + <var-decl name='ste_table' type-id='type-id-209' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='89' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PySTEntryObject' type-id='type-id-1390' filepath='./Include/internal/pycore_symtable.h' line='90' column='1' id='type-id-1391'/> + <typedef-decl name='basicblock' type-id='type-id-1379' filepath='Python/compile.c' line='90' column='1' id='type-id-1392'/> + <pointer-type-def type-id='type-id-1357' size-in-bits='64' id='type-id-1389'/> + <pointer-type-def type-id='type-id-1391' size-in-bits='64' id='type-id-1393'/> + <pointer-type-def type-id='type-id-1359' size-in-bits='64' id='type-id-1394'/> + <pointer-type-def type-id='type-id-1379' size-in-bits='64' id='type-id-1381'/> + <pointer-type-def type-id='type-id-1376' size-in-bits='64' id='type-id-1350'/> + <pointer-type-def type-id='type-id-1382' size-in-bits='64' id='type-id-1395'/> + <pointer-type-def type-id='type-id-1374' size-in-bits='64' id='type-id-1377'/> + <pointer-type-def type-id='type-id-1370' size-in-bits='64' id='type-id-1378'/> + <pointer-type-def type-id='type-id-1368' size-in-bits='64' id='type-id-1396'/> + <pointer-type-def type-id='type-id-1363' size-in-bits='64' id='type-id-1367'/> + <pointer-type-def type-id='type-id-1365' size-in-bits='64' id='type-id-1397'/> + <pointer-type-def type-id='type-id-1390' size-in-bits='64' id='type-id-1388'/> + <pointer-type-def type-id='type-id-1392' size-in-bits='64' id='type-id-1398'/> + <qualified-type-def type-id='type-id-352' const='yes' id='type-id-1352'/> + <pointer-type-def type-id='type-id-1387' size-in-bits='64' id='type-id-209'/> + <function-decl name='PyErr_ProgramTextObject' mangled-name='PyErr_ProgramTextObject' filepath='./Include/cpython/pyerrors.h' line='138' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_ProgramTextObject'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyAST_ExprAsUnicode' filepath='./Include/internal/pycore_ast.h' line='912' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-502'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCode_GetFreevars' filepath='./Include/internal/pycore_code.h' line='208' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyAST_Optimize' filepath='./Include/internal/pycore_compile.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-467'/> + <parameter type-id='type-id-1337'/> + <parameter type-id='type-id-1394'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyBasicblock_InsertInstruction' filepath='./Include/internal/pycore_flowgraph.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1381'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1378'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCfgBuilder_UseLabel' filepath='./Include/internal/pycore_flowgraph.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1395'/> + <parameter type-id='type-id-1372'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCfgBuilder_Addop' filepath='./Include/internal/pycore_flowgraph.h' line='88' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1395'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1355'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCfgBuilder_Init' filepath='./Include/internal/pycore_flowgraph.h' line='90' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1395'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCfgBuilder_Fini' filepath='./Include/internal/pycore_flowgraph.h' line='91' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1395'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyCfg_OptimizeCodeUnit' filepath='./Include/internal/pycore_flowgraph.h' line='94' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1395'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCfg_Stackdepth' filepath='./Include/internal/pycore_flowgraph.h' line='96' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1381'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCfg_ConvertPseudoOps' filepath='./Include/internal/pycore_flowgraph.h' line='97' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1381'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyCfg_ResolveJumps' filepath='./Include/internal/pycore_flowgraph.h' line='98' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1395'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyAssemble_MakeCodeObject' filepath='./Include/internal/pycore_flowgraph.h' line='113' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1396'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1397'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-328'/> + </function-decl> + <var-decl name='_PyOpcode_Jump' type-id='type-id-1353' visibility='default' filepath='./Include/internal/pycore_opcode.h' line='15' column='1'/> + <var-decl name='_PyOpcode_Caches' type-id='type-id-1354' visibility='default' filepath='./Include/internal/pycore_opcode.h' line='17' column='1'/> + <var-decl name='_PyOpcode_Deopt' type-id='type-id-1354' visibility='default' filepath='./Include/internal/pycore_opcode.h' line='19' column='1'/> + <function-decl name='_PyST_GetSymbol' filepath='./Include/internal/pycore_symtable.h' line='96' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1393'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='_PyST_GetScope' filepath='./Include/internal/pycore_symtable.h' line='97' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1393'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyST_IsFunctionLike' filepath='./Include/internal/pycore_symtable.h' line='98' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1393'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySymtable_Build' filepath='./Include/internal/pycore_symtable.h' line='100' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-467'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-1389'/> + <return type-id='type-id-209'/> + </function-decl> + <function-decl name='PySymtable_Lookup' mangled-name='PySymtable_Lookup' filepath='./Include/internal/pycore_symtable.h' line='104' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySymtable_Lookup'> + <parameter type-id='type-id-209'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-1393'/> + </function-decl> + <function-decl name='_PySymtable_Free' filepath='./Include/internal/pycore_symtable.h' line='106' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-209'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFuture_FromAST' filepath='./Include/internal/pycore_symtable.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-467'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-1389'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyCompile_OpcodeStackEffectWithJump' mangled-name='PyCompile_OpcodeStackEffectWithJump' filepath='Python/compile.c' line='876' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCompile_OpcodeStackEffectWithJump'> + <parameter type-id='type-id-8' name='opcode' filepath='Python/compile.c' line='876' column='1'/> + <parameter type-id='type-id-8' name='oparg' filepath='Python/compile.c' line='876' column='1'/> + <parameter type-id='type-id-8' name='jump' filepath='Python/compile.c' line='876' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCompile_CodeGen' mangled-name='_PyCompile_CodeGen' filepath='Python/compile.c' line='7916' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCompile_CodeGen'> + <parameter type-id='type-id-2' name='ast' filepath='Python/compile.c' line='7916' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/compile.c' line='7916' column='1'/> + <parameter type-id='type-id-208' name='pflags' filepath='Python/compile.c' line='7916' column='1'/> + <parameter type-id='type-id-8' name='optimize' filepath='Python/compile.c' line='7917' column='1'/> + <parameter type-id='type-id-8' name='compile_mode' filepath='Python/compile.c' line='7917' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCompile_OptimizeCfg' mangled-name='_PyCompile_OptimizeCfg' filepath='Python/compile.c' line='8001' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCompile_OptimizeCfg'> + <parameter type-id='type-id-2' name='instructions' filepath='Python/compile.c' line='8001' column='1'/> + <parameter type-id='type-id-2' name='consts' filepath='Python/compile.c' line='8001' column='1'/> + <parameter type-id='type-id-8' name='nlocals' filepath='Python/compile.c' line='8001' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCfg_JumpLabelsToTargets' filepath='Python/compile.c' line='8025' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1398'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCompile_Assemble' mangled-name='_PyCompile_Assemble' filepath='Python/compile.c' line='8028' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCompile_Assemble'> + <parameter type-id='type-id-1396' name='umd' filepath='Python/compile.c' line='8028' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/compile.c' line='8028' column='1'/> + <parameter type-id='type-id-2' name='instructions' filepath='Python/compile.c' line='8029' column='1'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='PyCode_Optimize' mangled-name='PyCode_Optimize' filepath='Python/compile.c' line='8095' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyCode_Optimize'> + <parameter type-id='type-id-2' name='code' filepath='Python/compile.c' line='8095' column='1'/> + <parameter type-id='type-id-2' name='_unused_consts' filepath='Python/compile.c' line='8095' column='1'/> + <parameter type-id='type-id-2' name='_unused_names' filepath='Python/compile.c' line='8096' column='1'/> + <parameter type-id='type-id-2' name='_unused_lnotab_obj' filepath='Python/compile.c' line='8096' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyOpcode_num_popped' filepath='Python/opcode_metadata.h' line='7' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-614'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyOpcode_num_pushed' filepath='Python/opcode_metadata.h' line='403' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-614'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/context.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PyContext_Type' type-id='type-id-256' mangled-name='PyContext_Type' visibility='default' filepath='./Include/cpython/context.h' line='8' column='1' elf-symbol-id='PyContext_Type'/> + <var-decl name='PyContextVar_Type' type-id='type-id-256' mangled-name='PyContextVar_Type' visibility='default' filepath='./Include/cpython/context.h' line='11' column='1' elf-symbol-id='PyContextVar_Type'/> + <var-decl name='PyContextToken_Type' type-id='type-id-256' mangled-name='PyContextToken_Type' visibility='default' filepath='./Include/cpython/context.h' line='14' column='1' elf-symbol-id='PyContextToken_Type'/> + <var-decl name='_PyContextTokenMissing_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_context.h' line='11' column='1'/> + <function-decl name='_PyHamt_New' filepath='./Include/internal/pycore_hamt.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-828'/> + </function-decl> + <function-decl name='_PyHamt_Assoc' filepath='./Include/internal/pycore_hamt.h' line='99' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-828'/> + </function-decl> + <function-decl name='_PyHamt_Without' filepath='./Include/internal/pycore_hamt.h' line='102' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-828'/> + </function-decl> + <function-decl name='_PyHamt_Find' filepath='./Include/internal/pycore_hamt.h' line='111' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyHamt_Eq' filepath='./Include/internal/pycore_hamt.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <parameter type-id='type-id-828'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyHamt_Len' filepath='./Include/internal/pycore_hamt.h' line='123' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyHamt_NewIterKeys' filepath='./Include/internal/pycore_hamt.h' line='126' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyHamt_NewIterValues' filepath='./Include/internal/pycore_hamt.h' line='129' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyHamt_NewIterItems' filepath='./Include/internal/pycore_hamt.h' line='132' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-828'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyContext_NewHamtForTests' mangled-name='_PyContext_NewHamtForTests' filepath='Python/context.c' line='78' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyContext_NewHamtForTests'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyContext_New' mangled-name='PyContext_New' filepath='Python/context.c' line='85' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContext_New'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyContext_Copy' mangled-name='PyContext_Copy' filepath='Python/context.c' line='92' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContext_Copy'> + <parameter type-id='type-id-2' name='octx' filepath='Python/context.c' line='92' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyContext_CopyCurrent' mangled-name='PyContext_CopyCurrent' filepath='Python/context.c' line='101' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContext_CopyCurrent'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyContext_Enter' mangled-name='PyContext_Enter' filepath='Python/context.c' line='135' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContext_Enter'> + <parameter type-id='type-id-2' name='octx' filepath='Python/context.c' line='135' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyContext_Exit' mangled-name='PyContext_Exit' filepath='Python/context.c' line='173' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContext_Exit'> + <parameter type-id='type-id-2' name='octx' filepath='Python/context.c' line='173' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyContextVar_New' mangled-name='PyContextVar_New' filepath='Python/context.c' line='182' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContextVar_New'> + <parameter type-id='type-id-12' name='name' filepath='Python/context.c' line='182' column='1'/> + <parameter type-id='type-id-2' name='def' filepath='Python/context.c' line='182' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyContextVar_Get' mangled-name='PyContextVar_Get' filepath='Python/context.c' line='195' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContextVar_Get'> + <parameter type-id='type-id-2' name='ovar' filepath='Python/context.c' line='195' column='1'/> + <parameter type-id='type-id-2' name='def' filepath='Python/context.c' line='195' column='1'/> + <parameter type-id='type-id-233' name='val' filepath='Python/context.c' line='195' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyContextVar_Set' mangled-name='PyContextVar_Set' filepath='Python/context.c' line='258' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContextVar_Set'> + <parameter type-id='type-id-2' name='ovar' filepath='Python/context.c' line='258' column='1'/> + <parameter type-id='type-id-2' name='val' filepath='Python/context.c' line='258' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyContextVar_Reset' mangled-name='PyContextVar_Reset' filepath='Python/context.c' line='294' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyContextVar_Reset'> + <parameter type-id='type-id-2' name='ovar' filepath='Python/context.c' line='294' column='1'/> + <parameter type-id='type-id-2' name='otok' filepath='Python/context.c' line='294' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/deepfreeze/deepfreeze.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyStaticCode_Fini' filepath='./Include/internal/pycore_code.h' line='251' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyStaticCode_Init' filepath='./Include/internal/pycore_code.h' line='253' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-8'/> + </function-decl> + <var-decl name='_Py_next_func_version' type-id='type-id-352' visibility='default' filepath='./Include/internal/pycore_code.h' line='463' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='Python/errors.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_fopen_obj' mangled-name='_Py_fopen_obj' filepath='./Include/cpython/fileutils.h' line='6' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_fopen_obj'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-229'/> + </function-decl> + <function-decl name='_PyTraceBack_FromFrame' mangled-name='_PyTraceBack_FromFrame' filepath='./Include/internal/pycore_traceback.h' line='83' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceBack_FromFrame'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-365'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyTraceBack_Print' mangled-name='PyTraceBack_Print' filepath='./Include/traceback.h' line='10' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTraceBack_Print'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='strerror' filepath='/usr/include/string.h' line='419' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_PyErr_Restore' mangled-name='_PyErr_Restore' filepath='Python/errors.c' line='65' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_Restore'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='65' column='1'/> + <parameter type-id='type-id-2' name='type' filepath='Python/errors.c' line='65' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Python/errors.c' line='65' column='1'/> + <parameter type-id='type-id-2' name='traceback' filepath='Python/errors.c' line='66' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_SetNone' mangled-name='_PyErr_SetNone' filepath='Python/errors.c' line='276' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_SetNone'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='276' column='1'/> + <parameter type-id='type-id-2' name='exception' filepath='Python/errors.c' line='276' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_NormalizeException' mangled-name='_PyErr_NormalizeException' filepath='Python/errors.c' line='376' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_NormalizeException'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='376' column='1'/> + <parameter type-id='type-id-233' name='exc' filepath='Python/errors.c' line='376' column='1'/> + <parameter type-id='type-id-233' name='val' filepath='Python/errors.c' line='377' column='1'/> + <parameter type-id='type-id-233' name='tb' filepath='Python/errors.c' line='377' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_Fetch' mangled-name='_PyErr_Fetch' filepath='Python/errors.c' line='501' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_Fetch'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='501' column='1'/> + <parameter type-id='type-id-233' name='p_type' filepath='Python/errors.c' line='501' column='1'/> + <parameter type-id='type-id-233' name='p_value' filepath='Python/errors.c' line='501' column='1'/> + <parameter type-id='type-id-233' name='p_traceback' filepath='Python/errors.c' line='502' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_GetExcInfo' mangled-name='_PyErr_GetExcInfo' filepath='Python/errors.c' line='568' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_GetExcInfo'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='568' column='1'/> + <parameter type-id='type-id-233' name='p_type' filepath='Python/errors.c' line='569' column='1'/> + <parameter type-id='type-id-233' name='p_value' filepath='Python/errors.c' line='569' column='1'/> + <parameter type-id='type-id-233' name='p_traceback' filepath='Python/errors.c' line='569' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_GetHandledException' mangled-name='_PyErr_GetHandledException' filepath='Python/errors.c' line='579' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_GetHandledException'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='579' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_GetHandledException' mangled-name='PyErr_GetHandledException' filepath='Python/errors.c' line='590' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_GetHandledException'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_SetHandledException' mangled-name='_PyErr_SetHandledException' filepath='Python/errors.c' line='597' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_SetHandledException'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/errors.c' line='597' column='1'/> + <parameter type-id='type-id-2' name='exc' filepath='Python/errors.c' line='597' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_GetExcInfo' mangled-name='PyErr_GetExcInfo' filepath='Python/errors.c' line='610' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_GetExcInfo'> + <parameter type-id='type-id-233' name='p_type' filepath='Python/errors.c' line='610' column='1'/> + <parameter type-id='type-id-233' name='p_value' filepath='Python/errors.c' line='610' column='1'/> + <parameter type-id='type-id-233' name='p_traceback' filepath='Python/errors.c' line='610' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_SetExcInfo' mangled-name='PyErr_SetExcInfo' filepath='Python/errors.c' line='617' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetExcInfo'> + <parameter type-id='type-id-2' name='type' filepath='Python/errors.c' line='617' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Python/errors.c' line='617' column='1'/> + <parameter type-id='type-id-2' name='traceback' filepath='Python/errors.c' line='617' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_StackItemToExcInfoTuple' mangled-name='_PyErr_StackItemToExcInfoTuple' filepath='Python/errors.c' line='628' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_StackItemToExcInfoTuple'> + <parameter type-id='type-id-376' name='err_info' filepath='Python/errors.c' line='628' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyErr_ChainExceptions' mangled-name='_PyErr_ChainExceptions' filepath='Python/errors.c' line='653' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_ChainExceptions'> + <parameter type-id='type-id-2' name='typ' filepath='Python/errors.c' line='653' column='1'/> + <parameter type-id='type-id-2' name='val' filepath='Python/errors.c' line='653' column='1'/> + <parameter type-id='type-id-2' name='tb' filepath='Python/errors.c' line='653' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_SetFromErrnoWithFilenameObject' mangled-name='PyErr_SetFromErrnoWithFilenameObject' filepath='Python/errors.c' line='811' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetFromErrnoWithFilenameObject'> + <parameter type-id='type-id-2' name='exc' filepath='Python/errors.c' line='811' column='1'/> + <parameter type-id='type-id-2' name='filenameObject' filepath='Python/errors.c' line='811' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SetFromErrnoWithFilenameObjects' mangled-name='PyErr_SetFromErrnoWithFilenameObjects' filepath='Python/errors.c' line='817' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetFromErrnoWithFilenameObjects'> + <parameter type-id='type-id-2' name='exc' filepath='Python/errors.c' line='817' column='1'/> + <parameter type-id='type-id-2' name='filenameObject' filepath='Python/errors.c' line='817' column='1'/> + <parameter type-id='type-id-2' name='filenameObject2' filepath='Python/errors.c' line='817' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SetImportErrorSubclass' mangled-name='PyErr_SetImportErrorSubclass' filepath='Python/errors.c' line='1112' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetImportErrorSubclass'> + <parameter type-id='type-id-2' name='exception' filepath='Python/errors.c' line='1112' column='1'/> + <parameter type-id='type-id-2' name='msg' filepath='Python/errors.c' line='1112' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Python/errors.c' line='1113' column='1'/> + <parameter type-id='type-id-2' name='path' filepath='Python/errors.c' line='1113' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SetImportError' mangled-name='PyErr_SetImportError' filepath='Python/errors.c' line='1125' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SetImportError'> + <parameter type-id='type-id-2' name='msg' filepath='Python/errors.c' line='1125' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Python/errors.c' line='1125' column='1'/> + <parameter type-id='type-id-2' name='path' filepath='Python/errors.c' line='1125' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_BadInternalCall' mangled-name='PyErr_BadInternalCall' filepath='Python/errors.c' line='1143' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_BadInternalCall'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_FormatV' mangled-name='PyErr_FormatV' filepath='Python/errors.c' line='1172' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_FormatV'> + <parameter type-id='type-id-2' name='exception' filepath='Python/errors.c' line='1172' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/errors.c' line='1172' column='1'/> + <parameter type-id='type-id-306' name='vargs' filepath='Python/errors.c' line='1172' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_NewExceptionWithDoc' mangled-name='PyErr_NewExceptionWithDoc' filepath='Python/errors.c' line='1286' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_NewExceptionWithDoc'> + <parameter type-id='type-id-12' name='name' filepath='Python/errors.c' line='1286' column='1'/> + <parameter type-id='type-id-12' name='doc' filepath='Python/errors.c' line='1286' column='1'/> + <parameter type-id='type-id-2' name='base' filepath='Python/errors.c' line='1287' column='1'/> + <parameter type-id='type-id-2' name='dict' filepath='Python/errors.c' line='1287' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyErr_SyntaxLocation' mangled-name='PyErr_SyntaxLocation' filepath='Python/errors.c' line='1691' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SyntaxLocation'> + <parameter type-id='type-id-12' name='filename' filepath='Python/errors.c' line='1691' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/errors.c' line='1691' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_SyntaxLocationObject' mangled-name='PyErr_SyntaxLocationObject' filepath='Python/errors.c' line='1810' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SyntaxLocationObject'> + <parameter type-id='type-id-2' name='filename' filepath='Python/errors.c' line='1810' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/errors.c' line='1810' column='1'/> + <parameter type-id='type-id-8' name='col_offset' filepath='Python/errors.c' line='1810' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_RangedSyntaxLocationObject' mangled-name='PyErr_RangedSyntaxLocationObject' filepath='Python/errors.c' line='1815' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_RangedSyntaxLocationObject'> + <parameter type-id='type-id-2' name='filename' filepath='Python/errors.c' line='1815' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/errors.c' line='1815' column='1'/> + <parameter type-id='type-id-8' name='col_offset' filepath='Python/errors.c' line='1815' column='1'/> + <parameter type-id='type-id-8' name='end_lineno' filepath='Python/errors.c' line='1816' column='1'/> + <parameter type-id='type-id-8' name='end_col_offset' filepath='Python/errors.c' line='1816' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_SyntaxLocationEx' mangled-name='PyErr_SyntaxLocationEx' filepath='Python/errors.c' line='1821' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_SyntaxLocationEx'> + <parameter type-id='type-id-12' name='filename' filepath='Python/errors.c' line='1821' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/errors.c' line='1821' column='1'/> + <parameter type-id='type-id-8' name='col_offset' filepath='Python/errors.c' line='1821' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_ProgramText' mangled-name='PyErr_ProgramText' filepath='Python/errors.c' line='1886' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_ProgramText'> + <parameter type-id='type-id-12' name='filename' filepath='Python/errors.c' line='1886' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/errors.c' line='1886' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/fileutils.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='__mbstate_t' size-in-bits='64' is-struct='yes' naming-typedef-id='type-id-1399' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='13' column='1' id='type-id-1400'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='__count' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='__value' type-id='type-id-1401' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='20' column='1'/> + </data-member> + </class-decl> + <union-decl name='__anonymous_union__' size-in-bits='32' is-anonymous='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='16' column='1' id='type-id-1401'> + <data-member access='public'> + <var-decl name='__wch' type-id='type-id-95' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='18' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__wchb' type-id='type-id-619' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='19' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='__mbstate_t' type-id='type-id-1400' filepath='/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h' line='21' column='1' id='type-id-1399'/> + <typedef-decl name='mbstate_t' type-id='type-id-1399' filepath='/usr/include/x86_64-linux-gnu/bits/types/mbstate_t.h' line='6' column='1' id='type-id-1402'/> + <pointer-type-def type-id='type-id-1402' size-in-bits='64' id='type-id-1403'/> + <qualified-type-def type-id='type-id-1403' restrict='yes' id='type-id-1404'/> + <qualified-type-def type-id='type-id-51' restrict='yes' id='type-id-1405'/> + <function-decl name='realpath' filepath='/usr/include/stdlib.h' line='808' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-183'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='mbstowcs' filepath='/usr/include/stdlib.h' line='941' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='wcstombs' filepath='/usr/include/stdlib.h' line='945' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-18'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='write' filepath='/usr/include/unistd.h' line='378' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='getcwd' filepath='/usr/include/unistd.h' line='531' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='readlink' filepath='/usr/include/unistd.h' line='838' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-185'/> + </function-decl> + <function-decl name='close_range' filepath='/usr/include/unistd.h' line='1208' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-95'/> + <parameter type-id='type-id-95'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='mbrtowc' filepath='/usr/include/wchar.h' line='297' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-1404'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='ioctl' filepath='/usr/include/x86_64-linux-gnu/sys/ioctl.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-28'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_device_encoding' mangled-name='_Py_device_encoding' filepath='Python/fileutils.c' line='75' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_device_encoding'> + <parameter type-id='type-id-8' name='fd' filepath='Python/fileutils.c' line='75' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_EncodeLocale' mangled-name='Py_EncodeLocale' filepath='Python/fileutils.c' line='863' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_EncodeLocale'> + <parameter type-id='type-id-16' name='text' filepath='Python/fileutils.c' line='863' column='1'/> + <parameter type-id='type-id-441' name='error_pos' filepath='Python/fileutils.c' line='863' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_Py_EncodeLocaleRaw' mangled-name='_Py_EncodeLocaleRaw' filepath='Python/fileutils.c' line='872' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_EncodeLocaleRaw'> + <parameter type-id='type-id-16' name='text' filepath='Python/fileutils.c' line='872' column='1'/> + <parameter type-id='type-id-441' name='error_pos' filepath='Python/fileutils.c' line='872' column='1'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_Py_GetLocaleEncodingObject' mangled-name='_Py_GetLocaleEncodingObject' filepath='Python/fileutils.c' line='936' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetLocaleEncodingObject'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_stat' mangled-name='_Py_stat' filepath='Python/fileutils.c' line='1354' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_stat'> + <parameter type-id='type-id-2' name='path' filepath='Python/fileutils.c' line='1354' column='1'/> + <parameter type-id='type-id-51' name='statbuf' filepath='Python/fileutils.c' line='1354' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_get_inheritable' mangled-name='_Py_get_inheritable' filepath='Python/fileutils.c' line='1434' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_get_inheritable'> + <parameter type-id='type-id-8' name='fd' filepath='Python/fileutils.c' line='1434' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_set_inheritable' mangled-name='_Py_set_inheritable' filepath='Python/fileutils.c' line='1594' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_set_inheritable'> + <parameter type-id='type-id-8' name='fd' filepath='Python/fileutils.c' line='1594' column='1'/> + <parameter type-id='type-id-8' name='inheritable' filepath='Python/fileutils.c' line='1594' column='1'/> + <parameter type-id='type-id-179' name='atomic_flag_works' filepath='Python/fileutils.c' line='1594' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_set_inheritable_async_safe' mangled-name='_Py_set_inheritable_async_safe' filepath='Python/fileutils.c' line='1603' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_set_inheritable_async_safe'> + <parameter type-id='type-id-8' name='fd' filepath='Python/fileutils.c' line='1603' column='1'/> + <parameter type-id='type-id-8' name='inheritable' filepath='Python/fileutils.c' line='1603' column='1'/> + <parameter type-id='type-id-179' name='atomic_flag_works' filepath='Python/fileutils.c' line='1603' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_wfopen' mangled-name='_Py_wfopen' filepath='Python/fileutils.c' line='1706' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_wfopen'> + <parameter type-id='type-id-16' name='path' filepath='Python/fileutils.c' line='1706' column='1'/> + <parameter type-id='type-id-16' name='mode' filepath='Python/fileutils.c' line='1706' column='1'/> + <return type-id='type-id-229'/> + </function-decl> + <function-decl name='_Py_normpath' mangled-name='_Py_normpath' filepath='Python/fileutils.c' line='2381' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_normpath'> + <parameter type-id='type-id-52' name='path' filepath='Python/fileutils.c' line='2381' column='1'/> + <parameter type-id='type-id-14' name='size' filepath='Python/fileutils.c' line='2381' column='1'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_Py_get_blocking' mangled-name='_Py_get_blocking' filepath='Python/fileutils.c' line='2613' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_get_blocking'> + <parameter type-id='type-id-8' name='fd' filepath='Python/fileutils.c' line='2613' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_set_blocking' mangled-name='_Py_set_blocking' filepath='Python/fileutils.c' line='2634' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_set_blocking'> + <parameter type-id='type-id-8' name='fd' filepath='Python/fileutils.c' line='2634' column='1'/> + <parameter type-id='type-id-8' name='blocking' filepath='Python/fileutils.c' line='2634' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_closerange' mangled-name='_Py_closerange' filepath='Python/fileutils.c' line='2885' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_closerange'> + <parameter type-id='type-id-8' name='first' filepath='Python/fileutils.c' line='2885' column='1'/> + <parameter type-id='type-id-8' name='last' filepath='Python/fileutils.c' line='2885' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/flowgraph.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyCompile_EnsureArrayLargeEnough' filepath='./Include/internal/pycore_compile.h' line='86' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-253'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/formatter_unicode.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='lconv' size-in-bits='768' is-struct='yes' visibility='default' filepath='/usr/include/locale.h' line='51' column='1' id='type-id-1406'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='decimal_point' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='55' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='thousands_sep' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='56' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='grouping' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='62' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='int_curr_symbol' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='68' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='currency_symbol' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='69' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='mon_decimal_point' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='mon_thousands_sep' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='71' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='mon_grouping' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='72' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='positive_sign' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='73' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='negative_sign' type-id='type-id-15' visibility='default' filepath='/usr/include/locale.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='640'> + <var-decl name='int_frac_digits' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='648'> + <var-decl name='frac_digits' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='656'> + <var-decl name='p_cs_precedes' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='78' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='664'> + <var-decl name='p_sep_by_space' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='80' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='672'> + <var-decl name='n_cs_precedes' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='82' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='680'> + <var-decl name='n_sep_by_space' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='84' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='688'> + <var-decl name='p_sign_posn' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='91' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='696'> + <var-decl name='n_sign_posn' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='92' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='int_p_cs_precedes' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='95' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='712'> + <var-decl name='int_p_sep_by_space' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='97' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='720'> + <var-decl name='int_n_cs_precedes' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='728'> + <var-decl name='int_n_sep_by_space' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='736'> + <var-decl name='int_p_sign_posn' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='108' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='744'> + <var-decl name='int_n_sign_posn' type-id='type-id-48' visibility='default' filepath='/usr/include/locale.h' line='109' column='1'/> + </data-member> + </class-decl> + <pointer-type-def type-id='type-id-1406' size-in-bits='64' id='type-id-1407'/> + <function-decl name='_Py_GetLocaleconvNumeric' mangled-name='_Py_GetLocaleconvNumeric' filepath='./Include/internal/pycore_fileutils.h' line='222' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetLocaleconvNumeric'> + <parameter type-id='type-id-1407'/> + <parameter type-id='type-id-233'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='localeconv' filepath='/usr/include/locale.h' line='125' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-1407'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/frame.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyFrame_New_NoTrack' filepath='./Include/internal/pycore_frame.h' line='29' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-365'/> + </function-decl> + <function-decl name='PyUnstable_InterpreterFrame_GetCode' mangled-name='PyUnstable_InterpreterFrame_GetCode' filepath='Python/frame.c' line='150' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_InterpreterFrame_GetCode'> + <parameter type-id='type-id-375' name='frame' filepath='Python/frame.c' line='150' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyUnstable_InterpreterFrame_GetLasti' mangled-name='PyUnstable_InterpreterFrame_GetLasti' filepath='Python/frame.c' line='158' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_InterpreterFrame_GetLasti'> + <parameter type-id='type-id-375' name='frame' filepath='Python/frame.c' line='158' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/frozen.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='_frozen' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/cpython/import.h' line='32' column='1' id='type-id-1408'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/cpython/import.h' line='33' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='code' type-id='type-id-383' visibility='default' filepath='./Include/cpython/import.h' line='34' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='size' type-id='type-id-8' visibility='default' filepath='./Include/cpython/import.h' line='35' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='is_package' type-id='type-id-8' visibility='default' filepath='./Include/cpython/import.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='get_code' type-id='type-id-390' visibility='default' filepath='./Include/cpython/import.h' line='37' column='1'/> + </data-member> + </class-decl> + <class-decl name='_module_alias' size-in-bits='128' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_import.h' line='163' column='1' id='type-id-1409'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/internal/pycore_import.h' line='164' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='orig' type-id='type-id-12' visibility='default' filepath='./Include/internal/pycore_import.h' line='165' column='1'/> + </data-member> + </class-decl> + <qualified-type-def type-id='type-id-1408' const='yes' id='type-id-1410'/> + <pointer-type-def type-id='type-id-1410' size-in-bits='64' id='type-id-1411'/> + <qualified-type-def type-id='type-id-1409' const='yes' id='type-id-1412'/> + <pointer-type-def type-id='type-id-1412' size-in-bits='64' id='type-id-1413'/> + <var-decl name='PyImport_FrozenModules' type-id='type-id-1411' mangled-name='PyImport_FrozenModules' visibility='default' filepath='./Include/cpython/import.h' line='43' column='1' elf-symbol-id='PyImport_FrozenModules'/> + <var-decl name='_PyImport_FrozenBootstrap' type-id='type-id-1411' mangled-name='_PyImport_FrozenBootstrap' visibility='default' filepath='./Include/internal/pycore_import.h' line='168' column='1' elf-symbol-id='_PyImport_FrozenBootstrap'/> + <var-decl name='_PyImport_FrozenStdlib' type-id='type-id-1411' mangled-name='_PyImport_FrozenStdlib' visibility='default' filepath='./Include/internal/pycore_import.h' line='169' column='1' elf-symbol-id='_PyImport_FrozenStdlib'/> + <var-decl name='_PyImport_FrozenTest' type-id='type-id-1411' mangled-name='_PyImport_FrozenTest' visibility='default' filepath='./Include/internal/pycore_import.h' line='170' column='1' elf-symbol-id='_PyImport_FrozenTest'/> + <var-decl name='_PyImport_FrozenAliases' type-id='type-id-1413' visibility='default' filepath='./Include/internal/pycore_import.h' line='171' column='1'/> + <function-decl name='_Py_get_importlib__bootstrap_toplevel' filepath='Python/frozen.c' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_importlib__bootstrap_external_toplevel' filepath='Python/frozen.c' line='73' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_zipimport_toplevel' filepath='Python/frozen.c' line='74' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_abc_toplevel' filepath='Python/frozen.c' line='75' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_codecs_toplevel' filepath='Python/frozen.c' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_io_toplevel' filepath='Python/frozen.c' line='77' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get__collections_abc_toplevel' filepath='Python/frozen.c' line='78' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get__sitebuiltins_toplevel' filepath='Python/frozen.c' line='79' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_genericpath_toplevel' filepath='Python/frozen.c' line='80' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_ntpath_toplevel' filepath='Python/frozen.c' line='81' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_posixpath_toplevel' filepath='Python/frozen.c' line='83' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_os_toplevel' filepath='Python/frozen.c' line='84' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_site_toplevel' filepath='Python/frozen.c' line='85' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_stat_toplevel' filepath='Python/frozen.c' line='86' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_importlib_util_toplevel' filepath='Python/frozen.c' line='87' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_importlib_machinery_toplevel' filepath='Python/frozen.c' line='88' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_runpy_toplevel' filepath='Python/frozen.c' line='89' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get___hello___toplevel' filepath='Python/frozen.c' line='93' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get___phello___toplevel' filepath='Python/frozen.c' line='95' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get___phello___ham_toplevel' filepath='Python/frozen.c' line='97' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get___phello___ham_eggs_toplevel' filepath='Python/frozen.c' line='98' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get___phello___spam_toplevel' filepath='Python/frozen.c' line='99' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_get_frozen_only_toplevel' filepath='Python/frozen.c' line='100' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/frozenmain.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyStatus' size-in-bits='256' is-struct='yes' naming-typedef-id='type-id-54' visibility='default' filepath='./Include/cpython/initconfig.h' line='10' column='1' id='type-id-1414'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='_type' type-id='type-id-993' visibility='default' filepath='./Include/cpython/initconfig.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='func' type-id='type-id-12' visibility='default' filepath='./Include/cpython/initconfig.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='err_msg' type-id='type-id-12' visibility='default' filepath='./Include/cpython/initconfig.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='exitcode' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='18' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyStatus' type-id='type-id-1414' filepath='./Include/cpython/initconfig.h' line='19' column='1' id='type-id-54'/> + <pointer-type-def type-id='type-id-258' size-in-bits='64' id='type-id-53'/> + <function-decl name='PyStatus_Exception' mangled-name='PyStatus_Exception' filepath='./Include/cpython/initconfig.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_Exception'> + <parameter type-id='type-id-54'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyConfig_InitPythonConfig' mangled-name='PyConfig_InitPythonConfig' filepath='./Include/cpython/initconfig.h' line='221' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_InitPythonConfig'> + <parameter type-id='type-id-53'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyConfig_Clear' mangled-name='PyConfig_Clear' filepath='./Include/cpython/initconfig.h' line='223' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_Clear'> + <parameter type-id='type-id-53'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyConfig_SetBytesArgv' mangled-name='PyConfig_SetBytesArgv' filepath='./Include/cpython/initconfig.h' line='233' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_SetBytesArgv'> + <parameter type-id='type-id-53'/> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-136'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_InitializeFromConfig' mangled-name='Py_InitializeFromConfig' filepath='./Include/cpython/pylifecycle.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_InitializeFromConfig'> + <parameter type-id='type-id-260'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_ExitStatusException' mangled-name='Py_ExitStatusException' filepath='./Include/cpython/pylifecycle.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_ExitStatusException'> + <parameter type-id='type-id-54'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyRun_AnyFileExFlags' mangled-name='PyRun_AnyFileExFlags' filepath='./Include/cpython/pythonrun.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_AnyFileExFlags'> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-208'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_ImportFrozenModule' mangled-name='PyImport_ImportFrozenModule' filepath='./Include/import.h' line='80' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ImportFrozenModule'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyRuntime_Initialize' mangled-name='_PyRuntime_Initialize' filepath='./Include/internal/pycore_runtime.h' line='188' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRuntime_Initialize'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_FinalizeEx' mangled-name='Py_FinalizeEx' filepath='./Include/pylifecycle.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_FinalizeEx'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_GetVersion' mangled-name='Py_GetVersion' filepath='./Include/pylifecycle.h' line='54' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetVersion'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='Py_GetCopyright' mangled-name='Py_GetCopyright' filepath='./Include/pylifecycle.h' line='56' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetCopyright'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='Py_FrozenMain' mangled-name='Py_FrozenMain' filepath='Python/frozenmain.c' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_FrozenMain'> + <parameter type-id='type-id-8' name='argc' filepath='Python/frozenmain.c' line='16' column='1'/> + <parameter type-id='type-id-239' name='argv' filepath='Python/frozenmain.c' line='16' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/getargs.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyArg_Parse' mangled-name='PyArg_Parse' filepath='Python/getargs.c' line='99' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_Parse'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='99' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='99' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_Parse_SizeT' mangled-name='_PyArg_Parse_SizeT' filepath='Python/getargs.c' line='111' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_Parse_SizeT'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='111' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='111' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_ParseStack' mangled-name='_PyArg_ParseStack' filepath='Python/getargs.c' line='149' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseStack'> + <parameter type-id='type-id-248' name='args' filepath='Python/getargs.c' line='149' column='1'/> + <parameter type-id='type-id-14' name='nargs' filepath='Python/getargs.c' line='149' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='149' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_ParseStack_SizeT' mangled-name='_PyArg_ParseStack_SizeT' filepath='Python/getargs.c' line='161' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseStack_SizeT'> + <parameter type-id='type-id-248' name='args' filepath='Python/getargs.c' line='161' column='1'/> + <parameter type-id='type-id-14' name='nargs' filepath='Python/getargs.c' line='161' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='161' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyArg_VaParse' mangled-name='PyArg_VaParse' filepath='Python/getargs.c' line='174' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_VaParse'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='174' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='174' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/getargs.c' line='174' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_VaParse_SizeT' mangled-name='_PyArg_VaParse_SizeT' filepath='Python/getargs.c' line='187' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_VaParse_SizeT'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='187' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='187' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/getargs.c' line='187' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyArg_VaParseTupleAndKeywords' mangled-name='PyArg_VaParseTupleAndKeywords' filepath='Python/getargs.c' line='1373' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyArg_VaParseTupleAndKeywords'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='1373' column='1'/> + <parameter type-id='type-id-2' name='keywords' filepath='Python/getargs.c' line='1374' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='1375' column='1'/> + <parameter type-id='type-id-239' name='kwlist' filepath='Python/getargs.c' line='1376' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/getargs.c' line='1376' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_VaParseTupleAndKeywords_SizeT' mangled-name='_PyArg_VaParseTupleAndKeywords_SizeT' filepath='Python/getargs.c' line='1398' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_VaParseTupleAndKeywords_SizeT'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='1398' column='1'/> + <parameter type-id='type-id-2' name='keywords' filepath='Python/getargs.c' line='1399' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/getargs.c' line='1400' column='1'/> + <parameter type-id='type-id-239' name='kwlist' filepath='Python/getargs.c' line='1401' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/getargs.c' line='1401' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_ParseTupleAndKeywordsFast' mangled-name='_PyArg_ParseTupleAndKeywordsFast' filepath='Python/getargs.c' line='1424' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseTupleAndKeywordsFast'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='1424' column='1'/> + <parameter type-id='type-id-2' name='keywords' filepath='Python/getargs.c' line='1424' column='1'/> + <parameter type-id='type-id-262' name='parser' filepath='Python/getargs.c' line='1425' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_ParseTupleAndKeywordsFast_SizeT' mangled-name='_PyArg_ParseTupleAndKeywordsFast_SizeT' filepath='Python/getargs.c' line='1437' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseTupleAndKeywordsFast_SizeT'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='1437' column='1'/> + <parameter type-id='type-id-2' name='keywords' filepath='Python/getargs.c' line='1437' column='1'/> + <parameter type-id='type-id-262' name='parser' filepath='Python/getargs.c' line='1438' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_ParseStackAndKeywords' mangled-name='_PyArg_ParseStackAndKeywords' filepath='Python/getargs.c' line='1450' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseStackAndKeywords'> + <parameter type-id='type-id-248' name='args' filepath='Python/getargs.c' line='1450' column='1'/> + <parameter type-id='type-id-14' name='nargs' filepath='Python/getargs.c' line='1450' column='1'/> + <parameter type-id='type-id-2' name='kwnames' filepath='Python/getargs.c' line='1450' column='1'/> + <parameter type-id='type-id-262' name='parser' filepath='Python/getargs.c' line='1451' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_ParseStackAndKeywords_SizeT' mangled-name='_PyArg_ParseStackAndKeywords_SizeT' filepath='Python/getargs.c' line='1463' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_ParseStackAndKeywords_SizeT'> + <parameter type-id='type-id-248' name='args' filepath='Python/getargs.c' line='1463' column='1'/> + <parameter type-id='type-id-14' name='nargs' filepath='Python/getargs.c' line='1463' column='1'/> + <parameter type-id='type-id-2' name='kwnames' filepath='Python/getargs.c' line='1463' column='1'/> + <parameter type-id='type-id-262' name='parser' filepath='Python/getargs.c' line='1464' column='1'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_VaParseTupleAndKeywordsFast' mangled-name='_PyArg_VaParseTupleAndKeywordsFast' filepath='Python/getargs.c' line='1477' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_VaParseTupleAndKeywordsFast'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='1477' column='1'/> + <parameter type-id='type-id-2' name='keywords' filepath='Python/getargs.c' line='1477' column='1'/> + <parameter type-id='type-id-262' name='parser' filepath='Python/getargs.c' line='1478' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/getargs.c' line='1478' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_VaParseTupleAndKeywordsFast_SizeT' mangled-name='_PyArg_VaParseTupleAndKeywordsFast_SizeT' filepath='Python/getargs.c' line='1491' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_VaParseTupleAndKeywordsFast_SizeT'> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='1491' column='1'/> + <parameter type-id='type-id-2' name='keywords' filepath='Python/getargs.c' line='1491' column='1'/> + <parameter type-id='type-id-262' name='parser' filepath='Python/getargs.c' line='1492' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/getargs.c' line='1492' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArg_NoPositional' mangled-name='_PyArg_NoPositional' filepath='Python/getargs.c' line='2912' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArg_NoPositional'> + <parameter type-id='type-id-12' name='funcname' filepath='Python/getargs.c' line='2912' column='1'/> + <parameter type-id='type-id-2' name='args' filepath='Python/getargs.c' line='2912' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/getcompiler.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='Py_GetCompiler' mangled-name='Py_GetCompiler' filepath='Python/getcompiler.c' line='24' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetCompiler'> + <return type-id='type-id-12'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/getopt.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyOS_opterr' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_getopt.h' line='8' column='1'/> + <var-decl name='_PyOS_optind' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_getopt.h' line='9' column='1'/> + <var-decl name='_PyOS_optarg' type-id='type-id-16' visibility='default' filepath='./Include/internal/pycore_getopt.h' line='10' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='Python/getversion.c' comp-dir-path='/src' language='LANG_C11'> + <qualified-type-def type-id='type-id-28' const='yes' id='type-id-1415'/> + <var-decl name='Py_Version' type-id='type-id-1415' mangled-name='Py_Version' visibility='default' filepath='./Include/pylifecycle.h' line='66' column='1' elf-symbol-id='Py_Version'/> + </abi-instr> + <abi-instr address-size='64' path='Python/hamt.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyHamt_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='23' column='1'/> + <var-decl name='_PyHamt_ArrayNode_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='24' column='1'/> + <var-decl name='_PyHamt_BitmapNode_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='25' column='1'/> + <var-decl name='_PyHamt_CollisionNode_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='26' column='1'/> + <var-decl name='_PyHamtKeys_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='27' column='1'/> + <var-decl name='_PyHamtValues_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='28' column='1'/> + <var-decl name='_PyHamtItems_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_hamt.h' line='29' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='Python/hashtable.c' comp-dir-path='/src' language='LANG_C11'> + <typedef-decl name='_Py_hashtable_foreach_func' type-id='type-id-1416' filepath='./Include/internal/pycore_hashtable.h' line='96' column='1' id='type-id-1417'/> + <pointer-type-def type-id='type-id-917' size-in-bits='64' id='type-id-1418'/> + <qualified-type-def type-id='type-id-910' const='yes' id='type-id-1419'/> + <pointer-type-def type-id='type-id-1419' size-in-bits='64' id='type-id-1420'/> + <pointer-type-def type-id='type-id-1421' size-in-bits='64' id='type-id-1416'/> + <function-decl name='_Py_HashPointerRaw' mangled-name='_Py_HashPointerRaw' filepath='./Include/pyhash.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_HashPointerRaw'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-305'/> + </function-decl> + <function-decl name='_Py_hashtable_hash_ptr' mangled-name='_Py_hashtable_hash_ptr' filepath='Python/hashtable.c' line='92' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_hash_ptr'> + <parameter type-id='type-id-22' name='key' filepath='Python/hashtable.c' line='92' column='1'/> + <return type-id='type-id-908'/> + </function-decl> + <function-decl name='_Py_hashtable_compare_direct' mangled-name='_Py_hashtable_compare_direct' filepath='Python/hashtable.c' line='99' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_compare_direct'> + <parameter type-id='type-id-22' name='key1' filepath='Python/hashtable.c' line='99' column='1'/> + <parameter type-id='type-id-22' name='key2' filepath='Python/hashtable.c' line='99' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_hashtable_size' mangled-name='_Py_hashtable_size' filepath='Python/hashtable.c' line='120' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_size'> + <parameter type-id='type-id-1420' name='ht' filepath='Python/hashtable.c' line='120' column='1'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='_Py_hashtable_steal' mangled-name='_Py_hashtable_steal' filepath='Python/hashtable.c' line='174' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_steal'> + <parameter type-id='type-id-996' name='ht' filepath='Python/hashtable.c' line='174' column='1'/> + <parameter type-id='type-id-22' name='key' filepath='Python/hashtable.c' line='174' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_Py_hashtable_set' mangled-name='_Py_hashtable_set' filepath='Python/hashtable.c' line='209' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_set'> + <parameter type-id='type-id-996' name='ht' filepath='Python/hashtable.c' line='209' column='1'/> + <parameter type-id='type-id-22' name='key' filepath='Python/hashtable.c' line='209' column='1'/> + <parameter type-id='type-id-22' name='value' filepath='Python/hashtable.c' line='209' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_hashtable_get' mangled-name='_Py_hashtable_get' filepath='Python/hashtable.c' line='248' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_get'> + <parameter type-id='type-id-996' name='ht' filepath='Python/hashtable.c' line='248' column='1'/> + <parameter type-id='type-id-22' name='key' filepath='Python/hashtable.c' line='248' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_Py_hashtable_foreach' mangled-name='_Py_hashtable_foreach' filepath='Python/hashtable.c' line='261' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_foreach'> + <parameter type-id='type-id-996' name='ht' filepath='Python/hashtable.c' line='261' column='1'/> + <parameter type-id='type-id-1417' name='func' filepath='Python/hashtable.c' line='262' column='1'/> + <parameter type-id='type-id-22' name='user_data' filepath='Python/hashtable.c' line='263' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_hashtable_new_full' mangled-name='_Py_hashtable_new_full' filepath='Python/hashtable.c' line='316' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_new_full'> + <parameter type-id='type-id-912' name='hash_func' filepath='Python/hashtable.c' line='316' column='1'/> + <parameter type-id='type-id-913' name='compare_func' filepath='Python/hashtable.c' line='317' column='1'/> + <parameter type-id='type-id-914' name='key_destroy_func' filepath='Python/hashtable.c' line='318' column='1'/> + <parameter type-id='type-id-914' name='value_destroy_func' filepath='Python/hashtable.c' line='319' column='1'/> + <parameter type-id='type-id-1418' name='allocator' filepath='Python/hashtable.c' line='320' column='1'/> + <return type-id='type-id-996'/> + </function-decl> + <function-decl name='_Py_hashtable_new' mangled-name='_Py_hashtable_new' filepath='Python/hashtable.c' line='363' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_new'> + <parameter type-id='type-id-912' name='hash_func' filepath='Python/hashtable.c' line='363' column='1'/> + <parameter type-id='type-id-913' name='compare_func' filepath='Python/hashtable.c' line='364' column='1'/> + <return type-id='type-id-996'/> + </function-decl> + <function-decl name='_Py_hashtable_clear' mangled-name='_Py_hashtable_clear' filepath='Python/hashtable.c' line='385' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_clear'> + <parameter type-id='type-id-996' name='ht' filepath='Python/hashtable.c' line='385' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_hashtable_destroy' mangled-name='_Py_hashtable_destroy' filepath='Python/hashtable.c' line='404' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_hashtable_destroy'> + <parameter type-id='type-id-996' name='ht' filepath='Python/hashtable.c' line='404' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1421'> + <parameter type-id='type-id-996'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Python/import.c' comp-dir-path='/src' language='LANG_C11'> + <enum-decl name='_PyTime_round_t' naming-typedef-id='type-id-1422' filepath='./Include/cpython/pytime.h' line='70' column='1' id='type-id-1423'> + <underlying-type type-id='type-id-24'/> + <enumerator name='_PyTime_ROUND_FLOOR' value='0'/> + <enumerator name='_PyTime_ROUND_CEILING' value='1'/> + <enumerator name='_PyTime_ROUND_HALF_EVEN' value='2'/> + <enumerator name='_PyTime_ROUND_UP' value='3'/> + <enumerator name='_PyTime_ROUND_TIMEOUT' value='3'/> + </enum-decl> + <typedef-decl name='_PyTime_round_t' type-id='type-id-1423' filepath='./Include/cpython/pytime.h' line='90' column='1' id='type-id-1422'/> + <typedef-decl name='_PyRuntimeState' type-id='type-id-979' filepath='./Include/internal/pycore_runtime.h' line='172' column='1' id='type-id-1424'/> + <pointer-type-def type-id='type-id-1424' size-in-bits='64' id='type-id-178'/> + <var-decl name='PyImport_Inittab' type-id='type-id-922' mangled-name='PyImport_Inittab' visibility='default' filepath='./Include/cpython/import.h' line='29' column='1' elf-symbol-id='PyImport_Inittab'/> + <function-decl name='PyStatus_NoMemory' mangled-name='PyStatus_NoMemory' filepath='./Include/cpython/initconfig.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_NoMemory'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyInterpreterState_HasFeature' mangled-name='_PyInterpreterState_HasFeature' filepath='./Include/cpython/pystate.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_HasFeature'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-28'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_AsMicroseconds' mangled-name='_PyTime_AsMicroseconds' filepath='./Include/cpython/pytime.h' line='165' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsMicroseconds'> + <parameter type-id='type-id-788'/> + <parameter type-id='type-id-1422'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_GetPerfCounter' mangled-name='_PyTime_GetPerfCounter' filepath='./Include/cpython/pytime.h' line='305' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_GetPerfCounter'> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_Py_KeyedHash' filepath='./Include/internal/pycore_pyhash.h' line='37' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-117'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-117'/> + </function-decl> + <function-decl name='_PyThreadState_InitDetached' filepath='./Include/internal/pycore_pystate.h' line='139' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_ClearDetached' filepath='./Include/internal/pycore_pystate.h' line='140' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_BindDetached' filepath='./Include/internal/pycore_pystate.h' line='141' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_UnbindDetached' filepath='./Include/internal/pycore_pystate.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_Swap' mangled-name='_PyThreadState_Swap' filepath='./Include/internal/pycore_pystate.h' line='147' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Swap'> + <parameter type-id='type-id-178'/> + <parameter type-id='type-id-177'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='_PySys_ClearAttrString' filepath='./Include/internal/pycore_sysmodule.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyMarshal_ReadObjectFromString' mangled-name='PyMarshal_ReadObjectFromString' filepath='./Include/marshal.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_ReadObjectFromString'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_AcquireLock' mangled-name='_PyImport_AcquireLock' filepath='Python/import.c' line='103' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_AcquireLock'> + <parameter type-id='type-id-20' name='interp' filepath='Python/import.c' line='103' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_ReleaseLock' mangled-name='_PyImport_ReleaseLock' filepath='Python/import.c' line='130' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_ReleaseLock'> + <parameter type-id='type-id-20' name='interp' filepath='Python/import.c' line='130' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_GetModuleDict' mangled-name='PyImport_GetModuleDict' filepath='Python/import.c' line='203' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_GetModuleDict'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_GetModuleId' mangled-name='_PyImport_GetModuleId' filepath='Python/import.c' line='214' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_GetModuleId'> + <parameter type-id='type-id-309' name='nameid' filepath='Python/import.c' line='214' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_SetModule' mangled-name='_PyImport_SetModule' filepath='Python/import.c' line='224' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_SetModule'> + <parameter type-id='type-id-2' name='name' filepath='Python/import.c' line='224' column='1'/> + <parameter type-id='type-id-2' name='m' filepath='Python/import.c' line='224' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_SetModuleString' mangled-name='_PyImport_SetModuleString' filepath='Python/import.c' line='232' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_SetModuleString'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='232' column='1'/> + <parameter type-id='type-id-2' name='m' filepath='Python/import.c' line='232' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_AddModuleObject' mangled-name='PyImport_AddModuleObject' filepath='Python/import.c' line='354' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_AddModuleObject'> + <parameter type-id='type-id-2' name='name' filepath='Python/import.c' line='354' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_AddModule' mangled-name='PyImport_AddModule' filepath='Python/import.c' line='372' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_AddModule'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='372' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyState_FindModule' mangled-name='PyState_FindModule' filepath='Python/import.c' line='488' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyState_FindModule'> + <parameter type-id='type-id-399' name='module' filepath='Python/import.c' line='488' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyState_AddModule' mangled-name='_PyState_AddModule' filepath='Python/import.c' line='502' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyState_AddModule'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/import.c' line='502' column='1'/> + <parameter type-id='type-id-2' name='module' filepath='Python/import.c' line='502' column='1'/> + <parameter type-id='type-id-399' name='def' filepath='Python/import.c' line='502' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyState_AddModule' mangled-name='PyState_AddModule' filepath='Python/import.c' line='518' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyState_AddModule'> + <parameter type-id='type-id-2' name='module' filepath='Python/import.c' line='518' column='1'/> + <parameter type-id='type-id-399' name='def' filepath='Python/import.c' line='518' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyState_RemoveModule' mangled-name='PyState_RemoveModule' filepath='Python/import.c' line='547' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyState_RemoveModule'> + <parameter type-id='type-id-399' name='def' filepath='Python/import.c' line='547' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_ClearExtension' mangled-name='_PyImport_ClearExtension' filepath='Python/import.c' line='777' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_ClearExtension'> + <parameter type-id='type-id-2' name='name' filepath='Python/import.c' line='777' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/import.c' line='777' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_FixupExtensionObject' mangled-name='_PyImport_FixupExtensionObject' filepath='Python/import.c' line='1186' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_FixupExtensionObject'> + <parameter type-id='type-id-2' name='mod' filepath='Python/import.c' line='1186' column='1'/> + <parameter type-id='type-id-2' name='name' filepath='Python/import.c' line='1186' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/import.c' line='1187' column='1'/> + <parameter type-id='type-id-2' name='modules' filepath='Python/import.c' line='1187' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_FixupBuiltin' mangled-name='_PyImport_FixupBuiltin' filepath='Python/import.c' line='1299' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_FixupBuiltin'> + <parameter type-id='type-id-2' name='mod' filepath='Python/import.c' line='1299' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='1299' column='1'/> + <parameter type-id='type-id-2' name='modules' filepath='Python/import.c' line='1299' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_ExtendInittab' mangled-name='PyImport_ExtendInittab' filepath='Python/import.c' line='1397' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ExtendInittab'> + <parameter type-id='type-id-922' name='newtab' filepath='Python/import.c' line='1397' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_AppendInittab' mangled-name='PyImport_AppendInittab' filepath='Python/import.c' line='1447' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_AppendInittab'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='1447' column='1'/> + <parameter type-id='type-id-390' name='initfunc' filepath='Python/import.c' line='1447' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_GetMagicNumber' mangled-name='PyImport_GetMagicNumber' filepath='Python/import.c' line='1524' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_GetMagicNumber'> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='PyImport_GetMagicTag' mangled-name='PyImport_GetMagicTag' filepath='Python/import.c' line='1546' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_GetMagicTag'> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='PyImport_ExecCodeModule' mangled-name='PyImport_ExecCodeModule' filepath='Python/import.c' line='1567' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ExecCodeModule'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='1567' column='1'/> + <parameter type-id='type-id-2' name='co' filepath='Python/import.c' line='1567' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ExecCodeModuleEx' mangled-name='PyImport_ExecCodeModuleEx' filepath='Python/import.c' line='1574' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ExecCodeModuleEx'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='1574' column='1'/> + <parameter type-id='type-id-2' name='co' filepath='Python/import.c' line='1574' column='1'/> + <parameter type-id='type-id-12' name='pathname' filepath='Python/import.c' line='1574' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ExecCodeModuleWithPathnames' mangled-name='PyImport_ExecCodeModuleWithPathnames' filepath='Python/import.c' line='1581' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ExecCodeModuleWithPathnames'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='1581' column='1'/> + <parameter type-id='type-id-2' name='co' filepath='Python/import.c' line='1581' column='1'/> + <parameter type-id='type-id-12' name='pathname' filepath='Python/import.c' line='1582' column='1'/> + <parameter type-id='type-id-12' name='cpathname' filepath='Python/import.c' line='1583' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ExecCodeModuleObject' mangled-name='PyImport_ExecCodeModuleObject' filepath='Python/import.c' line='1683' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ExecCodeModuleObject'> + <parameter type-id='type-id-2' name='name' filepath='Python/import.c' line='1683' column='1'/> + <parameter type-id='type-id-2' name='co' filepath='Python/import.c' line='1683' column='1'/> + <parameter type-id='type-id-2' name='pathname' filepath='Python/import.c' line='1683' column='1'/> + <parameter type-id='type-id-2' name='cpathname' filepath='Python/import.c' line='1684' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ImportFrozenModuleObject' mangled-name='PyImport_ImportFrozenModuleObject' filepath='Python/import.c' line='2062' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ImportFrozenModuleObject'> + <parameter type-id='type-id-2' name='name' filepath='Python/import.c' line='2062' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyImport_GetImporter' mangled-name='PyImport_GetImporter' filepath='Python/import.c' line='2376' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_GetImporter'> + <parameter type-id='type-id-2' name='path' filepath='Python/import.c' line='2376' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ImportModuleNoBlock' mangled-name='PyImport_ImportModuleNoBlock' filepath='Python/import.c' line='2440' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ImportModuleNoBlock'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='2440' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ImportModuleLevel' mangled-name='PyImport_ImportModuleLevel' filepath='Python/import.c' line='2887' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ImportModuleLevel'> + <parameter type-id='type-id-12' name='name' filepath='Python/import.c' line='2887' column='1'/> + <parameter type-id='type-id-2' name='globals' filepath='Python/import.c' line='2887' column='1'/> + <parameter type-id='type-id-2' name='locals' filepath='Python/import.c' line='2887' column='1'/> + <parameter type-id='type-id-2' name='fromlist' filepath='Python/import.c' line='2888' column='1'/> + <parameter type-id='type-id-8' name='level' filepath='Python/import.c' line='2888' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyImport_ReloadModule' mangled-name='PyImport_ReloadModule' filepath='Python/import.c' line='2905' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyImport_ReloadModule'> + <parameter type-id='type-id-2' name='m' filepath='Python/import.c' line='2905' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_GetModuleAttr' mangled-name='_PyImport_GetModuleAttr' filepath='Python/import.c' line='3220' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyImport_GetModuleAttr'> + <parameter type-id='type-id-2' name='modname' filepath='Python/import.c' line='3220' column='1'/> + <parameter type-id='type-id-2' name='attrname' filepath='Python/import.c' line='3220' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInit__imp' mangled-name='PyInit__imp' filepath='Python/import.c' line='3857' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInit__imp'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_LoadDynamicModuleWithSpec' filepath='Python/importdl.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-229'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/initconfig.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='_PyArgv' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='64' column='1' id='type-id-1425'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='argc' type-id='type-id-14' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='use_bytes_argv' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='bytes_argv' type-id='type-id-136' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='67' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='wchar_argv' type-id='type-id-1426' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='68' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyArgv' type-id='type-id-1425' filepath='./Include/internal/pycore_initconfig.h' line='69' column='1' id='type-id-1427'/> + <class-decl name='_PyPreCmdline' size-in-bits='384' is-struct='yes' naming-typedef-id='type-id-1428' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='97' column='1' id='type-id-1429'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='argv' type-id='type-id-739' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='98' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='xoptions' type-id='type-id-739' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='99' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='isolated' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='100' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='use_environment' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='101' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='dev_mode' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='102' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='352'> + <var-decl name='warn_default_encoding' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_initconfig.h' line='103' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyPreCmdline' type-id='type-id-1429' filepath='./Include/internal/pycore_initconfig.h' line='104' column='1' id='type-id-1428'/> + <pointer-type-def type-id='type-id-742' size-in-bits='64' id='type-id-1430'/> + <pointer-type-def type-id='type-id-739' size-in-bits='64' id='type-id-1431'/> + <pointer-type-def type-id='type-id-1428' size-in-bits='64' id='type-id-1432'/> + <qualified-type-def type-id='type-id-742' const='yes' id='type-id-1433'/> + <pointer-type-def type-id='type-id-1433' size-in-bits='64' id='type-id-1434'/> + <qualified-type-def type-id='type-id-739' const='yes' id='type-id-1435'/> + <pointer-type-def type-id='type-id-1435' size-in-bits='64' id='type-id-232'/> + <qualified-type-def type-id='type-id-1427' const='yes' id='type-id-1436'/> + <pointer-type-def type-id='type-id-1436' size-in-bits='64' id='type-id-1437'/> + <qualified-type-def type-id='type-id-1428' const='yes' id='type-id-1438'/> + <pointer-type-def type-id='type-id-1438' size-in-bits='64' id='type-id-1439'/> + <qualified-type-def type-id='type-id-16' restrict='yes' id='type-id-18'/> + <qualified-type-def type-id='type-id-52' const='yes' id='type-id-1440'/> + <pointer-type-def type-id='type-id-1440' size-in-bits='64' id='type-id-1426'/> + <qualified-type-def type-id='type-id-52' restrict='yes' id='type-id-17'/> + <qualified-type-def type-id='type-id-235' restrict='yes' id='type-id-1441'/> + <pointer-type-def type-id='type-id-235' size-in-bits='64' id='type-id-1442'/> + <var-decl name='Py_DebugFlag' type-id='type-id-8' mangled-name='Py_DebugFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='8' column='1' elf-symbol-id='Py_DebugFlag'/> + <var-decl name='Py_VerboseFlag' type-id='type-id-8' mangled-name='Py_VerboseFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='9' column='1' elf-symbol-id='Py_VerboseFlag'/> + <var-decl name='Py_QuietFlag' type-id='type-id-8' mangled-name='Py_QuietFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='10' column='1' elf-symbol-id='Py_QuietFlag'/> + <var-decl name='Py_InteractiveFlag' type-id='type-id-8' mangled-name='Py_InteractiveFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='11' column='1' elf-symbol-id='Py_InteractiveFlag'/> + <var-decl name='Py_InspectFlag' type-id='type-id-8' mangled-name='Py_InspectFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='12' column='1' elf-symbol-id='Py_InspectFlag'/> + <var-decl name='Py_OptimizeFlag' type-id='type-id-8' mangled-name='Py_OptimizeFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='13' column='1' elf-symbol-id='Py_OptimizeFlag'/> + <var-decl name='Py_NoSiteFlag' type-id='type-id-8' mangled-name='Py_NoSiteFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='14' column='1' elf-symbol-id='Py_NoSiteFlag'/> + <var-decl name='Py_BytesWarningFlag' type-id='type-id-8' mangled-name='Py_BytesWarningFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='15' column='1' elf-symbol-id='Py_BytesWarningFlag'/> + <var-decl name='Py_FrozenFlag' type-id='type-id-8' mangled-name='Py_FrozenFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='16' column='1' elf-symbol-id='Py_FrozenFlag'/> + <var-decl name='Py_IgnoreEnvironmentFlag' type-id='type-id-8' mangled-name='Py_IgnoreEnvironmentFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='17' column='1' elf-symbol-id='Py_IgnoreEnvironmentFlag'/> + <var-decl name='Py_DontWriteBytecodeFlag' type-id='type-id-8' mangled-name='Py_DontWriteBytecodeFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='18' column='1' elf-symbol-id='Py_DontWriteBytecodeFlag'/> + <var-decl name='Py_NoUserSiteDirectory' type-id='type-id-8' mangled-name='Py_NoUserSiteDirectory' visibility='default' filepath='./Include/cpython/pydebug.h' line='19' column='1' elf-symbol-id='Py_NoUserSiteDirectory'/> + <var-decl name='Py_UnbufferedStdioFlag' type-id='type-id-8' mangled-name='Py_UnbufferedStdioFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='20' column='1' elf-symbol-id='Py_UnbufferedStdioFlag'/> + <var-decl name='Py_HashRandomizationFlag' type-id='type-id-8' mangled-name='Py_HashRandomizationFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='21' column='1' elf-symbol-id='Py_HashRandomizationFlag'/> + <var-decl name='Py_IsolatedFlag' type-id='type-id-8' mangled-name='Py_IsolatedFlag' visibility='default' filepath='./Include/cpython/pydebug.h' line='22' column='1' elf-symbol-id='Py_IsolatedFlag'/> + <var-decl name='Py_UTF8Mode' type-id='type-id-8' mangled-name='Py_UTF8Mode' visibility='default' filepath='./Include/fileobject.h' line='29' column='1' elf-symbol-id='Py_UTF8Mode'/> + <function-decl name='Py_DecodeLocale' mangled-name='Py_DecodeLocale' filepath='./Include/fileutils.h' line='8' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_DecodeLocale'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-441'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_Py_GetForceASCII' mangled-name='_Py_GetForceASCII' filepath='./Include/internal/pycore_fileutils.h' line='212' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetForceASCII'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_GetLocaleEncoding' mangled-name='_Py_GetLocaleEncoding' filepath='./Include/internal/pycore_fileutils.h' line='229' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetLocaleEncoding'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_Py_isabs' filepath='./Include/internal/pycore_fileutils.h' line='244' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_abspath' filepath='./Include/internal/pycore_fileutils.h' line='245' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-235'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyOS_ResetGetOpt' filepath='./Include/internal/pycore_getopt.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyOS_GetOpt' filepath='./Include/internal/pycore_getopt.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-14'/> + <parameter type-id='type-id-1426'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyArgv_AsWstrList' mangled-name='_PyArgv_AsWstrList' filepath='./Include/internal/pycore_initconfig.h' line='71' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyArgv_AsWstrList'> + <parameter type-id='type-id-1437'/> + <parameter type-id='type-id-1431'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_Py_str_to_int' mangled-name='_Py_str_to_int' filepath='./Include/internal/pycore_initconfig.h' line='77' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_str_to_int'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-179'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_get_xoption' mangled-name='_Py_get_xoption' filepath='./Include/internal/pycore_initconfig.h' line='80' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_get_xoption'> + <parameter type-id='type-id-232'/> + <parameter type-id='type-id-16'/> + <return type-id='type-id-16'/> + </function-decl> + <function-decl name='_Py_GetEnv' mangled-name='_Py_GetEnv' filepath='./Include/internal/pycore_initconfig.h' line='83' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetEnv'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_Py_get_env_flag' mangled-name='_Py_get_env_flag' filepath='./Include/internal/pycore_initconfig.h' line='86' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_get_env_flag'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPreCmdline_Clear' filepath='./Include/internal/pycore_initconfig.h' line='113' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1432'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPreCmdline_SetConfig' filepath='./Include/internal/pycore_initconfig.h' line='116' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1439'/> + <parameter type-id='type-id-53'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyPreCmdline_Read' filepath='./Include/internal/pycore_initconfig.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1432'/> + <parameter type-id='type-id-1434'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyPreConfig_InitFromPreConfig' filepath='./Include/internal/pycore_initconfig.h' line='129' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1430'/> + <parameter type-id='type-id-1434'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyPreConfig_AsDict' filepath='./Include/internal/pycore_initconfig.h' line='132' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1434'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyPreConfig_GetConfig' filepath='./Include/internal/pycore_initconfig.h' line='133' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1430'/> + <parameter type-id='type-id-260'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyConfig_InitPathConfig' filepath='./Include/internal/pycore_initconfig.h' line='153' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-53'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_Py_IsLocaleCoercionTarget' mangled-name='_Py_IsLocaleCoercionTarget' filepath='./Include/internal/pycore_pylifecycle.h' line='28' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_IsLocaleCoercionTarget'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySys_ReadPreinitWarnOptions' filepath='./Include/internal/pycore_pylifecycle.h' line='38' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1431'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PySys_ReadPreinitXOptions' filepath='./Include/internal/pycore_pylifecycle.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-53'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_Py_PreInitializeFromConfig' mangled-name='_Py_PreInitializeFromConfig' filepath='./Include/internal/pycore_pylifecycle.h' line='77' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_PreInitializeFromConfig'> + <parameter type-id='type-id-260'/> + <parameter type-id='type-id-1437'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='setlocale' filepath='/usr/include/locale.h' line='122' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='setvbuf' filepath='/usr/include/stdio.h' line='332' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-412'/> + <parameter type-id='type-id-183'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='printf' filepath='/usr/include/stdio.h' line='356' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='puts' filepath='/usr/include/stdio.h' line='661' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='strtoul' filepath='/usr/include/stdlib.h' line='181' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-184'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='getenv' filepath='/usr/include/stdlib.h' line='641' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='wcschr' filepath='/usr/include/wchar.h' line='165' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-422'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='wcstok' filepath='/usr/include/wchar.h' line='218' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-18'/> + <parameter type-id='type-id-1441'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='wcstol' filepath='/usr/include/wchar.h' line='429' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-18'/> + <parameter type-id='type-id-1441'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='PyStatus_Ok' mangled-name='PyStatus_Ok' filepath='Python/initconfig.c' line='312' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_Ok'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyStatus_Error' mangled-name='PyStatus_Error' filepath='Python/initconfig.c' line='315' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_Error'> + <parameter type-id='type-id-12' name='err_msg' filepath='Python/initconfig.c' line='315' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyStatus_Exit' mangled-name='PyStatus_Exit' filepath='Python/initconfig.c' line='325' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_Exit'> + <parameter type-id='type-id-8' name='exitcode' filepath='Python/initconfig.c' line='325' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyStatus_IsError' mangled-name='PyStatus_IsError' filepath='Python/initconfig.c' line='329' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_IsError'> + <parameter type-id='type-id-54' name='status' filepath='Python/initconfig.c' line='329' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyStatus_IsExit' mangled-name='PyStatus_IsExit' filepath='Python/initconfig.c' line='332' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyStatus_IsExit'> + <parameter type-id='type-id-54' name='status' filepath='Python/initconfig.c' line='332' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_SetFromPyStatus' mangled-name='_PyErr_SetFromPyStatus' filepath='Python/initconfig.c' line='339' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_SetFromPyStatus'> + <parameter type-id='type-id-54' name='status' filepath='Python/initconfig.c' line='339' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyWideStringList_Clear' mangled-name='_PyWideStringList_Clear' filepath='Python/initconfig.c' line='375' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWideStringList_Clear'> + <parameter type-id='type-id-1431' name='list' filepath='Python/initconfig.c' line='375' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyWideStringList_Copy' mangled-name='_PyWideStringList_Copy' filepath='Python/initconfig.c' line='388' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWideStringList_Copy'> + <parameter type-id='type-id-1431' name='list' filepath='Python/initconfig.c' line='388' column='1'/> + <parameter type-id='type-id-232' name='list2' filepath='Python/initconfig.c' line='388' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyWideStringList_Insert' mangled-name='PyWideStringList_Insert' filepath='Python/initconfig.c' line='423' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyWideStringList_Insert'> + <parameter type-id='type-id-1431' name='list' filepath='Python/initconfig.c' line='423' column='1'/> + <parameter type-id='type-id-14' name='index' filepath='Python/initconfig.c' line='424' column='1'/> + <parameter type-id='type-id-16' name='item' filepath='Python/initconfig.c' line='424' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyWideStringList_Append' mangled-name='PyWideStringList_Append' filepath='Python/initconfig.c' line='464' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyWideStringList_Append'> + <parameter type-id='type-id-1431' name='list' filepath='Python/initconfig.c' line='464' column='1'/> + <parameter type-id='type-id-16' name='item' filepath='Python/initconfig.c' line='464' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyWideStringList_Extend' mangled-name='_PyWideStringList_Extend' filepath='Python/initconfig.c' line='471' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWideStringList_Extend'> + <parameter type-id='type-id-1431' name='list' filepath='Python/initconfig.c' line='471' column='1'/> + <parameter type-id='type-id-232' name='list2' filepath='Python/initconfig.c' line='471' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyWideStringList_AsList' mangled-name='_PyWideStringList_AsList' filepath='Python/initconfig.c' line='496' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyWideStringList_AsList'> + <parameter type-id='type-id-232' name='list' filepath='Python/initconfig.c' line='496' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_SetStandardStreamEncoding' mangled-name='Py_SetStandardStreamEncoding' filepath='Python/initconfig.c' line='527' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_SetStandardStreamEncoding'> + <parameter type-id='type-id-12' name='encoding' filepath='Python/initconfig.c' line='527' column='1'/> + <parameter type-id='type-id-12' name='errors' filepath='Python/initconfig.c' line='527' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_ClearStandardStreamEncoding' mangled-name='_Py_ClearStandardStreamEncoding' filepath='Python/initconfig.c' line='585' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_ClearStandardStreamEncoding'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_ClearArgcArgv' mangled-name='_Py_ClearArgcArgv' filepath='Python/initconfig.c' line='608' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_ClearArgcArgv'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_GetArgcArgv' mangled-name='Py_GetArgcArgv' filepath='Python/initconfig.c' line='639' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetArgcArgv'> + <parameter type-id='type-id-179' name='argc' filepath='Python/initconfig.c' line='639' column='1'/> + <parameter type-id='type-id-1442' name='argv' filepath='Python/initconfig.c' line='639' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyConfig_InitCompatConfig' mangled-name='_PyConfig_InitCompatConfig' filepath='Python/initconfig.c' line='758' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyConfig_InitCompatConfig'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='758' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyConfig_InitIsolatedConfig' mangled-name='PyConfig_InitIsolatedConfig' filepath='Python/initconfig.c' line='842' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_InitIsolatedConfig'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='842' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyConfig_SetString' mangled-name='PyConfig_SetString' filepath='Python/initconfig.c' line='867' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_SetString'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='867' column='1'/> + <parameter type-id='type-id-235' name='config_str' filepath='Python/initconfig.c' line='867' column='1'/> + <parameter type-id='type-id-16' name='str' filepath='Python/initconfig.c' line='867' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyConfig_SetBytesString' mangled-name='PyConfig_SetBytesString' filepath='Python/initconfig.c' line='929' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_SetBytesString'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='929' column='1'/> + <parameter type-id='type-id-235' name='config_str' filepath='Python/initconfig.c' line='929' column='1'/> + <parameter type-id='type-id-12' name='str' filepath='Python/initconfig.c' line='930' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyConfig_AsDict' mangled-name='_PyConfig_AsDict' filepath='Python/initconfig.c' line='1038' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyConfig_AsDict'> + <parameter type-id='type-id-260' name='config' filepath='Python/initconfig.c' line='1038' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyConfig_FromDict' mangled-name='_PyConfig_FromDict' filepath='Python/initconfig.c' line='1306' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyConfig_FromDict'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='1306' column='1'/> + <parameter type-id='type-id-2' name='dict' filepath='Python/initconfig.c' line='1306' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyConfig_SetArgv' mangled-name='PyConfig_SetArgv' filepath='Python/initconfig.c' line='2955' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_SetArgv'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='2955' column='1'/> + <parameter type-id='type-id-14' name='argc' filepath='Python/initconfig.c' line='2955' column='1'/> + <parameter type-id='type-id-1426' name='argv' filepath='Python/initconfig.c' line='2955' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyConfig_SetWideStringList' mangled-name='PyConfig_SetWideStringList' filepath='Python/initconfig.c' line='2967' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_SetWideStringList'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='2967' column='1'/> + <parameter type-id='type-id-1431' name='list' filepath='Python/initconfig.c' line='2967' column='1'/> + <parameter type-id='type-id-14' name='length' filepath='Python/initconfig.c' line='2968' column='1'/> + <parameter type-id='type-id-235' name='items' filepath='Python/initconfig.c' line='2968' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='PyConfig_Read' mangled-name='PyConfig_Read' filepath='Python/initconfig.c' line='3051' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyConfig_Read'> + <parameter type-id='type-id-53' name='config' filepath='Python/initconfig.c' line='3051' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_Py_GetConfigsAsDict' mangled-name='_Py_GetConfigsAsDict' filepath='Python/initconfig.c' line='3058' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_GetConfigsAsDict'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/instrumentation.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_PyInstrumentation_MISSING' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_instruments.h' line='102' column='1'/> + <var-decl name='_PyInstrumentation_DISABLE' type-id='type-id-345' visibility='default' filepath='./Include/internal/pycore_instruments.h' line='103' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='Python/intrinsics.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-1443' size-in-bits='768' id='type-id-1444'> + <subrange length='12' type-id='type-id-28' id='type-id-653'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-1443' size-in-bits='infinite' id='type-id-1445'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-1446' size-in-bits='320' id='type-id-1447'> + <subrange length='5' type-id='type-id-28' id='type-id-689'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-1446' size-in-bits='infinite' id='type-id-1448'> + <subrange length='infinite' id='type-id-225'/> + </array-type-def> + <typedef-decl name='instrinsic_func1' type-id='type-id-1449' filepath='./Include/internal/pycore_intrinsics.h' line='29' column='1' id='type-id-1450'/> + <typedef-decl name='instrinsic_func2' type-id='type-id-1451' filepath='./Include/internal/pycore_intrinsics.h' line='30' column='1' id='type-id-1452'/> + <pointer-type-def type-id='type-id-1453' size-in-bits='64' id='type-id-1449'/> + <pointer-type-def type-id='type-id-1454' size-in-bits='64' id='type-id-1451'/> + <qualified-type-def type-id='type-id-1450' const='yes' id='type-id-1443'/> + <qualified-type-def type-id='type-id-1452' const='yes' id='type-id-1446'/> + <function-decl name='_PyFrame_LocalsToFast' filepath='./Include/internal/pycore_frame.h' line='233' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-374'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_set_function_type_params' filepath='./Include/internal/pycore_function.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyAsyncGenValueWrapperNew' filepath='./Include/internal/pycore_genobject.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='_PyIntrinsics_UnaryFunctions' type-id='type-id-1445' visibility='default' filepath='./Include/internal/pycore_intrinsics.h' line='31' column='1'/> + <var-decl name='_PyIntrinsics_BinaryFunctions' type-id='type-id-1448' visibility='default' filepath='./Include/internal/pycore_intrinsics.h' line='32' column='1'/> + <function-decl name='_Py_make_typevar' filepath='./Include/internal/pycore_typevarobject.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_make_paramspec' filepath='./Include/internal/pycore_typevarobject.h' line='12' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_make_typevartuple' filepath='./Include/internal/pycore_typevarobject.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_make_typealias' filepath='./Include/internal/pycore_typevarobject.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_subscript_generic' filepath='./Include/internal/pycore_typevarobject.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1453'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + <function-type size-in-bits='64' id='type-id-1454'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Python/legacy_tracing.c' comp-dir-path='/src' language='LANG_C11'> + <typedef-decl name='_PyMonitoringEventSet' type-id='type-id-352' filepath='./Include/internal/pycore_instruments.h' line='47' column='1' id='type-id-1455'/> + <function-decl name='_PyMonitoring_RegisterCallback' filepath='./Include/internal/pycore_instruments.h' line='62' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyMonitoring_SetEvents' filepath='./Include/internal/pycore_instruments.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1455'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_Instrumentation_GetLine' filepath='./Include/internal/pycore_instruments.h' line='100' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/marshal.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-116' size-in-bits='192' id='type-id-1456'> + <subrange length='3' type-id='type-id-28' id='type-id-630'/> + </array-type-def> + <class-decl name='stat' size-in-bits='1152' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='26' column='1' id='type-id-1457'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='st_dev' type-id='type-id-187' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='31' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='st_ino' type-id='type-id-1458' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='36' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='st_nlink' type-id='type-id-1459' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='44' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='st_mode' type-id='type-id-123' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='45' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='st_uid' type-id='type-id-125' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='47' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='st_gid' type-id='type-id-121' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='48' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='288'> + <var-decl name='__pad0' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='50' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='st_rdev' type-id='type-id-187' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='52' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='st_size' type-id='type-id-1279' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='57' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='448'> + <var-decl name='st_blksize' type-id='type-id-1460' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='61' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='512'> + <var-decl name='st_blocks' type-id='type-id-1461' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='63' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='576'> + <var-decl name='st_atim' type-id='type-id-1341' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='704'> + <var-decl name='st_mtim' type-id='type-id-1341' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='75' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='832'> + <var-decl name='st_ctim' type-id='type-id-1341' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='76' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='960'> + <var-decl name='__glibc_reserved' type-id='type-id-1456' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/struct_stat.h' line='89' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='__gid_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='147' column='1' id='type-id-121'/> + <typedef-decl name='__ino_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='148' column='1' id='type-id-1458'/> + <typedef-decl name='__mode_t' type-id='type-id-95' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='150' column='1' id='type-id-123'/> + <typedef-decl name='__nlink_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='151' column='1' id='type-id-1459'/> + <typedef-decl name='__blksize_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='175' column='1' id='type-id-1460'/> + <typedef-decl name='__blkcnt_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='180' column='1' id='type-id-1461'/> + <pointer-type-def type-id='type-id-1457' size-in-bits='64' id='type-id-51'/> + <function-decl name='_Py_fstat_noraise' mangled-name='_Py_fstat_noraise' filepath='./Include/internal/pycore_fileutils.h' line='97' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_fstat_noraise'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-51'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='fread' filepath='/usr/include/stdio.h' line='675' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-226'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-412'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='PyMarshal_WriteLongToFile' mangled-name='PyMarshal_WriteLongToFile' filepath='Python/marshal.c' line='629' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_WriteLongToFile'> + <parameter type-id='type-id-47' name='x' filepath='Python/marshal.c' line='629' column='1'/> + <parameter type-id='type-id-229' name='fp' filepath='Python/marshal.c' line='629' column='1'/> + <parameter type-id='type-id-8' name='version' filepath='Python/marshal.c' line='629' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyMarshal_WriteObjectToFile' mangled-name='PyMarshal_WriteObjectToFile' filepath='Python/marshal.c' line='644' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_WriteObjectToFile'> + <parameter type-id='type-id-2' name='x' filepath='Python/marshal.c' line='644' column='1'/> + <parameter type-id='type-id-229' name='fp' filepath='Python/marshal.c' line='644' column='1'/> + <parameter type-id='type-id-8' name='version' filepath='Python/marshal.c' line='644' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyMarshal_ReadShortFromFile' mangled-name='PyMarshal_ReadShortFromFile' filepath='Python/marshal.c' line='1518' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_ReadShortFromFile'> + <parameter type-id='type-id-229' name='fp' filepath='Python/marshal.c' line='1518' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyMarshal_ReadLongFromFile' mangled-name='PyMarshal_ReadLongFromFile' filepath='Python/marshal.c' line='1534' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_ReadLongFromFile'> + <parameter type-id='type-id-229' name='fp' filepath='Python/marshal.c' line='1534' column='1'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='PyMarshal_ReadLastObjectFromFile' mangled-name='PyMarshal_ReadLastObjectFromFile' filepath='Python/marshal.c' line='1570' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_ReadLastObjectFromFile'> + <parameter type-id='type-id-229' name='fp' filepath='Python/marshal.c' line='1570' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMarshal_ReadObjectFromFile' mangled-name='PyMarshal_ReadObjectFromFile' filepath='Python/marshal.c' line='1595' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_ReadObjectFromFile'> + <parameter type-id='type-id-229' name='fp' filepath='Python/marshal.c' line='1595' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMarshal_WriteObjectToString' mangled-name='PyMarshal_WriteObjectToString' filepath='Python/marshal.c' line='1636' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_WriteObjectToString'> + <parameter type-id='type-id-2' name='x' filepath='Python/marshal.c' line='1636' column='1'/> + <parameter type-id='type-id-8' name='version' filepath='Python/marshal.c' line='1636' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyMarshal_Init' mangled-name='PyMarshal_Init' filepath='Python/marshal.c' line='1886' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyMarshal_Init'> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/modsupport.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_convert_optional_to_ssize_t' mangled-name='_Py_convert_optional_to_ssize_t' filepath='Python/modsupport.c' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_convert_optional_to_ssize_t'> + <parameter type-id='type-id-2' name='obj' filepath='Python/modsupport.c' line='16' column='1'/> + <parameter type-id='type-id-22' name='result' filepath='Python/modsupport.c' line='16' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_VaBuildValue' mangled-name='Py_VaBuildValue' filepath='Python/modsupport.c' line='530' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_VaBuildValue'> + <parameter type-id='type-id-12' name='format' filepath='Python/modsupport.c' line='530' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/modsupport.c' line='530' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_VaBuildValue_SizeT' mangled-name='_Py_VaBuildValue_SizeT' filepath='Python/modsupport.c' line='536' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_VaBuildValue_SizeT'> + <parameter type-id='type-id-12' name='format' filepath='Python/modsupport.c' line='536' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/modsupport.c' line='536' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyModule_AddObject' mangled-name='PyModule_AddObject' filepath='Python/modsupport.c' line='661' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_AddObject'> + <parameter type-id='type-id-2' name='mod' filepath='Python/modsupport.c' line='661' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Python/modsupport.c' line='661' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Python/modsupport.c' line='661' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyModule_AddStringConstant' mangled-name='PyModule_AddStringConstant' filepath='Python/modsupport.c' line='683' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyModule_AddStringConstant'> + <parameter type-id='type-id-2' name='m' filepath='Python/modsupport.c' line='683' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Python/modsupport.c' line='683' column='1'/> + <parameter type-id='type-id-12' name='value' filepath='Python/modsupport.c' line='683' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/mysnprintf.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='vsnprintf' filepath='/usr/include/stdio.h' line='382' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-306'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyOS_vsnprintf' mangled-name='PyOS_vsnprintf' filepath='Python/mysnprintf.c' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_vsnprintf'> + <parameter type-id='type-id-15' name='str' filepath='Python/mysnprintf.c' line='53' column='1'/> + <parameter type-id='type-id-19' name='size' filepath='Python/mysnprintf.c' line='53' column='1'/> + <parameter type-id='type-id-12' name='format' filepath='Python/mysnprintf.c' line='53' column='1'/> + <parameter type-id='type-id-306' name='va' filepath='Python/mysnprintf.c' line='53' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pathconfig.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_wreadlink' mangled-name='_Py_wreadlink' filepath='./Include/internal/pycore_fileutils.h' line='133' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_wreadlink'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-52'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_wrealpath' mangled-name='_Py_wrealpath' filepath='./Include/internal/pycore_fileutils.h' line='142' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_wrealpath'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-52'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_Py_wgetcwd' mangled-name='_Py_wgetcwd' filepath='./Include/internal/pycore_fileutils.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_wgetcwd'> + <parameter type-id='type-id-52'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='wcscpy' filepath='/usr/include/wchar.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-18'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='wcsncpy' filepath='/usr/include/wchar.h' line='92' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-17'/> + <parameter type-id='type-id-18'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='wcsrchr' filepath='/usr/include/wchar.h' line='175' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-422'/> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='_PyPathConfig_ClearGlobal' mangled-name='_PyPathConfig_ClearGlobal' filepath='Python/pathconfig.c' line='57' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyPathConfig_ClearGlobal'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_SetPath' mangled-name='Py_SetPath' filepath='Python/pathconfig.c' line='215' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_SetPath'> + <parameter type-id='type-id-16' name='path' filepath='Python/pathconfig.c' line='215' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_SetPythonHome' mangled-name='Py_SetPythonHome' filepath='Python/pathconfig.c' line='256' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_SetPythonHome'> + <parameter type-id='type-id-16' name='home' filepath='Python/pathconfig.c' line='256' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_SetProgramName' mangled-name='Py_SetProgramName' filepath='Python/pathconfig.c' line='279' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_SetProgramName'> + <parameter type-id='type-id-16' name='program_name' filepath='Python/pathconfig.c' line='279' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_SetProgramFullPath' mangled-name='_Py_SetProgramFullPath' filepath='Python/pathconfig.c' line='301' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_SetProgramFullPath'> + <parameter type-id='type-id-16' name='program_full_path' filepath='Python/pathconfig.c' line='301' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_GetPath' mangled-name='Py_GetPath' filepath='Python/pathconfig.c' line='324' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetPath'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='Py_GetPrefix' mangled-name='Py_GetPrefix' filepath='Python/pathconfig.c' line='347' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetPrefix'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='Py_GetExecPrefix' mangled-name='Py_GetExecPrefix' filepath='Python/pathconfig.c' line='354' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetExecPrefix'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='Py_GetProgramFullPath' mangled-name='Py_GetProgramFullPath' filepath='Python/pathconfig.c' line='361' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetProgramFullPath'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='Py_GetPythonHome' mangled-name='Py_GetPythonHome' filepath='Python/pathconfig.c' line='368' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetPythonHome'> + <return type-id='type-id-52'/> + </function-decl> + <function-decl name='Py_GetProgramName' mangled-name='Py_GetProgramName' filepath='Python/pathconfig.c' line='375' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_GetProgramName'> + <return type-id='type-id-52'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/perf_trampoline.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='_Py_perfmap_callbacks' type-id='type-id-1462' visibility='default' filepath='./Include/internal/pycore_ceval.h' line='79' column='1'/> + <function-decl name='mprotect' filepath='/usr/include/x86_64-linux-gnu/sys/mman.h' line='81' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/preconfig.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_CoerceLegacyLocale' mangled-name='_Py_CoerceLegacyLocale' filepath='./Include/cpython/pylifecycle.h' line='62' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_CoerceLegacyLocale'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_LegacyLocaleDetected' mangled-name='_Py_LegacyLocaleDetected' filepath='./Include/cpython/pylifecycle.h' line='63' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_LegacyLocaleDetected'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_SetLocaleFromEnv' mangled-name='_Py_SetLocaleFromEnv' filepath='./Include/cpython/pylifecycle.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_SetLocaleFromEnv'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-15'/> + </function-decl> + <var-decl name='Py_FileSystemDefaultEncoding' type-id='type-id-12' mangled-name='Py_FileSystemDefaultEncoding' visibility='default' filepath='./Include/fileobject.h' line='22' column='1' elf-symbol-id='Py_FileSystemDefaultEncoding'/> + <var-decl name='Py_FileSystemDefaultEncodeErrors' type-id='type-id-12' mangled-name='Py_FileSystemDefaultEncodeErrors' visibility='default' filepath='./Include/fileobject.h' line='24' column='1' elf-symbol-id='Py_FileSystemDefaultEncodeErrors'/> + <var-decl name='Py_HasFileSystemDefaultEncoding' type-id='type-id-8' mangled-name='Py_HasFileSystemDefaultEncoding' visibility='default' filepath='./Include/fileobject.h' line='26' column='1' elf-symbol-id='Py_HasFileSystemDefaultEncoding'/> + <var-decl name='_Py_HasFileSystemDefaultEncodeErrors' type-id='type-id-8' mangled-name='_Py_HasFileSystemDefaultEncodeErrors' visibility='default' filepath='./Include/internal/pycore_fileutils.h' line='186' column='1' elf-symbol-id='_Py_HasFileSystemDefaultEncodeErrors'/> + <function-decl name='wcsncmp' filepath='/usr/include/wchar.h' line='109' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-16'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPreConfig_InitCompatConfig' mangled-name='_PyPreConfig_InitCompatConfig' filepath='Python/preconfig.c' line='283' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyPreConfig_InitCompatConfig'> + <parameter type-id='type-id-1430' name='config' filepath='Python/preconfig.c' line='283' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyPreConfig_InitPythonConfig' mangled-name='PyPreConfig_InitPythonConfig' filepath='Python/preconfig.c' line='311' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyPreConfig_InitPythonConfig'> + <parameter type-id='type-id-1430' name='config' filepath='Python/preconfig.c' line='311' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyPreConfig_InitIsolatedConfig' mangled-name='PyPreConfig_InitIsolatedConfig' filepath='Python/preconfig.c' line='332' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyPreConfig_InitIsolatedConfig'> + <parameter type-id='type-id-1430' name='config' filepath='Python/preconfig.c' line='332' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pyctype.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-382' size-in-bits='2048' id='type-id-1463'> + <subrange length='256' type-id='type-id-28' id='type-id-62'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-1464' size-in-bits='8192' id='type-id-1465'> + <subrange length='256' type-id='type-id-28' id='type-id-62'/> + </array-type-def> + <qualified-type-def type-id='type-id-95' const='yes' id='type-id-1464'/> + <var-decl name='_Py_ctype_table' type-id='type-id-1465' mangled-name='_Py_ctype_table' visibility='default' filepath='./Include/cpython/pyctype.h' line='16' column='1' elf-symbol-id='_Py_ctype_table'/> + <var-decl name='_Py_ctype_tolower' type-id='type-id-1463' mangled-name='_Py_ctype_tolower' visibility='default' filepath='./Include/cpython/pyctype.h' line='29' column='1' elf-symbol-id='_Py_ctype_tolower'/> + <var-decl name='_Py_ctype_toupper' type-id='type-id-1463' mangled-name='_Py_ctype_toupper' visibility='default' filepath='./Include/cpython/pyctype.h' line='30' column='1' elf-symbol-id='_Py_ctype_toupper'/> + </abi-instr> + <abi-instr address-size='64' path='Python/pyhash.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-85' size-in-bits='128' id='type-id-1466'> + <subrange length='16' type-id='type-id-28' id='type-id-57'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-85' size-in-bits='192' id='type-id-1467'> + <subrange length='24' type-id='type-id-28' id='type-id-674'/> + </array-type-def> + <union-decl name='_Py_HashSecret_t' size-in-bits='192' naming-typedef-id='type-id-1468' visibility='default' filepath='./Include/pyhash.h' line='55' column='1' id='type-id-1469'> + <data-member access='public'> + <var-decl name='uc' type-id='type-id-1467' visibility='default' filepath='./Include/pyhash.h' line='57' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='fnv' type-id='type-id-1470' visibility='default' filepath='./Include/pyhash.h' line='62' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='siphash' type-id='type-id-1471' visibility='default' filepath='./Include/pyhash.h' line='67' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='djbx33a' type-id='type-id-1472' visibility='default' filepath='./Include/pyhash.h' line='72' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='expat' type-id='type-id-1473' visibility='default' filepath='./Include/pyhash.h' line='76' column='1'/> + </data-member> + </union-decl> + <class-decl name='__anonymous_struct__' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/pyhash.h' line='59' column='1' id='type-id-1470'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='prefix' type-id='type-id-305' visibility='default' filepath='./Include/pyhash.h' line='60' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='suffix' type-id='type-id-305' visibility='default' filepath='./Include/pyhash.h' line='61' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__1' size-in-bits='128' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/pyhash.h' line='64' column='1' id='type-id-1471'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='k0' type-id='type-id-117' visibility='default' filepath='./Include/pyhash.h' line='65' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='k1' type-id='type-id-117' visibility='default' filepath='./Include/pyhash.h' line='66' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__2' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/pyhash.h' line='69' column='1' id='type-id-1472'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='padding' type-id='type-id-1466' visibility='default' filepath='./Include/pyhash.h' line='70' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='suffix' type-id='type-id-305' visibility='default' filepath='./Include/pyhash.h' line='71' column='1'/> + </data-member> + </class-decl> + <class-decl name='__anonymous_struct__3' size-in-bits='192' is-struct='yes' is-anonymous='yes' visibility='default' filepath='./Include/pyhash.h' line='73' column='1' id='type-id-1473'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='padding' type-id='type-id-1466' visibility='default' filepath='./Include/pyhash.h' line='74' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='hashsalt' type-id='type-id-305' visibility='default' filepath='./Include/pyhash.h' line='75' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_HashSecret_t' type-id='type-id-1469' filepath='./Include/pyhash.h' line='77' column='1' id='type-id-1468'/> + <class-decl name='PyHash_FuncDef' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1474' visibility='default' filepath='./Include/pyhash.h' line='86' column='1' id='type-id-1475'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='hash' type-id='type-id-1476' visibility='default' filepath='./Include/pyhash.h' line='87' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='name' type-id='type-id-12' visibility='default' filepath='./Include/pyhash.h' line='88' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='hash_bits' type-id='type-id-261' visibility='default' filepath='./Include/pyhash.h' line='89' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='seed_bits' type-id='type-id-261' visibility='default' filepath='./Include/pyhash.h' line='90' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyHash_FuncDef' type-id='type-id-1475' filepath='./Include/pyhash.h' line='91' column='1' id='type-id-1474'/> + <pointer-type-def type-id='type-id-1474' size-in-bits='64' id='type-id-1477'/> + <pointer-type-def type-id='type-id-1478' size-in-bits='64' id='type-id-1479'/> + <qualified-type-def type-id='type-id-1479' const='yes' id='type-id-1476'/> + <var-decl name='_Py_HashSecret' type-id='type-id-1468' mangled-name='_Py_HashSecret' visibility='default' filepath='./Include/pyhash.h' line='78' column='1' elf-symbol-id='_Py_HashSecret'/> + <function-decl name='PyHash_GetFuncDef' mangled-name='PyHash_GetFuncDef' filepath='Python/pyhash.c' line='221' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyHash_GetFuncDef'> + <return type-id='type-id-1477'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1478'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-305'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Python/pylifecycle.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='PyInterpreterConfig' size-in-bits='224' is-struct='yes' naming-typedef-id='type-id-1480' visibility='default' filepath='./Include/cpython/initconfig.h' line='247' column='1' id='type-id-1481'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='use_main_obmalloc' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='249' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='allow_fork' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='250' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='allow_exec' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='251' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='allow_threads' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='252' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='allow_daemon_threads' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='253' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='check_multi_interp_extensions' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='254' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='own_gil' type-id='type-id-8' visibility='default' filepath='./Include/cpython/initconfig.h' line='255' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='PyInterpreterConfig' type-id='type-id-1481' filepath='./Include/cpython/initconfig.h' line='256' column='1' id='type-id-1480'/> + <class-decl name='_PyPerf_Callbacks' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1462' visibility='default' filepath='./Include/internal/pycore_ceval.h' line='62' column='1' id='type-id-1482'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='init_state' type-id='type-id-813' visibility='default' filepath='./Include/internal/pycore_ceval.h' line='64' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='write_state' type-id='type-id-814' visibility='default' filepath='./Include/internal/pycore_ceval.h' line='66' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='free_state' type-id='type-id-815' visibility='default' filepath='./Include/internal/pycore_ceval.h' line='69' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyPerf_Callbacks' type-id='type-id-1482' filepath='./Include/internal/pycore_ceval.h' line='70' column='1' id='type-id-1462'/> + <class-decl name='_PyShimCodeDef' size-in-bits='192' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_code.h' line='453' column='1' id='type-id-1483'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='code' type-id='type-id-316' visibility='default' filepath='./Include/internal/pycore_code.h' line='454' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='codelen' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='455' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='stacksize' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_code.h' line='456' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='cname' type-id='type-id-12' visibility='default' filepath='./Include/internal/pycore_code.h' line='457' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_PyShimCodeDef' type-id='type-id-1483' filepath='./Include/internal/pycore_code.h' line='458' column='1' id='type-id-1484'/> + <typedef-decl name='PyOS_sighandler_t' type-id='type-id-1013' filepath='./Include/pylifecycle.h' line='61' column='1' id='type-id-1485'/> + <typedef-decl name='nl_item' type-id='type-id-8' filepath='/usr/include/nl_types.h' line='36' column='1' id='type-id-1486'/> + <typedef-decl name='sigset_t' type-id='type-id-30' filepath='/usr/include/x86_64-linux-gnu/bits/types/sigset_t.h' line='7' column='1' id='type-id-73'/> + <pointer-type-def type-id='type-id-177' size-in-bits='64' id='type-id-1487'/> + <pointer-type-def type-id='type-id-1462' size-in-bits='64' id='type-id-231'/> + <qualified-type-def type-id='type-id-1480' const='yes' id='type-id-1488'/> + <pointer-type-def type-id='type-id-1488' size-in-bits='64' id='type-id-1489'/> + <qualified-type-def type-id='type-id-1484' const='yes' id='type-id-1490'/> + <pointer-type-def type-id='type-id-1490' size-in-bits='64' id='type-id-1491'/> + <qualified-type-def type-id='type-id-834' const='yes' id='type-id-1492'/> + <pointer-type-def type-id='type-id-1492' size-in-bits='64' id='type-id-1493'/> + <qualified-type-def type-id='type-id-1493' restrict='yes' id='type-id-1494'/> + <pointer-type-def type-id='type-id-834' size-in-bits='64' id='type-id-1495'/> + <qualified-type-def type-id='type-id-1495' restrict='yes' id='type-id-1496'/> + <pointer-type-def type-id='type-id-73' size-in-bits='64' id='type-id-45'/> + <function-decl name='_Py_FinishPendingCalls' filepath='./Include/internal/pycore_ceval.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_Fini' filepath='./Include/internal/pycore_ceval.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPerfTrampoline_SetCallbacks' filepath='./Include/internal/pycore_ceval.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-231'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPerfTrampoline_Init' filepath='./Include/internal/pycore_ceval.h' line='74' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyPerfTrampoline_Fini' filepath='./Include/internal/pycore_ceval.h' line='75' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyEval_InitGIL' filepath='./Include/internal/pycore_ceval.h' line='99' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyEval_FiniGIL' filepath='./Include/internal/pycore_ceval.h' line='100' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_ReleaseLock' filepath='./Include/internal/pycore_ceval.h' line='103' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_MakeShimCode' filepath='./Include/internal/pycore_code.h' line='461' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1491'/> + <return type-id='type-id-328'/> + </function-decl> + <function-decl name='_PyContext_Init' filepath='./Include/internal/pycore_context.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyContext_Fini' filepath='./Include/internal/pycore_context.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyDict_Fini' filepath='./Include/internal/pycore_dict.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyExc_InitState' filepath='./Include/internal/pycore_exceptions.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyExc_InitGlobalObjects' filepath='./Include/internal/pycore_exceptions.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyExc_InitTypes' filepath='./Include/internal/pycore_exceptions.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyExc_Fini' filepath='./Include/internal/pycore_exceptions.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyExc_ClearExceptionGroupType' filepath='./Include/internal/pycore_exceptions.h' line='31' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_write_noraise' mangled-name='_Py_write_noraise' filepath='./Include/internal/pycore_fileutils.h' line='127' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_write_noraise'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_Py_ResetForceASCII' mangled-name='_Py_ResetForceASCII' filepath='./Include/internal/pycore_fileutils.h' line='219' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_ResetForceASCII'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFloat_InitState' filepath='./Include/internal/pycore_floatobject.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFloat_InitTypes' filepath='./Include/internal/pycore_floatobject.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyFloat_Fini' filepath='./Include/internal/pycore_floatobject.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFloat_FiniType' filepath='./Include/internal/pycore_floatobject.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGC_CollectNoFail' filepath='./Include/internal/pycore_gc.h' line='195' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyAsyncGen_Fini' filepath='./Include/internal/pycore_genobject.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_ClearModules' filepath='./Include/internal/pycore_import.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_ClearModulesByIndex' filepath='./Include/internal/pycore_import.h' line='122' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_InitDefaultImportFunc' filepath='./Include/internal/pycore_import.h' line='124' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyImport_GetImportlibLoader' filepath='./Include/internal/pycore_import.h' line='129' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_Init' filepath='./Include/internal/pycore_import.h' line='143' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyImport_Fini' filepath='./Include/internal/pycore_import.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_InitCore' filepath='./Include/internal/pycore_import.h' line='147' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyImport_InitExternal' filepath='./Include/internal/pycore_import.h' line='151' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyImport_FiniCore' filepath='./Include/internal/pycore_import.h' line='152' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_FiniExternal' filepath='./Include/internal/pycore_import.h' line='153' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPreConfig_InitFromConfig' filepath='./Include/internal/pycore_initconfig.h' line='126' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1430'/> + <parameter type-id='type-id-260'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPreConfig_Read' filepath='./Include/internal/pycore_initconfig.h' line='135' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1430'/> + <parameter type-id='type-id-1437'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyPreConfig_Write' filepath='./Include/internal/pycore_initconfig.h' line='137' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1434'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyConfig_Copy' filepath='./Include/internal/pycore_initconfig.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-53'/> + <parameter type-id='type-id-260'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyConfig_InitImportConfig' filepath='./Include/internal/pycore_initconfig.h' line='156' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-53'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyConfig_Read' filepath='./Include/internal/pycore_initconfig.h' line='157' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-53'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyConfig_Write' filepath='./Include/internal/pycore_initconfig.h' line='158' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-260'/> + <parameter type-id='type-id-931'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyInterpreterState_Clear' filepath='./Include/internal/pycore_interp.h' line='198' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyList_Fini' filepath='./Include/internal/pycore_list.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyLong_InitTypes' filepath='./Include/internal/pycore_long.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyLong_FiniTypes' filepath='./Include/internal/pycore_long.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyPathConfig_UpdateGlobal' filepath='./Include/internal/pycore_pathconfig.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-260'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyErr_InitTypes' filepath='./Include/internal/pycore_pyerrors.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyErr_FiniTypes' filepath='./Include/internal/pycore_pyerrors.h' line='15' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_ClearFileSystemEncoding' filepath='./Include/internal/pycore_pylifecycle.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_InitEncodings' filepath='./Include/internal/pycore_pylifecycle.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_Py_InitVersion' filepath='./Include/internal/pycore_pylifecycle.h' line='32' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFaulthandler_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyBuiltin_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='34' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PySys_Create' filepath='./Include/internal/pycore_pylifecycle.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-233'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PySys_UpdateConfig' filepath='./Include/internal/pycore_pylifecycle.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySys_FiniTypes' filepath='./Include/internal/pycore_pylifecycle.h' line='41' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyBuiltins_AddExceptions' filepath='./Include/internal/pycore_pylifecycle.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_HashRandomization_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='43' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-260'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyTime_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='45' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyGC_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='46' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyAtExit_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='47' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_Py_Deepfreeze_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='48' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySignal_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PySignal_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_HashRandomization_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='56' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyFaulthandler_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='57' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyHash_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='58' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTraceMalloc_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThread_FiniType' filepath='./Include/internal/pycore_pylifecycle.h' line='63' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_Deepfreeze_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyArg_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='65' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_FinalizeAllocatedBlocks' filepath='./Include/internal/pycore_pylifecycle.h' line='66' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-178'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGILState_Init' filepath='./Include/internal/pycore_pylifecycle.h' line='68' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyGILState_SetTstate' filepath='./Include/internal/pycore_pylifecycle.h' line='69' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyGILState_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='70' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGC_DumpShutdownStats' filepath='./Include/internal/pycore_pylifecycle.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyAtExit_Call' filepath='./Include/internal/pycore_pylifecycle.h' line='94' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyMem_RawMalloc' filepath='./Include/internal/pycore_pymem_init.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyMem_RawCalloc' filepath='./Include/internal/pycore_pymem_init.h' line='18' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyMem_RawRealloc' filepath='./Include/internal/pycore_pymem_init.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyMem_RawFree' filepath='./Include/internal/pycore_pymem_init.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_Malloc' filepath='./Include/internal/pycore_pymem_init.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyObject_Calloc' filepath='./Include/internal/pycore_pymem_init.h' line='25' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyObject_Free' filepath='./Include/internal/pycore_pymem_init.h' line='26' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_Realloc' filepath='./Include/internal/pycore_pymem_init.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyMem_ArenaAlloc' filepath='./Include/internal/pycore_pymem_init.h' line='52' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyMem_ArenaFree' filepath='./Include/internal/pycore_pymem_init.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_New' mangled-name='_PyThreadState_New' filepath='./Include/internal/pycore_pystate.h' line='132' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_New'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='_PyThreadState_Bind' mangled-name='_PyThreadState_Bind' filepath='./Include/internal/pycore_pystate.h' line='133' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Bind'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyInterpreterState_Enable' mangled-name='_PyInterpreterState_Enable' filepath='./Include/internal/pycore_pystate.h' line='151' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_Enable'> + <parameter type-id='type-id-178'/> + <return type-id='type-id-54'/> + </function-decl> + <var-decl name='_PyRuntime' type-id='type-id-1424' mangled-name='_PyRuntime' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='177' column='1' elf-symbol-id='_PyRuntime'/> + <function-decl name='_PyRuntimeState_Init' mangled-name='_PyRuntimeState_Init' filepath='./Include/internal/pycore_runtime.h' line='179' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRuntimeState_Init'> + <parameter type-id='type-id-178'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyRuntimeState_Fini' mangled-name='_PyRuntimeState_Fini' filepath='./Include/internal/pycore_runtime.h' line='180' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRuntimeState_Fini'> + <parameter type-id='type-id-178'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PySlice_Fini' filepath='./Include/internal/pycore_sliceobject.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PySys_ClearAuditHooks' filepath='./Include/internal/pycore_sysmodule.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PySys_SetAttr' filepath='./Include/internal/pycore_sysmodule.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_DumpTracebackThreads' mangled-name='_Py_DumpTracebackThreads' filepath='./Include/internal/pycore_traceback.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DumpTracebackThreads'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-177'/> + <return type-id='type-id-12'/> + </function-decl> + <function-decl name='_Py_DumpASCII' mangled-name='_Py_DumpASCII' filepath='./Include/internal/pycore_traceback.h' line='67' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DumpASCII'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_DumpDecimal' mangled-name='_Py_DumpDecimal' filepath='./Include/internal/pycore_traceback.h' line='72' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DumpDecimal'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_DumpHexadecimal' mangled-name='_Py_DumpHexadecimal' filepath='./Include/internal/pycore_traceback.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DumpHexadecimal'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-747'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTuple_Fini' filepath='./Include/internal/pycore_tuple.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTypes_InitTypes' filepath='./Include/internal/pycore_typeobject.h' line='76' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyTypes_FiniTypes' filepath='./Include/internal/pycore_typeobject.h' line='77' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTypes_Fini' filepath='./Include/internal/pycore_typeobject.h' line='78' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_clear_generic_types' filepath='./Include/internal/pycore_typevarobject.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_InitState' filepath='./Include/internal/pycore_unicodeobject.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_InitGlobalObjects' filepath='./Include/internal/pycore_unicodeobject.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyUnicode_InitTypes' filepath='./Include/internal/pycore_unicodeobject.h' line='21' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='_PyUnicode_Fini' filepath='./Include/internal/pycore_unicodeobject.h' line='22' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_FiniTypes' filepath='./Include/internal/pycore_unicodeobject.h' line='23' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyUnicode_ClearInterned' filepath='./Include/internal/pycore_unicodeobject.h' line='64' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyWarnings_InitState' filepath='./Include/internal/pycore_warnings.h' line='20' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyModule_IsExtension' filepath='./Include/moduleobject.h' line='109' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyGC_Collect' mangled-name='PyGC_Collect' filepath='./Include/objimpl.h' line='154' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyGC_Collect'> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='PyInterpreterState_New' mangled-name='PyInterpreterState_New' filepath='./Include/pystate.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_New'> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='PyInterpreterState_Delete' mangled-name='PyInterpreterState_Delete' filepath='./Include/pystate.h' line='16' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Delete'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThreadState_Clear' mangled-name='PyThreadState_Clear' filepath='./Include/pystate.h' line='49' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_Clear'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThreadState_Delete' mangled-name='PyThreadState_Delete' filepath='./Include/pystate.h' line='50' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_Delete'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThreadState_Swap' mangled-name='PyThreadState_Swap' filepath='./Include/pystate.h' line='65' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_Swap'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='PyOS_mystrnicmp' mangled-name='PyOS_mystrnicmp' filepath='./Include/pystrcmp.h' line='8' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_mystrnicmp'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-14'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyErr_PrintEx' mangled-name='PyErr_PrintEx' filepath='./Include/pythonrun.h' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_PrintEx'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_DisplayException' mangled-name='PyErr_DisplayException' filepath='./Include/pythonrun.h' line='17' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_DisplayException'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PySys_SetObject' mangled-name='PySys_SetObject' filepath='./Include/sysmodule.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PySys_SetObject'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyUnstable_PerfMapState_Fini' mangled-name='PyUnstable_PerfMapState_Fini' filepath='./Include/sysmodule.h' line='42' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyUnstable_PerfMapState_Fini'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTraceMalloc_Start' mangled-name='_PyTraceMalloc_Start' filepath='./Include/tracemalloc.h' line='53' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_Start'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='nl_langinfo' filepath='/usr/include/langinfo.h' line='661' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1486'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='sigemptyset' filepath='/usr/include/signal.h' line='199' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-45'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sigaction' filepath='/usr/include/signal.h' line='243' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-1494'/> + <parameter type-id='type-id-1496'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='vfprintf' filepath='/usr/include/stdio.h' line='365' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-412'/> + <parameter type-id='type-id-181'/> + <parameter type-id='type-id-306'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='abort' filepath='/usr/include/stdlib.h' line='598' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='exit' filepath='/usr/include/stdlib.h' line='624' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='setenv' filepath='/usr/include/stdlib.h' line='660' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyRuntime_Finalize' mangled-name='_PyRuntime_Finalize' filepath='Python/pylifecycle.c' line='121' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRuntime_Finalize'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_IsFinalizing' mangled-name='_Py_IsFinalizing' filepath='Python/pylifecycle.c' line='128' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_IsFinalizing'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_IsCoreInitialized' mangled-name='_Py_IsCoreInitialized' filepath='Python/pylifecycle.c' line='144' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_IsCoreInitialized'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyInterpreterState_SetConfig' mangled-name='_PyInterpreterState_SetConfig' filepath='Python/pylifecycle.c' line='414' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_SetConfig'> + <parameter type-id='type-id-260' name='src_config' filepath='Python/pylifecycle.c' line='414' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_PreInitializeFromPyArgv' mangled-name='_Py_PreInitializeFromPyArgv' filepath='Python/pylifecycle.c' line='898' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_PreInitializeFromPyArgv'> + <parameter type-id='type-id-1434' name='src_config' filepath='Python/pylifecycle.c' line='898' column='1'/> + <parameter type-id='type-id-1437' name='args' filepath='Python/pylifecycle.c' line='898' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_PreInitializeFromBytesArgs' mangled-name='Py_PreInitializeFromBytesArgs' filepath='Python/pylifecycle.c' line='945' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_PreInitializeFromBytesArgs'> + <parameter type-id='type-id-1434' name='src_config' filepath='Python/pylifecycle.c' line='945' column='1'/> + <parameter type-id='type-id-14' name='argc' filepath='Python/pylifecycle.c' line='945' column='1'/> + <parameter type-id='type-id-239' name='argv' filepath='Python/pylifecycle.c' line='945' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_PreInitializeFromArgs' mangled-name='Py_PreInitializeFromArgs' filepath='Python/pylifecycle.c' line='953' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_PreInitializeFromArgs'> + <parameter type-id='type-id-1434' name='src_config' filepath='Python/pylifecycle.c' line='953' column='1'/> + <parameter type-id='type-id-14' name='argc' filepath='Python/pylifecycle.c' line='953' column='1'/> + <parameter type-id='type-id-235' name='argv' filepath='Python/pylifecycle.c' line='953' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_PreInitialize' mangled-name='Py_PreInitialize' filepath='Python/pylifecycle.c' line='961' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_PreInitialize'> + <parameter type-id='type-id-1434' name='src_config' filepath='Python/pylifecycle.c' line='961' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_InitializeEx' mangled-name='Py_InitializeEx' filepath='Python/pylifecycle.c' line='1263' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_InitializeEx'> + <parameter type-id='type-id-8' name='install_sigs' filepath='Python/pylifecycle.c' line='1263' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_Initialize' mangled-name='Py_Initialize' filepath='Python/pylifecycle.c' line='1291' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Initialize'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_InitializeMain' mangled-name='_Py_InitializeMain' filepath='Python/pylifecycle.c' line='1298' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_InitializeMain'> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_Finalize' mangled-name='Py_Finalize' filepath='Python/pylifecycle.c' line='1973' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Finalize'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_NewInterpreterFromConfig' mangled-name='Py_NewInterpreterFromConfig' filepath='Python/pylifecycle.c' line='2098' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_NewInterpreterFromConfig'> + <parameter type-id='type-id-1487' name='tstate_p' filepath='Python/pylifecycle.c' line='2098' column='1'/> + <parameter type-id='type-id-1489' name='config' filepath='Python/pylifecycle.c' line='2099' column='1'/> + <return type-id='type-id-54'/> + </function-decl> + <function-decl name='Py_NewInterpreter' mangled-name='Py_NewInterpreter' filepath='Python/pylifecycle.c' line='2105' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_NewInterpreter'> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='Py_EndInterpreter' mangled-name='Py_EndInterpreter' filepath='Python/pylifecycle.c' line='2129' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_EndInterpreter'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/pylifecycle.c' line='2129' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_DumpExtensionModules' mangled-name='_Py_DumpExtensionModules' filepath='Python/pylifecycle.c' line='2708' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DumpExtensionModules'> + <parameter type-id='type-id-8' name='fd' filepath='Python/pylifecycle.c' line='2708' column='1'/> + <parameter type-id='type-id-20' name='interp' filepath='Python/pylifecycle.c' line='2708' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_FatalError' mangled-name='Py_FatalError' filepath='Python/pylifecycle.c' line='2881' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_FatalError'> + <parameter type-id='type-id-12' name='msg' filepath='Python/pylifecycle.c' line='2881' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_FatalRefcountErrorFunc' mangled-name='_Py_FatalRefcountErrorFunc' filepath='Python/pylifecycle.c' line='2925' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_FatalRefcountErrorFunc'> + <parameter type-id='type-id-12' name='func' filepath='Python/pylifecycle.c' line='2925' column='1'/> + <parameter type-id='type-id-12' name='msg' filepath='Python/pylifecycle.c' line='2925' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_AtExit' mangled-name='Py_AtExit' filepath='Python/pylifecycle.c' line='2975' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_AtExit'> + <parameter type-id='type-id-227' name='func' filepath='Python/pylifecycle.c' line='2975' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_Exit' mangled-name='Py_Exit' filepath='Python/pylifecycle.c' line='3001' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Exit'> + <parameter type-id='type-id-8' name='sts' filepath='Python/pylifecycle.c' line='3001' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='Py_FdIsInteractive' mangled-name='Py_FdIsInteractive' filepath='Python/pylifecycle.c' line='3018' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_FdIsInteractive'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pylifecycle.c' line='3018' column='1'/> + <parameter type-id='type-id-12' name='filename' filepath='Python/pylifecycle.c' line='3018' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_FdIsInteractive' mangled-name='_Py_FdIsInteractive' filepath='Python/pylifecycle.c' line='3033' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_FdIsInteractive'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pylifecycle.c' line='3033' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/pylifecycle.c' line='3033' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyOS_getsig' mangled-name='PyOS_getsig' filepath='Python/pylifecycle.c' line='3050' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_getsig'> + <parameter type-id='type-id-8' name='sig' filepath='Python/pylifecycle.c' line='3050' column='1'/> + <return type-id='type-id-1485'/> + </function-decl> + <function-decl name='PyOS_setsig' mangled-name='PyOS_setsig' filepath='Python/pylifecycle.c' line='3089' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_setsig'> + <parameter type-id='type-id-8' name='sig' filepath='Python/pylifecycle.c' line='3089' column='1'/> + <parameter type-id='type-id-1485' name='handler' filepath='Python/pylifecycle.c' line='3089' column='1'/> + <return type-id='type-id-1485'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pystate.c' comp-dir-path='/src' language='LANG_C11'> + <pointer-type-def type-id='type-id-821' size-in-bits='64' id='type-id-1497'/> + <pointer-type-def type-id='type-id-852' size-in-bits='64' id='type-id-1498'/> + <qualified-type-def type-id='type-id-19' const='yes' id='type-id-1499'/> + <function-decl name='_PyEval_InitState' filepath='./Include/internal/pycore_ceval.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-820'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_FiniState' filepath='./Include/internal/pycore_ceval.h' line='25' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1497'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyEval_AcquireLock' filepath='./Include/internal/pycore_ceval.h' line='102' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGC_InitState' filepath='./Include/internal/pycore_gc.h' line='193' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1498'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyImport_ClearCore' filepath='./Include/internal/pycore_import.h' line='109' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyType_InitCache' filepath='./Include/internal/pycore_object.h' line='138' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_VirtualAlloc' filepath='./Include/internal/pycore_obmalloc.h' line='677' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-19'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='_PyObject_VirtualFree' filepath='./Include/internal/pycore_obmalloc.h' line='678' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyInterpreterState_FinalizeAllocatedBlocks' filepath='./Include/internal/pycore_obmalloc.h' line='686' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyGC_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyWarnings_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='60' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyAST_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyAtExit_Fini' filepath='./Include/internal/pycore_pylifecycle.h' line='62' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <return type-id='type-id-46'/> + </function-decl> + <var-decl name='_Py_tss_tstate' type-id='type-id-177' visibility='default' filepath='./Include/internal/pycore_pystate.h' line='75' column='1'/> + <function-decl name='PyThread_get_thread_native_id' mangled-name='PyThread_get_thread_native_id' filepath='./Include/pythread.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_get_thread_native_id'> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyThread_tss_create' mangled-name='PyThread_tss_create' filepath='./Include/pythread.h' line='120' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_create'> + <parameter type-id='type-id-409'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_tss_delete' mangled-name='PyThread_tss_delete' filepath='./Include/pythread.h' line='121' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_delete'> + <parameter type-id='type-id-409'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_GetCurrent' mangled-name='_PyThreadState_GetCurrent' filepath='Python/pystate.c' line='108' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_GetCurrent'> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='PyInterpreterState_Clear' mangled-name='PyInterpreterState_Clear' filepath='Python/pystate.c' line='914' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Clear'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='914' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyInterpreterState_RequiresIDRef' mangled-name='_PyInterpreterState_RequiresIDRef' filepath='Python/pystate.c' line='1107' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_RequiresIDRef'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1107' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyInterpreterState_RequireIDRef' mangled-name='_PyInterpreterState_RequireIDRef' filepath='Python/pystate.c' line='1113' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_RequireIDRef'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1113' column='1'/> + <parameter type-id='type-id-8' name='required' filepath='Python/pystate.c' line='1113' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyInterpreterState_GetMainModule' mangled-name='_PyInterpreterState_GetMainModule' filepath='Python/pystate.c' line='1119' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetMainModule'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1119' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyInterpreterState_GetDict' mangled-name='PyInterpreterState_GetDict' filepath='Python/pystate.c' line='1130' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_GetDict'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1130' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyThreadState_New' mangled-name='PyThreadState_New' filepath='Python/pystate.c' line='1372' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_New'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1372' column='1'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='_PyThreadState_Prealloc' mangled-name='_PyThreadState_Prealloc' filepath='Python/pystate.c' line='1395' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Prealloc'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1395' column='1'/> + <return type-id='type-id-177'/> + </function-decl> + <function-decl name='_PyThreadState_Init' mangled-name='_PyThreadState_Init' filepath='Python/pystate.c' line='1403' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Init'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1403' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_DeleteCurrent' mangled-name='_PyThreadState_DeleteCurrent' filepath='Python/pystate.c' line='1565' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_DeleteCurrent'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1565' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThreadState_DeleteCurrent' mangled-name='PyThreadState_DeleteCurrent' filepath='Python/pystate.c' line='1575' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_DeleteCurrent'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyThreadState_GetDict' mangled-name='_PyThreadState_GetDict' filepath='Python/pystate.c' line='1706' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_GetDict'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1706' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyThreadState_GetInterpreter' mangled-name='PyThreadState_GetInterpreter' filepath='Python/pystate.c' line='1731' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetInterpreter'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1731' column='1'/> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='PyThreadState_GetID' mangled-name='PyThreadState_GetID' filepath='Python/pystate.c' line='1755' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetID'> + <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1755' column='1'/> + <return type-id='type-id-117'/> + </function-decl> + <function-decl name='PyThreadState_SetAsyncExc' mangled-name='PyThreadState_SetAsyncExc' filepath='Python/pystate.c' line='1809' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_SetAsyncExc'> + <parameter type-id='type-id-28' name='id' filepath='Python/pystate.c' line='1809' column='1'/> + <parameter type-id='type-id-2' name='exc' filepath='Python/pystate.c' line='1809' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyInterpreterState_Main' mangled-name='PyInterpreterState_Main' filepath='Python/pystate.c' line='1952' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Main'> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='_PyThread_CurrentFrames' mangled-name='_PyThread_CurrentFrames' filepath='Python/pystate.c' line='1983' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_CurrentFrames'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyThread_CurrentExceptions' mangled-name='_PyThread_CurrentExceptions' filepath='Python/pystate.c' line='2044' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_CurrentExceptions'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyGILState_GetInterpreterStateUnsafe' mangled-name='_PyGILState_GetInterpreterStateUnsafe' filepath='Python/pystate.c' line='2162' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyGILState_GetInterpreterStateUnsafe'> + <return type-id='type-id-20'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_Init' mangled-name='_PyCrossInterpreterData_Init' filepath='Python/pystate.c' line='2325' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Init'> + <parameter type-id='type-id-1056' name='data' filepath='Python/pystate.c' line='2325' column='1'/> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2326' column='1'/> + <parameter type-id='type-id-22' name='shared' filepath='Python/pystate.c' line='2327' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2327' column='1'/> + <parameter type-id='type-id-782' name='new_object' filepath='Python/pystate.c' line='2328' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_InitWithSize' mangled-name='_PyCrossInterpreterData_InitWithSize' filepath='Python/pystate.c' line='2347' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_InitWithSize'> + <parameter type-id='type-id-1056' name='data' filepath='Python/pystate.c' line='2347' column='1'/> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2348' column='1'/> + <parameter type-id='type-id-1499' name='size' filepath='Python/pystate.c' line='2349' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2349' column='1'/> + <parameter type-id='type-id-782' name='new_object' filepath='Python/pystate.c' line='2350' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_Clear' mangled-name='_PyCrossInterpreterData_Clear' filepath='Python/pystate.c' line='2366' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Clear'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2366' column='1'/> + <parameter type-id='type-id-1056' name='data' filepath='Python/pystate.c' line='2367' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyObject_CheckCrossInterpreterData' mangled-name='_PyObject_CheckCrossInterpreterData' filepath='Python/pystate.c' line='2412' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CheckCrossInterpreterData'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2412' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyObject_GetCrossInterpreterData' mangled-name='_PyObject_GetCrossInterpreterData' filepath='Python/pystate.c' line='2422' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetCrossInterpreterData'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2422' column='1'/> + <parameter type-id='type-id-1056' name='data' filepath='Python/pystate.c' line='2422' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_NewObject' mangled-name='_PyCrossInterpreterData_NewObject' filepath='Python/pystate.c' line='2460' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_NewObject'> + <parameter type-id='type-id-1056' name='data' filepath='Python/pystate.c' line='2460' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_Release' mangled-name='_PyCrossInterpreterData_Release' filepath='Python/pystate.c' line='2494' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Release'> + <parameter type-id='type-id-1056' name='data' filepath='Python/pystate.c' line='2494' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_RegisterClass' mangled-name='_PyCrossInterpreterData_RegisterClass' filepath='Python/pystate.c' line='2595' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_RegisterClass'> + <parameter type-id='type-id-1' name='cls' filepath='Python/pystate.c' line='2595' column='1'/> + <parameter type-id='type-id-785' name='getdata' filepath='Python/pystate.c' line='2596' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_UnregisterClass' mangled-name='_PyCrossInterpreterData_UnregisterClass' filepath='Python/pystate.c' line='2618' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_UnregisterClass'> + <parameter type-id='type-id-1' name='cls' filepath='Python/pystate.c' line='2618' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyCrossInterpreterData_Lookup' mangled-name='_PyCrossInterpreterData_Lookup' filepath='Python/pystate.c' line='2638' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Lookup'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2638' column='1'/> + <return type-id='type-id-785'/> + </function-decl> + <function-decl name='_PyInterpreterState_GetEvalFrameFunc' mangled-name='_PyInterpreterState_GetEvalFrameFunc' filepath='Python/pystate.c' line='2787' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetEvalFrameFunc'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2787' column='1'/> + <return type-id='type-id-778'/> + </function-decl> + <function-decl name='_PyInterpreterState_SetEvalFrameFunc' mangled-name='_PyInterpreterState_SetEvalFrameFunc' filepath='Python/pystate.c' line='2797' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_SetEvalFrameFunc'> + <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2797' column='1'/> + <parameter type-id='type-id-778' name='eval_frame' filepath='Python/pystate.c' line='2798' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyInterpreterState_GetConfigCopy' mangled-name='_PyInterpreterState_GetConfigCopy' filepath='Python/pystate.c' line='2817' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetConfigCopy'> + <parameter type-id='type-id-53' name='config' filepath='Python/pystate.c' line='2817' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pystrcmp.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyOS_mystricmp' mangled-name='PyOS_mystricmp' filepath='Python/pystrcmp.c' line='22' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyOS_mystricmp'> + <parameter type-id='type-id-12' name='s1' filepath='Python/pystrcmp.c' line='22' column='1'/> + <parameter type-id='type-id-12' name='s2' filepath='Python/pystrcmp.c' line='22' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pystrhex.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_Py_strhex' mangled-name='_Py_strhex' filepath='Python/pystrhex.c' line='148' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_strhex'> + <parameter type-id='type-id-12' name='argbuf' filepath='Python/pystrhex.c' line='148' column='1'/> + <parameter type-id='type-id-246' name='arglen' filepath='Python/pystrhex.c' line='148' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_strhex_bytes' mangled-name='_Py_strhex_bytes' filepath='Python/pystrhex.c' line='155' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_strhex_bytes'> + <parameter type-id='type-id-12' name='argbuf' filepath='Python/pystrhex.c' line='155' column='1'/> + <parameter type-id='type-id-246' name='arglen' filepath='Python/pystrhex.c' line='155' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_strhex_bytes_with_sep' mangled-name='_Py_strhex_bytes_with_sep' filepath='Python/pystrhex.c' line='170' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_strhex_bytes_with_sep'> + <parameter type-id='type-id-12' name='argbuf' filepath='Python/pystrhex.c' line='170' column='1'/> + <parameter type-id='type-id-246' name='arglen' filepath='Python/pystrhex.c' line='170' column='1'/> + <parameter type-id='type-id-2' name='sep' filepath='Python/pystrhex.c' line='171' column='1'/> + <parameter type-id='type-id-261' name='bytes_per_group' filepath='Python/pystrhex.c' line='171' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pythonrun.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='PyAST_mod2obj' filepath='./Include/internal/pycore_ast.h' line='905' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-468'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyImport_GetImportlibExternalLoader' filepath='./Include/internal/pycore_import.h' line='132' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-12'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyParser_ASTFromString' filepath='./Include/internal/pycore_parser.h' line='44' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-467'/> + </function-decl> + <function-decl name='_PyParser_ASTFromFile' filepath='./Include/internal/pycore_parser.h' line='51' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-208'/> + <parameter type-id='type-id-179'/> + <parameter type-id='type-id-563'/> + <return type-id='type-id-467'/> + </function-decl> + <function-decl name='_Py_Offer_Suggestions' filepath='./Include/internal/pycore_pyerrors.h' line='108' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTraceBack_Print_Indented' mangled-name='_PyTraceBack_Print_Indented' filepath='./Include/internal/pycore_traceback.h' line='92' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceBack_Print_Indented'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_WriteIndentedMargin' mangled-name='_Py_WriteIndentedMargin' filepath='./Include/internal/pycore_traceback.h' line='95' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_WriteIndentedMargin'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-12'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_WriteIndent' mangled-name='_Py_WriteIndent' filepath='./Include/internal/pycore_traceback.h' line='96' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_WriteIndent'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='rewind' filepath='/usr/include/stdio.h' line='723' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-229'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyRun_AnyFileObject' mangled-name='_PyRun_AnyFileObject' filepath='Python/pythonrun.c' line='57' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRun_AnyFileObject'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='57' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/pythonrun.c' line='57' column='1'/> + <parameter type-id='type-id-8' name='closeit' filepath='Python/pythonrun.c' line='57' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='58' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyRun_InteractiveLoopObject' mangled-name='_PyRun_InteractiveLoopObject' filepath='Python/pythonrun.c' line='111' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRun_InteractiveLoopObject'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='111' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/pythonrun.c' line='111' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='111' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_InteractiveLoopFlags' mangled-name='PyRun_InteractiveLoopFlags' filepath='Python/pythonrun.c' line='167' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_InteractiveLoopFlags'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='167' column='1'/> + <parameter type-id='type-id-12' name='filename' filepath='Python/pythonrun.c' line='167' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='167' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_InteractiveOneObject' mangled-name='PyRun_InteractiveOneObject' filepath='Python/pythonrun.c' line='271' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_InteractiveOneObject'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='271' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/pythonrun.c' line='271' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='271' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_InteractiveOneFlags' mangled-name='PyRun_InteractiveOneFlags' filepath='Python/pythonrun.c' line='284' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_InteractiveOneFlags'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='284' column='1'/> + <parameter type-id='type-id-12' name='filename_str' filepath='Python/pythonrun.c' line='284' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='284' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyRun_SimpleFileObject' mangled-name='_PyRun_SimpleFileObject' filepath='Python/pythonrun.c' line='376' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyRun_SimpleFileObject'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='376' column='1'/> + <parameter type-id='type-id-2' name='filename' filepath='Python/pythonrun.c' line='376' column='1'/> + <parameter type-id='type-id-8' name='closeit' filepath='Python/pythonrun.c' line='376' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='377' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_SimpleFileExFlags' mangled-name='PyRun_SimpleFileExFlags' filepath='Python/pythonrun.c' line='459' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_SimpleFileExFlags'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='459' column='1'/> + <parameter type-id='type-id-12' name='filename' filepath='Python/pythonrun.c' line='459' column='1'/> + <parameter type-id='type-id-8' name='closeit' filepath='Python/pythonrun.c' line='459' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='460' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_SimpleStringFlags' mangled-name='PyRun_SimpleStringFlags' filepath='Python/pythonrun.c' line='473' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_SimpleStringFlags'> + <parameter type-id='type-id-12' name='command' filepath='Python/pythonrun.c' line='473' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='473' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_Py_HandleSystemExit' mangled-name='_Py_HandleSystemExit' filepath='Python/pythonrun.c' line='688' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_HandleSystemExit'> + <parameter type-id='type-id-179' name='exitcode_p' filepath='Python/pythonrun.c' line='688' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyErr_Display' mangled-name='_PyErr_Display' filepath='Python/pythonrun.c' line='1498' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_Display'> + <parameter type-id='type-id-2' name='file' filepath='Python/pythonrun.c' line='1498' column='1'/> + <parameter type-id='type-id-2' name='unused' filepath='Python/pythonrun.c' line='1498' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Python/pythonrun.c' line='1498' column='1'/> + <parameter type-id='type-id-2' name='tb' filepath='Python/pythonrun.c' line='1498' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyErr_Display' mangled-name='PyErr_Display' filepath='Python/pythonrun.c' line='1547' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyErr_Display'> + <parameter type-id='type-id-2' name='unused' filepath='Python/pythonrun.c' line='1547' column='1'/> + <parameter type-id='type-id-2' name='value' filepath='Python/pythonrun.c' line='1547' column='1'/> + <parameter type-id='type-id-2' name='tb' filepath='Python/pythonrun.c' line='1547' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyErr_DisplayException' mangled-name='_PyErr_DisplayException' filepath='Python/pythonrun.c' line='1564' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyErr_DisplayException'> + <parameter type-id='type-id-2' name='file' filepath='Python/pythonrun.c' line='1564' column='1'/> + <parameter type-id='type-id-2' name='exc' filepath='Python/pythonrun.c' line='1564' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyRun_FileExFlags' mangled-name='PyRun_FileExFlags' filepath='Python/pythonrun.c' line='1628' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_FileExFlags'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1628' column='1'/> + <parameter type-id='type-id-12' name='filename' filepath='Python/pythonrun.c' line='1628' column='1'/> + <parameter type-id='type-id-8' name='start' filepath='Python/pythonrun.c' line='1628' column='1'/> + <parameter type-id='type-id-2' name='globals' filepath='Python/pythonrun.c' line='1628' column='1'/> + <parameter type-id='type-id-2' name='locals' filepath='Python/pythonrun.c' line='1629' column='1'/> + <parameter type-id='type-id-8' name='closeit' filepath='Python/pythonrun.c' line='1629' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='1629' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_CompileStringExFlags' mangled-name='Py_CompileStringExFlags' filepath='Python/pythonrun.c' line='1790' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_CompileStringExFlags'> + <parameter type-id='type-id-12' name='str' filepath='Python/pythonrun.c' line='1790' column='1'/> + <parameter type-id='type-id-12' name='filename_str' filepath='Python/pythonrun.c' line='1790' column='1'/> + <parameter type-id='type-id-8' name='start' filepath='Python/pythonrun.c' line='1790' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='1791' column='1'/> + <parameter type-id='type-id-8' name='optimize' filepath='Python/pythonrun.c' line='1791' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyRun_AnyFile' mangled-name='PyRun_AnyFile' filepath='Python/pythonrun.c' line='1892' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_AnyFile'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1892' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Python/pythonrun.c' line='1892' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_AnyFileEx' mangled-name='PyRun_AnyFileEx' filepath='Python/pythonrun.c' line='1899' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_AnyFileEx'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1899' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Python/pythonrun.c' line='1899' column='1'/> + <parameter type-id='type-id-8' name='closeit' filepath='Python/pythonrun.c' line='1899' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_AnyFileFlags' mangled-name='PyRun_AnyFileFlags' filepath='Python/pythonrun.c' line='1906' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_AnyFileFlags'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1906' column='1'/> + <parameter type-id='type-id-12' name='name' filepath='Python/pythonrun.c' line='1906' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='1906' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_File' mangled-name='PyRun_File' filepath='Python/pythonrun.c' line='1913' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_File'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1913' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1913' column='1'/> + <parameter type-id='type-id-8' name='s' filepath='Python/pythonrun.c' line='1913' column='1'/> + <parameter type-id='type-id-2' name='g' filepath='Python/pythonrun.c' line='1913' column='1'/> + <parameter type-id='type-id-2' name='l' filepath='Python/pythonrun.c' line='1913' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyRun_FileEx' mangled-name='PyRun_FileEx' filepath='Python/pythonrun.c' line='1920' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_FileEx'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1920' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1920' column='1'/> + <parameter type-id='type-id-8' name='s' filepath='Python/pythonrun.c' line='1920' column='1'/> + <parameter type-id='type-id-2' name='g' filepath='Python/pythonrun.c' line='1920' column='1'/> + <parameter type-id='type-id-2' name='l' filepath='Python/pythonrun.c' line='1920' column='1'/> + <parameter type-id='type-id-8' name='c' filepath='Python/pythonrun.c' line='1920' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyRun_FileFlags' mangled-name='PyRun_FileFlags' filepath='Python/pythonrun.c' line='1927' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_FileFlags'> + <parameter type-id='type-id-229' name='fp' filepath='Python/pythonrun.c' line='1927' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1927' column='1'/> + <parameter type-id='type-id-8' name='s' filepath='Python/pythonrun.c' line='1927' column='1'/> + <parameter type-id='type-id-2' name='g' filepath='Python/pythonrun.c' line='1927' column='1'/> + <parameter type-id='type-id-2' name='l' filepath='Python/pythonrun.c' line='1927' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='1928' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyRun_SimpleFile' mangled-name='PyRun_SimpleFile' filepath='Python/pythonrun.c' line='1935' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_SimpleFile'> + <parameter type-id='type-id-229' name='f' filepath='Python/pythonrun.c' line='1935' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1935' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_SimpleFileEx' mangled-name='PyRun_SimpleFileEx' filepath='Python/pythonrun.c' line='1942' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_SimpleFileEx'> + <parameter type-id='type-id-229' name='f' filepath='Python/pythonrun.c' line='1942' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1942' column='1'/> + <parameter type-id='type-id-8' name='c' filepath='Python/pythonrun.c' line='1942' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_String' mangled-name='PyRun_String' filepath='Python/pythonrun.c' line='1950' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_String'> + <parameter type-id='type-id-12' name='str' filepath='Python/pythonrun.c' line='1950' column='1'/> + <parameter type-id='type-id-8' name='s' filepath='Python/pythonrun.c' line='1950' column='1'/> + <parameter type-id='type-id-2' name='g' filepath='Python/pythonrun.c' line='1950' column='1'/> + <parameter type-id='type-id-2' name='l' filepath='Python/pythonrun.c' line='1950' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyRun_SimpleString' mangled-name='PyRun_SimpleString' filepath='Python/pythonrun.c' line='1957' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_SimpleString'> + <parameter type-id='type-id-12' name='s' filepath='Python/pythonrun.c' line='1957' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='Py_CompileString' mangled-name='Py_CompileString' filepath='Python/pythonrun.c' line='1964' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_CompileString'> + <parameter type-id='type-id-12' name='str' filepath='Python/pythonrun.c' line='1964' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1964' column='1'/> + <parameter type-id='type-id-8' name='s' filepath='Python/pythonrun.c' line='1964' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='Py_CompileStringFlags' mangled-name='Py_CompileStringFlags' filepath='Python/pythonrun.c' line='1971' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_CompileStringFlags'> + <parameter type-id='type-id-12' name='str' filepath='Python/pythonrun.c' line='1971' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1971' column='1'/> + <parameter type-id='type-id-8' name='s' filepath='Python/pythonrun.c' line='1971' column='1'/> + <parameter type-id='type-id-208' name='flags' filepath='Python/pythonrun.c' line='1972' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='PyRun_InteractiveOne' mangled-name='PyRun_InteractiveOne' filepath='Python/pythonrun.c' line='1979' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_InteractiveOne'> + <parameter type-id='type-id-229' name='f' filepath='Python/pythonrun.c' line='1979' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1979' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyRun_InteractiveLoop' mangled-name='PyRun_InteractiveLoop' filepath='Python/pythonrun.c' line='1986' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyRun_InteractiveLoop'> + <parameter type-id='type-id-229' name='f' filepath='Python/pythonrun.c' line='1986' column='1'/> + <parameter type-id='type-id-12' name='p' filepath='Python/pythonrun.c' line='1986' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/pytime.c' comp-dir-path='/src' language='LANG_C11'> + <class-decl name='_Py_clock_info_t' size-in-bits='192' is-struct='yes' naming-typedef-id='type-id-1500' visibility='default' filepath='./Include/cpython/pytime.h' line='240' column='1' id='type-id-1501'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='implementation' type-id='type-id-12' visibility='default' filepath='./Include/cpython/pytime.h' line='241' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='monotonic' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pytime.h' line='242' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='adjustable' type-id='type-id-8' visibility='default' filepath='./Include/cpython/pytime.h' line='243' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='resolution' type-id='type-id-251' visibility='default' filepath='./Include/cpython/pytime.h' line='244' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='_Py_clock_info_t' type-id='type-id-1501' filepath='./Include/cpython/pytime.h' line='245' column='1' id='type-id-1500'/> + <typedef-decl name='__suseconds_t' type-id='type-id-47' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='162' column='1' id='type-id-1502'/> + <typedef-decl name='__clockid_t' type-id='type-id-8' filepath='/usr/include/x86_64-linux-gnu/bits/types.h' line='169' column='1' id='type-id-212'/> + <typedef-decl name='clockid_t' type-id='type-id-212' filepath='/usr/include/x86_64-linux-gnu/bits/types/clockid_t.h' line='7' column='1' id='type-id-221'/> + <class-decl name='timeval' size-in-bits='128' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h' line='8' column='1' id='type-id-101'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tv_sec' type-id='type-id-1340' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='tv_usec' type-id='type-id-1502' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h' line='15' column='1'/> + </data-member> + </class-decl> + <class-decl name='tm' size-in-bits='448' is-struct='yes' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='7' column='1' id='type-id-214'> + <data-member access='public' layout-offset-in-bits='0'> + <var-decl name='tm_sec' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='9' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='32'> + <var-decl name='tm_min' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='10' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='64'> + <var-decl name='tm_hour' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='11' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='96'> + <var-decl name='tm_mday' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='12' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='128'> + <var-decl name='tm_mon' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='13' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='160'> + <var-decl name='tm_year' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='14' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='192'> + <var-decl name='tm_wday' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='15' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='224'> + <var-decl name='tm_yday' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='16' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='256'> + <var-decl name='tm_isdst' type-id='type-id-8' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='17' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='320'> + <var-decl name='tm_gmtoff' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='20' column='1'/> + </data-member> + <data-member access='public' layout-offset-in-bits='384'> + <var-decl name='tm_zone' type-id='type-id-12' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/types/struct_tm.h' line='21' column='1'/> + </data-member> + </class-decl> + <typedef-decl name='time_t' type-id='type-id-1340' filepath='/usr/include/x86_64-linux-gnu/bits/types/time_t.h' line='10' column='1' id='type-id-219'/> + <pointer-type-def type-id='type-id-788' size-in-bits='64' id='type-id-1503'/> + <pointer-type-def type-id='type-id-1500' size-in-bits='64' id='type-id-1504'/> + <qualified-type-def type-id='type-id-219' const='yes' id='type-id-1505'/> + <pointer-type-def type-id='type-id-1505' size-in-bits='64' id='type-id-1506'/> + <qualified-type-def type-id='type-id-1506' restrict='yes' id='type-id-1507'/> + <pointer-type-def type-id='type-id-47' size-in-bits='64' id='type-id-1508'/> + <pointer-type-def type-id='type-id-219' size-in-bits='64' id='type-id-218'/> + <pointer-type-def type-id='type-id-101' size-in-bits='64' id='type-id-1509'/> + <pointer-type-def type-id='type-id-214' size-in-bits='64' id='type-id-220'/> + <qualified-type-def type-id='type-id-220' restrict='yes' id='type-id-1510'/> + <function-decl name='gmtime_r' filepath='/usr/include/time.h' line='154' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1507'/> + <parameter type-id='type-id-1510'/> + <return type-id='type-id-220'/> + </function-decl> + <function-decl name='localtime_r' filepath='/usr/include/time.h' line='159' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1507'/> + <parameter type-id='type-id-1510'/> + <return type-id='type-id-220'/> + </function-decl> + <function-decl name='clock_getres' filepath='/usr/include/time.h' line='276' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-221'/> + <parameter type-id='type-id-180'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='clock_gettime' filepath='/usr/include/time.h' line='279' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-221'/> + <parameter type-id='type-id-180'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_Add' mangled-name='_PyTime_Add' filepath='Python/pytime.c' line='104' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_Add'> + <parameter type-id='type-id-788' name='t1' filepath='Python/pytime.c' line='104' column='1'/> + <parameter type-id='type-id-788' name='t2' filepath='Python/pytime.c' line='104' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_MulDiv' mangled-name='_PyTime_MulDiv' filepath='Python/pytime.c' line='152' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_MulDiv'> + <parameter type-id='type-id-788' name='ticks' filepath='Python/pytime.c' line='152' column='1'/> + <parameter type-id='type-id-788' name='mul' filepath='Python/pytime.c' line='152' column='1'/> + <parameter type-id='type-id-788' name='div' filepath='Python/pytime.c' line='152' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyLong_AsTime_t' mangled-name='_PyLong_AsTime_t' filepath='Python/pytime.c' line='169' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_AsTime_t'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='169' column='1'/> + <return type-id='type-id-219'/> + </function-decl> + <function-decl name='_PyLong_FromTime_t' mangled-name='_PyLong_FromTime_t' filepath='Python/pytime.c' line='189' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyLong_FromTime_t'> + <parameter type-id='type-id-219' name='t' filepath='Python/pytime.c' line='189' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTime_ObjectToTime_t' mangled-name='_PyTime_ObjectToTime_t' filepath='Python/pytime.c' line='357' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_ObjectToTime_t'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='357' column='1'/> + <parameter type-id='type-id-218' name='sec' filepath='Python/pytime.c' line='357' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='357' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_ObjectToTimespec' mangled-name='_PyTime_ObjectToTimespec' filepath='Python/pytime.c' line='392' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_ObjectToTimespec'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='392' column='1'/> + <parameter type-id='type-id-218' name='sec' filepath='Python/pytime.c' line='392' column='1'/> + <parameter type-id='type-id-1508' name='nsec' filepath='Python/pytime.c' line='392' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='393' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_ObjectToTimeval' mangled-name='_PyTime_ObjectToTimeval' filepath='Python/pytime.c' line='400' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_ObjectToTimeval'> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='400' column='1'/> + <parameter type-id='type-id-218' name='sec' filepath='Python/pytime.c' line='400' column='1'/> + <parameter type-id='type-id-1508' name='usec' filepath='Python/pytime.c' line='400' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='401' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_FromSeconds' mangled-name='_PyTime_FromSeconds' filepath='Python/pytime.c' line='408' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromSeconds'> + <parameter type-id='type-id-8' name='seconds' filepath='Python/pytime.c' line='408' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_FromNanoseconds' mangled-name='_PyTime_FromNanoseconds' filepath='Python/pytime.c' line='425' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromNanoseconds'> + <parameter type-id='type-id-788' name='ns' filepath='Python/pytime.c' line='425' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_FromMicrosecondsClamp' mangled-name='_PyTime_FromMicrosecondsClamp' filepath='Python/pytime.c' line='432' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromMicrosecondsClamp'> + <parameter type-id='type-id-788' name='us' filepath='Python/pytime.c' line='432' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_FromNanosecondsObject' mangled-name='_PyTime_FromNanosecondsObject' filepath='Python/pytime.c' line='440' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromNanosecondsObject'> + <parameter type-id='type-id-1503' name='tp' filepath='Python/pytime.c' line='440' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='440' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_FromTimespec' mangled-name='_PyTime_FromTimespec' filepath='Python/pytime.c' line='490' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromTimespec'> + <parameter type-id='type-id-1503' name='tp' filepath='Python/pytime.c' line='490' column='1'/> + <parameter type-id='type-id-180' name='ts' filepath='Python/pytime.c' line='490' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_FromTimeval' mangled-name='_PyTime_FromTimeval' filepath='Python/pytime.c' line='521' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromTimeval'> + <parameter type-id='type-id-1503' name='tp' filepath='Python/pytime.c' line='521' column='1'/> + <parameter type-id='type-id-1509' name='tv' filepath='Python/pytime.c' line='521' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_FromSecondsObject' mangled-name='_PyTime_FromSecondsObject' filepath='Python/pytime.c' line='589' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromSecondsObject'> + <parameter type-id='type-id-1503' name='tp' filepath='Python/pytime.c' line='589' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='589' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='589' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_FromMillisecondsObject' mangled-name='_PyTime_FromMillisecondsObject' filepath='Python/pytime.c' line='596' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_FromMillisecondsObject'> + <parameter type-id='type-id-1503' name='tp' filepath='Python/pytime.c' line='596' column='1'/> + <parameter type-id='type-id-2' name='obj' filepath='Python/pytime.c' line='596' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='596' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_AsSecondsDouble' mangled-name='_PyTime_AsSecondsDouble' filepath='Python/pytime.c' line='603' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsSecondsDouble'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='603' column='1'/> + <return type-id='type-id-251'/> + </function-decl> + <function-decl name='_PyTime_AsNanosecondsObject' mangled-name='_PyTime_AsNanosecondsObject' filepath='Python/pytime.c' line='624' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsNanosecondsObject'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='624' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTime_AsNanoseconds' mangled-name='_PyTime_AsNanoseconds' filepath='Python/pytime.c' line='729' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsNanoseconds'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='729' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_AsMilliseconds' mangled-name='_PyTime_AsMilliseconds' filepath='Python/pytime.c' line='754' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsMilliseconds'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='754' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='754' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_AsTimeval' mangled-name='_PyTime_AsTimeval' filepath='Python/pytime.c' line='804' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsTimeval'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='804' column='1'/> + <parameter type-id='type-id-1509' name='tv' filepath='Python/pytime.c' line='804' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='804' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_AsTimeval_clamp' mangled-name='_PyTime_AsTimeval_clamp' filepath='Python/pytime.c' line='811' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsTimeval_clamp'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='811' column='1'/> + <parameter type-id='type-id-1509' name='tv' filepath='Python/pytime.c' line='811' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='811' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTime_AsTimevalTime_t' mangled-name='_PyTime_AsTimevalTime_t' filepath='Python/pytime.c' line='818' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsTimevalTime_t'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='818' column='1'/> + <parameter type-id='type-id-218' name='p_secs' filepath='Python/pytime.c' line='818' column='1'/> + <parameter type-id='type-id-179' name='us' filepath='Python/pytime.c' line='818' column='1'/> + <parameter type-id='type-id-1422' name='round' filepath='Python/pytime.c' line='819' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_AsTimespec_clamp' mangled-name='_PyTime_AsTimespec_clamp' filepath='Python/pytime.c' line='857' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsTimespec_clamp'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='857' column='1'/> + <parameter type-id='type-id-180' name='ts' filepath='Python/pytime.c' line='857' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTime_AsTimespec' mangled-name='_PyTime_AsTimespec' filepath='Python/pytime.c' line='863' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_AsTimespec'> + <parameter type-id='type-id-788' name='t' filepath='Python/pytime.c' line='863' column='1'/> + <parameter type-id='type-id-180' name='ts' filepath='Python/pytime.c' line='863' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_GetSystemClock' mangled-name='_PyTime_GetSystemClock' filepath='Python/pytime.c' line='982' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_GetSystemClock'> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_GetSystemClockWithInfo' mangled-name='_PyTime_GetSystemClockWithInfo' filepath='Python/pytime.c' line='995' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_GetSystemClockWithInfo'> + <parameter type-id='type-id-1503' name='t' filepath='Python/pytime.c' line='995' column='1'/> + <parameter type-id='type-id-1504' name='info' filepath='Python/pytime.c' line='995' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_GetMonotonicClock' mangled-name='_PyTime_GetMonotonicClock' filepath='Python/pytime.c' line='1179' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_GetMonotonicClock'> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyTime_GetMonotonicClockWithInfo' mangled-name='_PyTime_GetMonotonicClockWithInfo' filepath='Python/pytime.c' line='1192' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_GetMonotonicClockWithInfo'> + <parameter type-id='type-id-1503' name='tp' filepath='Python/pytime.c' line='1192' column='1'/> + <parameter type-id='type-id-1504' name='info' filepath='Python/pytime.c' line='1192' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_GetPerfCounterWithInfo' mangled-name='_PyTime_GetPerfCounterWithInfo' filepath='Python/pytime.c' line='1273' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_GetPerfCounterWithInfo'> + <parameter type-id='type-id-1503' name='t' filepath='Python/pytime.c' line='1273' column='1'/> + <parameter type-id='type-id-1504' name='info' filepath='Python/pytime.c' line='1273' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_localtime' mangled-name='_PyTime_localtime' filepath='Python/pytime.c' line='1303' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_localtime'> + <parameter type-id='type-id-219' name='t' filepath='Python/pytime.c' line='1303' column='1'/> + <parameter type-id='type-id-220' name='tm' filepath='Python/pytime.c' line='1303' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTime_gmtime' mangled-name='_PyTime_gmtime' filepath='Python/pytime.c' line='1342' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTime_gmtime'> + <parameter type-id='type-id-219' name='t' filepath='Python/pytime.c' line='1342' column='1'/> + <parameter type-id='type-id-220' name='tm' filepath='Python/pytime.c' line='1342' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyDeadline_Init' mangled-name='_PyDeadline_Init' filepath='Python/pytime.c' line='1370' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDeadline_Init'> + <parameter type-id='type-id-788' name='timeout' filepath='Python/pytime.c' line='1370' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + <function-decl name='_PyDeadline_Get' mangled-name='_PyDeadline_Get' filepath='Python/pytime.c' line='1378' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyDeadline_Get'> + <parameter type-id='type-id-788' name='deadline' filepath='Python/pytime.c' line='1378' column='1'/> + <return type-id='type-id-788'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/specialize.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyDictKeys_GetVersionForCurrentState' filepath='./Include/internal/pycore_dict.h' line='40' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-20'/> + <parameter type-id='type-id-346'/> + <return type-id='type-id-352'/> + </function-decl> + <function-decl name='_PyDict_LookupIndex' filepath='./Include/internal/pycore_dict.h' line='50' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-340'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyDictKeys_StringLookup' filepath='./Include/internal/pycore_dict.h' line='51' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-346'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-14'/> + </function-decl> + <function-decl name='_PyFunction_GetVersionForCurrentState' filepath='./Include/internal/pycore_function.h' line='19' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-310'/> + <return type-id='type-id-352'/> + </function-decl> + <function-decl name='_Py_slot_tp_getattro' filepath='./Include/internal/pycore_typeobject.h' line='138' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_slot_tp_getattr_hook' filepath='./Include/internal/pycore_typeobject.h' line='139' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-2'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/suggestions.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyCode_GetVarnames' filepath='./Include/internal/pycore_code.h' line='206' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-328'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_Py_UTF8_Edit_Cost' mangled-name='_Py_UTF8_Edit_Cost' filepath='Python/suggestions.c' line='392' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_UTF8_Edit_Cost'> + <parameter type-id='type-id-2' name='a' filepath='Python/suggestions.c' line='392' column='1'/> + <parameter type-id='type-id-2' name='b' filepath='Python/suggestions.c' line='392' column='1'/> + <parameter type-id='type-id-14' name='max_cost' filepath='Python/suggestions.c' line='392' column='1'/> + <return type-id='type-id-14'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/symtable.c' comp-dir-path='/src' language='LANG_C11'> + <var-decl name='PySTEntry_Type' type-id='type-id-256' visibility='default' filepath='./Include/internal/pycore_symtable.h' line='92' column='1'/> + </abi-instr> + <abi-instr address-size='64' path='Python/thread.c' comp-dir-path='/src' language='LANG_C11'> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='256' id='type-id-1511'> + <subrange length='32' type-id='type-id-28' id='type-id-60'/> + </array-type-def> + <array-type-def dimensions='1' type-id='type-id-48' size-in-bits='448' id='type-id-1512'> + <subrange length='56' type-id='type-id-28' id='type-id-1513'/> + </array-type-def> + <enum-decl name='PyLockStatus' filepath='./Include/pythread.h' line='12' column='1' id='type-id-1514'> + <underlying-type type-id='type-id-24'/> + <enumerator name='PY_LOCK_FAILURE' value='0'/> + <enumerator name='PY_LOCK_ACQUIRED' value='1'/> + <enumerator name='PY_LOCK_INTR' value='2'/> + </enum-decl> + <typedef-decl name='PyLockStatus' type-id='type-id-1514' filepath='./Include/pythread.h' line='16' column='1' id='type-id-1515'/> + <typedef-decl name='pthread_t' type-id='type-id-28' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='27' column='1' id='type-id-207'/> + <union-decl name='pthread_attr_t' size-in-bits='448' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='56' column='1' id='type-id-1516'> + <data-member access='public'> + <var-decl name='__size' type-id='type-id-1512' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='58' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__align' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='59' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='pthread_attr_t' type-id='type-id-1516' filepath='/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h' line='62' column='1' id='type-id-1517'/> + <union-decl name='sem_t' size-in-bits='256' naming-typedef-id='type-id-1518' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/semaphore.h' line='35' column='1' id='type-id-1519'> + <data-member access='public'> + <var-decl name='__size' type-id='type-id-1511' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/semaphore.h' line='37' column='1'/> + </data-member> + <data-member access='public'> + <var-decl name='__align' type-id='type-id-47' visibility='default' filepath='/usr/include/x86_64-linux-gnu/bits/semaphore.h' line='38' column='1'/> + </data-member> + </union-decl> + <typedef-decl name='sem_t' type-id='type-id-1519' filepath='/usr/include/x86_64-linux-gnu/bits/semaphore.h' line='39' column='1' id='type-id-1518'/> + <qualified-type-def type-id='type-id-1517' const='yes' id='type-id-1520'/> + <pointer-type-def type-id='type-id-1520' size-in-bits='64' id='type-id-1521'/> + <qualified-type-def type-id='type-id-1521' restrict='yes' id='type-id-1522'/> + <qualified-type-def type-id='type-id-973' const='yes' id='type-id-1523'/> + <pointer-type-def type-id='type-id-1523' size-in-bits='64' id='type-id-1524'/> + <qualified-type-def type-id='type-id-1524' restrict='yes' id='type-id-1525'/> + <pointer-type-def type-id='type-id-1517' size-in-bits='64' id='type-id-1526'/> + <pointer-type-def type-id='type-id-787' size-in-bits='64' id='type-id-1527'/> + <pointer-type-def type-id='type-id-207' size-in-bits='64' id='type-id-1528'/> + <qualified-type-def type-id='type-id-1528' restrict='yes' id='type-id-1529'/> + <pointer-type-def type-id='type-id-1518' size-in-bits='64' id='type-id-1530'/> + <qualified-type-def type-id='type-id-1530' restrict='yes' id='type-id-1531'/> + <pointer-type-def type-id='type-id-1532' size-in-bits='64' id='type-id-1533'/> + <function-decl name='pthread_create' filepath='/usr/include/pthread.h' line='202' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1529'/> + <parameter type-id='type-id-1522'/> + <parameter type-id='type-id-1533'/> + <parameter type-id='type-id-226'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_exit' filepath='/usr/include/pthread.h' line='211' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='pthread_detach' filepath='/usr/include/pthread.h' line='269' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-207'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_self' filepath='/usr/include/pthread.h' line='273' column='1' visibility='default' binding='global' size-in-bits='64'> + <return type-id='type-id-207'/> + </function-decl> + <function-decl name='pthread_attr_init' filepath='/usr/include/pthread.h' line='285' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1526'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_attr_destroy' filepath='/usr/include/pthread.h' line='288' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1526'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_attr_setscope' filepath='/usr/include/pthread.h' line='349' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1526'/> + <parameter type-id='type-id-8'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_attr_setstacksize' filepath='/usr/include/pthread.h' line='373' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1526'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_cond_init' filepath='/usr/include/pthread.h' line='1112' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1347'/> + <parameter type-id='type-id-1525'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_condattr_init' filepath='/usr/include/pthread.h' line='1194' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-972'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_condattr_setclock' filepath='/usr/include/pthread.h' line='1219' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-972'/> + <parameter type-id='type-id-212'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_key_create' filepath='/usr/include/pthread.h' line='1297' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1527'/> + <parameter type-id='type-id-758'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_key_delete' filepath='/usr/include/pthread.h' line='1302' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-787'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='pthread_getspecific' filepath='/usr/include/pthread.h' line='1305' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-787'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='pthread_setspecific' filepath='/usr/include/pthread.h' line='1308' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-787'/> + <parameter type-id='type-id-22'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sem_init' filepath='/usr/include/semaphore.h' line='35' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1530'/> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-95'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sem_destroy' filepath='/usr/include/semaphore.h' line='39' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1530'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sem_wait' filepath='/usr/include/semaphore.h' line='55' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1530'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sem_clockwait' filepath='/usr/include/semaphore.h' line='81' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1531'/> + <parameter type-id='type-id-221'/> + <parameter type-id='type-id-206'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sem_trywait' filepath='/usr/include/semaphore.h' line='100' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1530'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='sem_post' filepath='/usr/include/semaphore.h' line='103' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-1530'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='perror' filepath='/usr/include/stdio.h' line='804' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-12'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='confstr' filepath='/usr/include/unistd.h' line='644' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-15'/> + <parameter type-id='type-id-19'/> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='syscall' filepath='/usr/include/unistd.h' line='1091' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-47'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='__sysconf' filepath='/usr/include/x86_64-linux-gnu/bits/pthread_stack_min-dynamic.h' line='24' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <return type-id='type-id-47'/> + </function-decl> + <function-decl name='PyThread_get_stacksize' mangled-name='PyThread_get_stacksize' filepath='Python/thread.c' line='54' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_get_stacksize'> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='PyThread_set_stacksize' mangled-name='PyThread_set_stacksize' filepath='Python/thread.c' line='65' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_set_stacksize'> + <parameter type-id='type-id-19' name='size' filepath='Python/thread.c' line='65' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_tss_alloc' mangled-name='PyThread_tss_alloc' filepath='Python/thread.c' line='81' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_alloc'> + <return type-id='type-id-409'/> + </function-decl> + <function-decl name='PyThread_tss_free' mangled-name='PyThread_tss_free' filepath='Python/thread.c' line='92' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_tss_free'> + <parameter type-id='type-id-409' name='key' filepath='Python/thread.c' line='92' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThread_start_new_thread' mangled-name='PyThread_start_new_thread' filepath='Python/thread_pthread.h' line='238' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_start_new_thread'> + <parameter type-id='type-id-758' name='func' filepath='Python/thread_pthread.h' line='238' column='1'/> + <parameter type-id='type-id-22' name='arg' filepath='Python/thread_pthread.h' line='238' column='1'/> + <return type-id='type-id-28'/> + </function-decl> + <function-decl name='PyThread_acquire_lock_timed' mangled-name='PyThread_acquire_lock_timed' filepath='Python/thread_pthread.h' line='422' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_acquire_lock_timed'> + <parameter type-id='type-id-820' name='lock' filepath='Python/thread_pthread.h' line='422' column='1'/> + <parameter type-id='type-id-378' name='microseconds' filepath='Python/thread_pthread.h' line='422' column='1'/> + <parameter type-id='type-id-8' name='intr_flag' filepath='Python/thread_pthread.h' line='423' column='1'/> + <return type-id='type-id-1515'/> + </function-decl> + <function-decl name='PyThread_create_key' mangled-name='PyThread_create_key' filepath='Python/thread_pthread.h' line='801' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_create_key'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_delete_key' mangled-name='PyThread_delete_key' filepath='Python/thread_pthread.h' line='821' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_delete_key'> + <parameter type-id='type-id-8' name='key' filepath='Python/thread_pthread.h' line='821' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThread_delete_key_value' mangled-name='PyThread_delete_key_value' filepath='Python/thread_pthread.h' line='829' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_delete_key_value'> + <parameter type-id='type-id-8' name='key' filepath='Python/thread_pthread.h' line='829' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyThread_set_key_value' mangled-name='PyThread_set_key_value' filepath='Python/thread_pthread.h' line='837' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_set_key_value'> + <parameter type-id='type-id-8' name='key' filepath='Python/thread_pthread.h' line='837' column='1'/> + <parameter type-id='type-id-22' name='value' filepath='Python/thread_pthread.h' line='837' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyThread_get_key_value' mangled-name='PyThread_get_key_value' filepath='Python/thread_pthread.h' line='848' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_get_key_value'> + <parameter type-id='type-id-8' name='key' filepath='Python/thread_pthread.h' line='848' column='1'/> + <return type-id='type-id-22'/> + </function-decl> + <function-decl name='PyThread_ReInitTLS' mangled-name='PyThread_ReInitTLS' filepath='Python/thread_pthread.h' line='859' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_ReInitTLS'> + <return type-id='type-id-46'/> + </function-decl> + <function-type size-in-bits='64' id='type-id-1532'> + <parameter type-id='type-id-22'/> + <return type-id='type-id-22'/> + </function-type> + </abi-instr> + <abi-instr address-size='64' path='Python/traceback.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyObject_CallMethodFormat' filepath='./Include/internal/pycore_call.h' line='33' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-177'/> + <parameter type-id='type-id-2'/> + <parameter type-id='type-id-12'/> + <parameter is-variadic='yes'/> + <return type-id='type-id-2'/> + </function-decl> + <var-decl name='PyTraceBack_Type' type-id='type-id-256' mangled-name='PyTraceBack_Type' visibility='default' filepath='./Include/traceback.h' line='13' column='1' elf-symbol-id='PyTraceBack_Type'/> + <function-decl name='_PyTokenizer_FindEncodingFilename' filepath='Python/traceback.c' line='34' column='1' visibility='default' binding='global' size-in-bits='64'> + <parameter type-id='type-id-8'/> + <parameter type-id='type-id-2'/> + <return type-id='type-id-15'/> + </function-decl> + <function-decl name='_PyTraceback_Add' mangled-name='_PyTraceback_Add' filepath='Python/traceback.c' line='261' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceback_Add'> + <parameter type-id='type-id-12' name='funcname' filepath='Python/traceback.c' line='261' column='1'/> + <parameter type-id='type-id-12' name='filename' filepath='Python/traceback.c' line='261' column='1'/> + <parameter type-id='type-id-8' name='lineno' filepath='Python/traceback.c' line='261' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_Py_DumpTraceback' mangled-name='_Py_DumpTraceback' filepath='Python/traceback.c' line='1251' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Py_DumpTraceback'> + <parameter type-id='type-id-8' name='fd' filepath='Python/traceback.c' line='1251' column='1'/> + <parameter type-id='type-id-177' name='tstate' filepath='Python/traceback.c' line='1251' column='1'/> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> + <abi-instr address-size='64' path='Python/tracemalloc.c' comp-dir-path='/src' language='LANG_C11'> + <function-decl name='_PyTraceMalloc_Init' mangled-name='_PyTraceMalloc_Init' filepath='Python/tracemalloc.c' line='799' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_Init'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTraceMalloc_Stop' mangled-name='_PyTraceMalloc_Stop' filepath='Python/tracemalloc.c' line='955' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_Stop'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='PyTraceMalloc_Track' mangled-name='PyTraceMalloc_Track' filepath='Python/tracemalloc.c' line='1301' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTraceMalloc_Track'> + <parameter type-id='type-id-95' name='domain' filepath='Python/tracemalloc.c' line='1301' column='1'/> + <parameter type-id='type-id-747' name='ptr' filepath='Python/tracemalloc.c' line='1301' column='1'/> + <parameter type-id='type-id-19' name='size' filepath='Python/tracemalloc.c' line='1302' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='PyTraceMalloc_Untrack' mangled-name='PyTraceMalloc_Untrack' filepath='Python/tracemalloc.c' line='1324' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyTraceMalloc_Untrack'> + <parameter type-id='type-id-95' name='domain' filepath='Python/tracemalloc.c' line='1324' column='1'/> + <parameter type-id='type-id-747' name='ptr' filepath='Python/tracemalloc.c' line='1324' column='1'/> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTraceMalloc_GetTraceback' mangled-name='_PyTraceMalloc_GetTraceback' filepath='Python/tracemalloc.c' line='1386' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_GetTraceback'> + <parameter type-id='type-id-95' name='domain' filepath='Python/tracemalloc.c' line='1386' column='1'/> + <parameter type-id='type-id-747' name='ptr' filepath='Python/tracemalloc.c' line='1386' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTraceMalloc_IsTracing' mangled-name='_PyTraceMalloc_IsTracing' filepath='Python/tracemalloc.c' line='1398' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_IsTracing'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTraceMalloc_ClearTraces' mangled-name='_PyTraceMalloc_ClearTraces' filepath='Python/tracemalloc.c' line='1404' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_ClearTraces'> + <return type-id='type-id-46'/> + </function-decl> + <function-decl name='_PyTraceMalloc_GetTraces' mangled-name='_PyTraceMalloc_GetTraces' filepath='Python/tracemalloc.c' line='1416' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_GetTraces'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTraceMalloc_GetObjectTraceback' mangled-name='_PyTraceMalloc_GetObjectTraceback' filepath='Python/tracemalloc.c' line='1496' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_GetObjectTraceback'> + <parameter type-id='type-id-2' name='obj' filepath='Python/tracemalloc.c' line='1496' column='1'/> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTraceMalloc_GetTracebackLimit' mangled-name='_PyTraceMalloc_GetTracebackLimit' filepath='Python/tracemalloc.c' line='1514' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_GetTracebackLimit'> + <return type-id='type-id-8'/> + </function-decl> + <function-decl name='_PyTraceMalloc_GetMemory' mangled-name='_PyTraceMalloc_GetMemory' filepath='Python/tracemalloc.c' line='1519' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_GetMemory'> + <return type-id='type-id-19'/> + </function-decl> + <function-decl name='_PyTraceMalloc_GetTracedMemory' mangled-name='_PyTraceMalloc_GetTracedMemory' filepath='Python/tracemalloc.c' line='1536' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_GetTracedMemory'> + <return type-id='type-id-2'/> + </function-decl> + <function-decl name='_PyTraceMalloc_ResetPeak' mangled-name='_PyTraceMalloc_ResetPeak' filepath='Python/tracemalloc.c' line='1552' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyTraceMalloc_ResetPeak'> + <return type-id='type-id-46'/> + </function-decl> + </abi-instr> +</abi-corpus> From webhook-mailer at python.org Tue May 23 04:58:00 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 23 May 2023 08:58:00 -0000 Subject: [Python-checkins] [3.12] howto/urllib2: remove link to an outdated french translation (GH-104193) (#104758) Message-ID: <mailman.12.1684832281.17421.python-checkins@python.org> https://github.com/python/cpython/commit/25b5ce72c9b1c31d5d23b4dcaacafc07690e73e1 commit: 25b5ce72c9b1c31d5d23b4dcaacafc07690e73e1 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-23T08:57:52Z summary: [3.12] howto/urllib2: remove link to an outdated french translation (GH-104193) (#104758) We now have our own translation and it's not outdated (cherry picked from commit 151b6bfb5d9a15b6e2682e5a3008a3f9ec3086ae) Co-authored-by: Mathieu Dupuy <deronnax at gmail.com> files: M Doc/howto/urllib2.rst diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst index 61ba6bd7224f..86137fb38c9b 100644 --- a/Doc/howto/urllib2.rst +++ b/Doc/howto/urllib2.rst @@ -6,13 +6,6 @@ :Author: `Michael Foord <https://agileabstractions.com/>`_ -.. note:: - - There is a French translation of an earlier revision of this - HOWTO, available at `urllib2 - Le Manuel manquant - <https://web.archive.org/web/20200910051922/http://www.voidspace.org.uk/python/articles/urllib2_francais.shtml>`_. - - Introduction ============ From webhook-mailer at python.org Tue May 23 05:24:36 2023 From: webhook-mailer at python.org (brandtbucher) Date: Tue, 23 May 2023 09:24:36 -0000 Subject: [Python-checkins] [3.12] GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104760) Message-ID: <mailman.13.1684833877.17421.python-checkins@python.org> https://github.com/python/cpython/commit/905d419cac0e2617ee07c8a478e132793878a875 commit: 905d419cac0e2617ee07c8a478e132793878a875 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: brandtbucher <brandtbucher at gmail.com> date: 2023-05-23T09:24:28Z summary: [3.12] GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104760) GH-104668: Don't call PyOS_* hooks in subinterpreters (GH-104674) (cherry picked from commit 357bed0bcd3c5d7c4a8caad451754a9a172aca3e) Co-authored-by: Brandt Bucher <brandtbucher at microsoft.com> files: A Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst M Doc/c-api/veryhigh.rst M Doc/whatsnew/3.12.rst M Parser/myreadline.c diff --git a/Doc/c-api/veryhigh.rst b/Doc/c-api/veryhigh.rst index 513856d8a48d..000a2d3d8790 100644 --- a/Doc/c-api/veryhigh.rst +++ b/Doc/c-api/veryhigh.rst @@ -167,6 +167,10 @@ the same library that the Python runtime is using. event loops, as done in the :file:`Modules/_tkinter.c` in the Python source code. + .. versionchanged:: 3.12 + This function is only called from the + :ref:`main interpreter <sub-interpreter-support>`. + .. c:var:: char* (*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, const char *) @@ -187,6 +191,10 @@ the same library that the Python runtime is using. :c:func:`PyMem_RawRealloc`, instead of being allocated by :c:func:`PyMem_Malloc` or :c:func:`PyMem_Realloc`. + .. versionchanged:: 3.12 + This function is only called from the + :ref:`main interpreter <sub-interpreter-support>`. + .. c:function:: PyObject* PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals) This is a simplified interface to :c:func:`PyRun_StringFlags` below, leaving diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index efbd2ca3de12..4ff90664bb79 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1476,6 +1476,15 @@ Porting to Python 3.12 Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12) already disallows creating classes whose metaclass overrides ``tp_new``. +* :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no + longer called in :ref:`subinterpreters <sub-interpreter-support>`. This is + because clients generally rely on process-wide global state (since these + callbacks have no way of recovering extension module state). + + This also avoids situations where extensions may find themselves running in a + subinterpreter that they don't support (or haven't yet been loaded in). See + :gh:`104668` for more info. + Deprecated ---------- diff --git a/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst new file mode 100644 index 000000000000..7b882afd7f81 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-05-19-10-22-34.gh-issue-104668.MLX1g9.rst @@ -0,0 +1,5 @@ +Don't call :c:var:`PyOS_InputHook` or :c:var:`PyOS_ReadlineFunctionPointer` +in subinterpreters, since it's generally difficult to avoid using global +state in their registered callbacks. This also avoids situations where +extensions may find themselves running in a subinterpreter they don't +support (or haven't yet been loaded in). diff --git a/Parser/myreadline.c b/Parser/myreadline.c index 3f0e29f051a4..7074aba74b72 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -45,7 +45,10 @@ my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp) #endif while (1) { - if (PyOS_InputHook != NULL) { + if (PyOS_InputHook != NULL && + // GH-104668: See PyOS_ReadlineFunctionPointer's comment below... + _Py_IsMainInterpreter(tstate->interp)) + { (void)(PyOS_InputHook)(); } @@ -131,7 +134,10 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn) wbuf = wbuf_local; wbuflen = sizeof(wbuf_local) / sizeof(wbuf_local[0]) - 1; while (1) { - if (PyOS_InputHook != NULL) { + if (PyOS_InputHook != NULL && + // GH-104668: See PyOS_ReadlineFunctionPointer's comment below... + _Py_IsMainInterpreter(tstate->interp)) + { (void)(PyOS_InputHook)(); } if (!ReadConsoleW(hStdIn, &wbuf[total_read], wbuflen - total_read, &n_read, NULL)) { @@ -389,11 +395,23 @@ PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) * a tty. This can happen, for example if python is run like * this: python -i < test1.py */ - if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout))) - rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt); - else - rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, - prompt); + if (!isatty(fileno(sys_stdin)) || !isatty(fileno(sys_stdout)) || + // GH-104668: Don't call global callbacks like PyOS_InputHook or + // PyOS_ReadlineFunctionPointer from subinterpreters, since it seems + // like there's no good way for users (like readline and tkinter) to + // avoid using global state to manage them. Plus, we generally don't + // want to cause trouble for libraries that don't know/care about + // subinterpreter support. If libraries really need better APIs that + // work per-interpreter and have ways to access module state, we can + // certainly add them later (but for now we'll cross our fingers and + // hope that nobody actually cares): + !_Py_IsMainInterpreter(tstate->interp)) + { + rv = PyOS_StdioReadline(sys_stdin, sys_stdout, prompt); + } + else { + rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, prompt); + } Py_END_ALLOW_THREADS PyThread_release_lock(_PyOS_ReadlineLock); From webhook-mailer at python.org Tue May 23 05:28:11 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 23 May 2023 09:28:11 -0000 Subject: [Python-checkins] [3.12] GH-101291: Avoid using macros with casts in low-level long API. (GH-104742) (#104759) Message-ID: <mailman.14.1684834092.17421.python-checkins@python.org> https://github.com/python/cpython/commit/e43fbbd92884ad167cdaea296526c671f593b234 commit: e43fbbd92884ad167cdaea296526c671f593b234 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-23T09:28:04Z summary: [3.12] GH-101291: Avoid using macros with casts in low-level long API. (GH-104742) (#104759) (cherry picked from commit e295d8605699ad3d8ec46c8d55a5e47da05b20c6) Co-authored-by: Mark Shannon <mark at hotpy.org> files: M Include/cpython/longintrepr.h diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 0f569935fff1..692c69ba76db 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -104,9 +104,10 @@ _PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); #define _PyLong_SIGN_MASK 3 #define _PyLong_NON_SIZE_BITS 3 + static inline int _PyLong_IsCompact(const PyLongObject* op) { - assert(PyLong_Check(op)); + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); } @@ -115,7 +116,7 @@ _PyLong_IsCompact(const PyLongObject* op) { static inline Py_ssize_t _PyLong_CompactValue(const PyLongObject *op) { - assert(PyLong_Check(op)); + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); assert(PyUnstable_Long_IsCompact(op)); Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); return sign * (Py_ssize_t)op->long_value.ob_digit[0]; From webhook-mailer at python.org Tue May 23 07:24:21 2023 From: webhook-mailer at python.org (gpshead) Date: Tue, 23 May 2023 11:24:21 -0000 Subject: [Python-checkins] [3.12] gh-99108: Release the GIL around hashlib built-in computation (GH-104675) (#104776) Message-ID: <mailman.15.1684841061.17421.python-checkins@python.org> https://github.com/python/cpython/commit/9aea1f28e2d22dd8650f6153eb5630ffd250d3c8 commit: 9aea1f28e2d22dd8650f6153eb5630ffd250d3c8 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-23T11:24:02Z summary: [3.12] gh-99108: Release the GIL around hashlib built-in computation (GH-104675) (#104776) gh-99108: Release the GIL around hashlib built-in computation (GH-104675) This matches the GIL releasing behavior of our existing `_hashopenssl` module, extending it to the HACL* built-ins. Includes adding comments to better describe the ENTER/LEAVE macros purpose and explain the lock strategy in both existing and new code. (cherry picked from commit 2e5d8a90aa633ff0bebc9b2b8e21eea389937b19) Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst M Modules/_hashopenssl.c M Modules/hashlib.h M Modules/md5module.c M Modules/sha1module.c M Modules/sha2module.c M Modules/sha3module.c diff --git a/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst new file mode 100644 index 000000000000..b595f1893609 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-19-19-46-22.gh-issue-99108.wqCg0t.rst @@ -0,0 +1,3 @@ +We now release the GIL around built-in :mod:`hashlib` computations of +reasonable size for the SHA families and MD5 hash functions, matching +what our OpenSSL backed hash computations already does. diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 99d0b7281913..4b425f414751 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -227,12 +227,16 @@ get_hashlib_state(PyObject *module) typedef struct { PyObject_HEAD EVP_MD_CTX *ctx; /* OpenSSL message digest context */ + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. PyThread_type_lock lock; /* OpenSSL context lock */ } EVPobject; typedef struct { PyObject_HEAD HMAC_CTX *ctx; /* OpenSSL hmac context */ + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. PyThread_type_lock lock; /* HMAC context lock */ } HMACobject; @@ -896,6 +900,8 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj, if (view.buf && view.len) { if (view.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ Py_BEGIN_ALLOW_THREADS result = EVP_hash(self, view.buf, view.len); Py_END_ALLOW_THREADS diff --git a/Modules/hashlib.h b/Modules/hashlib.h index 56ae7a5e50bf..a8bad9dd87a9 100644 --- a/Modules/hashlib.h +++ b/Modules/hashlib.h @@ -37,6 +37,13 @@ * LEAVE_HASHLIB block or explicitly acquire and release the lock inside * a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for * an operation. + * + * These only drop the GIL if the lock acquisition itself is likely to + * block. Thus the non-blocking acquire gating the GIL release for a + * blocking lock acquisition. The intent of these macros is to surround + * the assumed always "fast" operations that you aren't releasing the + * GIL around. Otherwise use code similar to what you see in hash + * function update() methods. */ #include "pythread.h" @@ -53,7 +60,7 @@ PyThread_release_lock((obj)->lock); \ } -/* TODO(gps): We should probably make this a module or EVPobject attribute +/* TODO(gpshead): We should make this a module or class attribute * to allow the user to optimize based on the platform they're using. */ #define HASHLIB_GIL_MINSIZE 2048 diff --git a/Modules/md5module.c b/Modules/md5module.c index 86605771d964..2122f8b18baf 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -49,7 +49,9 @@ typedef long long MD5_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD - + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_MD5_state *hash_state; } MD5object; @@ -72,6 +74,7 @@ static MD5object * newMD5object(MD5State * st) { MD5object *md5 = (MD5object *)PyObject_GC_New(MD5object, st->md5_type); + md5->lock = NULL; PyObject_GC_Track(md5); return md5; } @@ -88,6 +91,9 @@ static void MD5_dealloc(MD5object *ptr) { Hacl_Streaming_MD5_legacy_free(ptr->hash_state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -115,7 +121,9 @@ MD5Type_copy_impl(MD5object *self, PyTypeObject *cls) if ((newobj = newMD5object(st))==NULL) return NULL; + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_MD5_legacy_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -130,7 +138,9 @@ MD5Type_digest_impl(MD5object *self) /*[clinic end generated code: output=eb691dc4190a07ec input=bc0c4397c2994be6]*/ { unsigned char digest[MD5_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, MD5_DIGESTSIZE); } @@ -145,7 +155,9 @@ MD5Type_hexdigest_impl(MD5object *self) /*[clinic end generated code: output=17badced1f3ac932 input=b60b19de644798dd]*/ { unsigned char digest[MD5_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_MD5_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char*)digest, MD5_DIGESTSIZE); } @@ -177,7 +189,18 @@ MD5Type_update(MD5object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -279,7 +302,15 @@ _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update(new->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update(new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update(new->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha1module.c b/Modules/sha1module.c index bdb76c56f1a6..c66269b5f5cd 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -48,7 +48,9 @@ typedef long long SHA1_INT64; /* 64-bit integer */ typedef struct { PyObject_HEAD - + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA1_state *hash_state; } SHA1object; @@ -71,6 +73,7 @@ static SHA1object * newSHA1object(SHA1State *st) { SHA1object *sha = (SHA1object *)PyObject_GC_New(SHA1object, st->sha1_type); + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -88,6 +91,9 @@ static void SHA1_dealloc(SHA1object *ptr) { Hacl_Streaming_SHA1_legacy_free(ptr->hash_state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -115,7 +121,9 @@ SHA1Type_copy_impl(SHA1object *self, PyTypeObject *cls) if ((newobj = newSHA1object(st)) == NULL) return NULL; + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_SHA1_legacy_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -130,7 +138,9 @@ SHA1Type_digest_impl(SHA1object *self) /*[clinic end generated code: output=2f05302a7aa2b5cb input=13824b35407444bd]*/ { unsigned char digest[SHA1_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, SHA1_DIGESTSIZE); } @@ -145,7 +155,9 @@ SHA1Type_hexdigest_impl(SHA1object *self) /*[clinic end generated code: output=4161fd71e68c6659 input=97691055c0c74ab0]*/ { unsigned char digest[SHA1_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_SHA1_legacy_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, SHA1_DIGESTSIZE); } @@ -177,7 +189,18 @@ SHA1Type_update(SHA1object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -279,7 +302,15 @@ _sha1_sha1_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update(new->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update(new->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update(new->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 37d9b5c538fd..6c7c3917198d 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -52,12 +52,18 @@ class SHA512Type "SHA512object *" "&PyType_Type" typedef struct { PyObject_HEAD int digestsize; + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA2_state_sha2_256 *state; } SHA256object; typedef struct { PyObject_HEAD int digestsize; + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_SHA2_state_sha2_512 *state; } SHA512object; @@ -100,6 +106,7 @@ newSHA224object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -112,6 +119,7 @@ newSHA256object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -124,6 +132,7 @@ newSHA384object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -136,6 +145,7 @@ newSHA512object(sha2_state *state) if (!sha) { return NULL; } + sha->lock = NULL; PyObject_GC_Track(sha); return sha; } @@ -153,6 +163,9 @@ static void SHA256_dealloc(SHA256object *ptr) { Hacl_Streaming_SHA2_free_256(ptr->state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -163,6 +176,9 @@ static void SHA512_dealloc(SHA512object *ptr) { Hacl_Streaming_SHA2_free_512(ptr->state); + if (ptr->lock != NULL) { + PyThread_free_lock(ptr->lock); + } PyTypeObject *tp = Py_TYPE(ptr); PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); @@ -229,7 +245,9 @@ SHA256Type_copy_impl(SHA256object *self, PyTypeObject *cls) } } + ENTER_HASHLIB(self); SHA256copy(self, newobj); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -259,7 +277,9 @@ SHA512Type_copy_impl(SHA512object *self, PyTypeObject *cls) } } + ENTER_HASHLIB(self); SHA512copy(self, newobj); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -275,9 +295,11 @@ SHA256Type_digest_impl(SHA256object *self) { uint8_t digest[SHA256_DIGESTSIZE]; assert(self->digestsize <= SHA256_DIGESTSIZE); + ENTER_HASHLIB(self); // HACL* performs copies under the hood so that self->state remains valid // after this call. Hacl_Streaming_SHA2_finish_256(self->state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -293,9 +315,11 @@ SHA512Type_digest_impl(SHA512object *self) { uint8_t digest[SHA512_DIGESTSIZE]; assert(self->digestsize <= SHA512_DIGESTSIZE); + ENTER_HASHLIB(self); // HACL* performs copies under the hood so that self->state remains valid // after this call. Hacl_Streaming_SHA2_finish_512(self->state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, self->digestsize); } @@ -311,7 +335,9 @@ SHA256Type_hexdigest_impl(SHA256object *self) { uint8_t digest[SHA256_DIGESTSIZE]; assert(self->digestsize <= SHA256_DIGESTSIZE); + ENTER_HASHLIB(self); Hacl_Streaming_SHA2_finish_256(self->state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, self->digestsize); } @@ -327,7 +353,9 @@ SHA512Type_hexdigest_impl(SHA512object *self) { uint8_t digest[SHA512_DIGESTSIZE]; assert(self->digestsize <= SHA512_DIGESTSIZE); + ENTER_HASHLIB(self); Hacl_Streaming_SHA2_finish_512(self->state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, self->digestsize); } @@ -348,7 +376,18 @@ SHA256Type_update(SHA256object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update_256(self->state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update_256(self->state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update_256(self->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -371,7 +410,18 @@ SHA512Type_update(SHA512object *self, PyObject *obj) GET_BUFFER_VIEW_OR_ERROUT(obj, &buf); - update_512(self->state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + update_512(self->state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + update_512(self->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; @@ -560,7 +610,15 @@ _sha2_sha256_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_256(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_256(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_256(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -606,7 +664,15 @@ _sha2_sha224_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_256(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_256(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_256(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -651,7 +717,15 @@ _sha2_sha512_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_512(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_512(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_512(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } @@ -696,7 +770,15 @@ _sha2_sha384_impl(PyObject *module, PyObject *string, int usedforsecurity) return NULL; } if (string) { - update_512(new->state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + update_512(new->state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + update_512(new->state, buf.buf, buf.len); + } PyBuffer_Release(&buf); } diff --git a/Modules/sha3module.c b/Modules/sha3module.c index f05187498a19..558d2005cff6 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -60,6 +60,9 @@ class _sha3.shake_256 "SHA3object *" "&SHAKE256type" typedef struct { PyObject_HEAD + // Prevents undefined behavior via multiple threads entering the C API. + // The lock will be NULL before threaded access has been enabled. + PyThread_type_lock lock; Hacl_Streaming_Keccak_state *hash_state; } SHA3object; @@ -73,6 +76,7 @@ newSHA3object(PyTypeObject *type) if (newobj == NULL) { return NULL; } + newobj->lock = NULL; return newobj; } @@ -133,7 +137,15 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity) if (data) { GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error); - sha3_update(self->hash_state, buf.buf, buf.len); + if (buf.len >= HASHLIB_GIL_MINSIZE) { + /* We do not initialize self->lock here as this is the constructor + * where it is not yet possible to have concurrent access. */ + Py_BEGIN_ALLOW_THREADS + sha3_update(self->hash_state, buf.buf, buf.len); + Py_END_ALLOW_THREADS + } else { + sha3_update(self->hash_state, buf.buf, buf.len); + } } PyBuffer_Release(&buf); @@ -157,6 +169,9 @@ static void SHA3_dealloc(SHA3object *self) { Hacl_Streaming_Keccak_free(self->hash_state); + if (self->lock != NULL) { + PyThread_free_lock(self->lock); + } PyTypeObject *tp = Py_TYPE(self); PyObject_Free(self); Py_DECREF(tp); @@ -181,7 +196,9 @@ _sha3_sha3_224_copy_impl(SHA3object *self) if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) { return NULL; } + ENTER_HASHLIB(self); newobj->hash_state = Hacl_Streaming_Keccak_copy(self->hash_state); + LEAVE_HASHLIB(self); return (PyObject *)newobj; } @@ -199,7 +216,9 @@ _sha3_sha3_224_digest_impl(SHA3object *self) unsigned char digest[SHA3_MAX_DIGESTSIZE]; // This function errors out if the algorithm is Shake. Here, we know this // not to be the case, and therefore do not perform error checking. + ENTER_HASHLIB(self); Hacl_Streaming_Keccak_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return PyBytes_FromStringAndSize((const char *)digest, Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -216,7 +235,9 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self) /*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/ { unsigned char digest[SHA3_MAX_DIGESTSIZE]; + ENTER_HASHLIB(self); Hacl_Streaming_Keccak_finish(self->hash_state, digest); + LEAVE_HASHLIB(self); return _Py_strhex((const char *)digest, Hacl_Streaming_Keccak_hash_len(self->hash_state)); } @@ -237,7 +258,18 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data) { Py_buffer buf; GET_BUFFER_VIEW_OR_ERROUT(data, &buf); - sha3_update(self->hash_state, buf.buf, buf.len); + if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) { + self->lock = PyThread_allocate_lock(); + } + if (self->lock != NULL) { + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + sha3_update(self->hash_state, buf.buf, buf.len); + PyThread_release_lock(self->lock); + Py_END_ALLOW_THREADS + } else { + sha3_update(self->hash_state, buf.buf, buf.len); + } PyBuffer_Release(&buf); Py_RETURN_NONE; } From webhook-mailer at python.org Tue May 23 09:44:50 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Tue, 23 May 2023 13:44:50 -0000 Subject: [Python-checkins] gh-92871: Remove typing.{io, re} namespaces (#92873) Message-ID: <mailman.16.1684849491.17421.python-checkins@python.org> https://github.com/python/cpython/commit/abdda5b13388aa21923f6ce104242adff518d430 commit: abdda5b13388aa21923f6ce104242adff518d430 branch: main author: Sebastian Rittau <srittau at rittau.biz> committer: JelleZijlstra <jelle.zijlstra at gmail.com> date: 2023-05-23T13:44:26Z summary: gh-92871: Remove typing.{io,re} namespaces (#92873) Closes #92871 Co-authored-by: Alex Waygood <Alex.Waygood at Gmail.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/Library/2022-05-17-10-46-44.gh-issue-92871.GVogrT.rst M Doc/library/typing.rst M Doc/whatsnew/3.13.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index c90cb411acde..92943c46ef51 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2074,10 +2074,6 @@ Other concrete types represent the types of I/O streams such as returned by :func:`open`. - .. deprecated-removed:: 3.8 3.13 - The ``typing.io`` namespace is deprecated and will be removed. - These types should be directly imported from ``typing`` instead. - .. class:: Pattern Match @@ -2088,10 +2084,6 @@ Other concrete types ``Pattern[str]``, ``Pattern[bytes]``, ``Match[str]``, or ``Match[bytes]``. - .. deprecated-removed:: 3.8 3.13 - The ``typing.re`` namespace is deprecated and will be removed. - These types should be directly imported from ``typing`` instead. - .. deprecated:: 3.9 Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. See :pep:`585` and :ref:`types-genericalias`. @@ -2981,9 +2973,6 @@ convenience. This is subject to change, and not all deprecations are listed. +----------------------------------+---------------+-------------------+----------------+ | Feature | Deprecated in | Projected removal | PEP/issue | +==================================+===============+===================+================+ -| ``typing.io`` and ``typing.re`` | 3.8 | 3.13 | :issue:`38291` | -| submodules | | | | -+----------------------------------+---------------+-------------------+----------------+ | ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | | collections | | | | +----------------------------------+---------------+-------------------+----------------+ diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 8256f429183a..602a865b5930 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -107,6 +107,9 @@ Removed `Exscript <https://pypi.org/project/Exscript/>`_ instead. (Contributed by Victor Stinner in :gh:`104773`.) +* Namespaces ``typing.io`` and ``typing.re``, deprecated in Python 3.8, + are now removed. The items in those namespaces can be imported directly + from :mod:`typing`. (Contributed by Sebastian Rittau in :gh:`92871`.) Porting to Python 3.13 ====================== diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 9a3e64289ee8..b4a5a68a2f7e 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7529,17 +7529,6 @@ def stuff(a: BinaryIO) -> bytes: a = stuff.__annotations__['a'] self.assertEqual(a.__parameters__, ()) - def test_io_submodule(self): - with warnings.catch_warnings(record=True) as w: - warnings.filterwarnings("default", category=DeprecationWarning) - from typing.io import IO, TextIO, BinaryIO, __all__, __name__ - self.assertIs(IO, typing.IO) - self.assertIs(TextIO, typing.TextIO) - self.assertIs(BinaryIO, typing.BinaryIO) - self.assertEqual(set(__all__), set(['IO', 'TextIO', 'BinaryIO'])) - self.assertEqual(__name__, 'typing.io') - self.assertEqual(len(w), 1) - class RETests(BaseTestCase): # Much of this is really testing _TypeAlias. @@ -7584,16 +7573,6 @@ def test_repr(self): self.assertEqual(repr(Match[str]), 'typing.Match[str]') self.assertEqual(repr(Match[bytes]), 'typing.Match[bytes]') - def test_re_submodule(self): - with warnings.catch_warnings(record=True) as w: - warnings.filterwarnings("default", category=DeprecationWarning) - from typing.re import Match, Pattern, __all__, __name__ - self.assertIs(Match, typing.Match) - self.assertIs(Pattern, typing.Pattern) - self.assertEqual(set(__all__), set(['Match', 'Pattern'])) - self.assertEqual(__name__, 'typing.re') - self.assertEqual(len(w), 1) - def test_cannot_subclass(self): with self.assertRaisesRegex( TypeError, @@ -8765,7 +8744,7 @@ def test_all(self): # Context managers. self.assertIn('ContextManager', a) self.assertIn('AsyncContextManager', a) - # Check that io and re are not exported. + # Check that former namespaces io and re are not exported. self.assertNotIn('io', a) self.assertNotIn('re', a) # Spot-check that stdlib modules aren't exported. @@ -8785,7 +8764,6 @@ def test_all_exported_names(self): if k in actual_all or ( # avoid private names not k.startswith('_') and - k not in {'io', 're'} and # there's a few types and metaclasses that aren't exported not k.endswith(('Meta', '_contra', '_co')) and not k.upper() == k and diff --git a/Lib/typing.py b/Lib/typing.py index 96393d6a0281..95dbc0b85bcd 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -16,7 +16,6 @@ no_type_check_decorator. * Generic aliases for collections.abc ABCs and few additional protocols. * Special types: NewType, NamedTuple, TypedDict. -* Wrapper submodules for re and io related types. """ from abc import abstractmethod, ABCMeta @@ -27,7 +26,7 @@ import contextlib import functools import operator -import re as stdlib_re # Avoid confusion with the re we export. +import re as stdlib_re # Avoid confusion with the typing.re namespace on <=3.11 import sys import types import warnings @@ -158,10 +157,6 @@ 'Unpack', ] -# The pseudo-submodules 're' and 'io' are part of the public -# namespace, but excluded from __all__ because they might stomp on -# legitimate imports of those modules. - def _type_convert(arg, module=None, *, allow_special_forms=False): """For converting None to type(None), and strings to ForwardRef.""" @@ -3150,45 +3145,9 @@ def __enter__(self) -> 'TextIO': pass -class _DeprecatedType(type): - def __getattribute__(cls, name): - if name not in ("__dict__", "__module__") and name in cls.__dict__: - warnings.warn( - f"{cls.__name__} is deprecated, import directly " - f"from typing instead. {cls.__name__} will be removed " - "in Python 3.12.", - DeprecationWarning, - stacklevel=2, - ) - return super().__getattribute__(name) - - -class io(metaclass=_DeprecatedType): - """Wrapper namespace for IO generic classes.""" - - __all__ = ['IO', 'TextIO', 'BinaryIO'] - IO = IO - TextIO = TextIO - BinaryIO = BinaryIO - - -io.__name__ = __name__ + '.io' -sys.modules[io.__name__] = io - Pattern = _alias(stdlib_re.Pattern, 1) Match = _alias(stdlib_re.Match, 1) -class re(metaclass=_DeprecatedType): - """Wrapper namespace for re type aliases.""" - - __all__ = ['Pattern', 'Match'] - Pattern = Pattern - Match = Match - - -re.__name__ = __name__ + '.re' -sys.modules[re.__name__] = re - def reveal_type[T](obj: T, /) -> T: """Reveal the inferred type of a variable. diff --git a/Misc/NEWS.d/next/Library/2022-05-17-10-46-44.gh-issue-92871.GVogrT.rst b/Misc/NEWS.d/next/Library/2022-05-17-10-46-44.gh-issue-92871.GVogrT.rst new file mode 100644 index 000000000000..992f8afadbe9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-17-10-46-44.gh-issue-92871.GVogrT.rst @@ -0,0 +1,2 @@ +Remove the ``typing.io`` and ``typing.re`` namespaces, deprecated since Python +3.8. All items are still available from the main :mod:`typing` module. From webhook-mailer at python.org Tue May 23 09:52:44 2023 From: webhook-mailer at python.org (corona10) Date: Tue, 23 May 2023 13:52:44 -0000 Subject: [Python-checkins] gh-104469: Convert _testcapi/long to use AC (gh-104720) Message-ID: <mailman.17.1684849965.17421.python-checkins@python.org> https://github.com/python/cpython/commit/76170f545870db93b6c45cae09ff34b18639ee97 commit: 76170f545870db93b6c45cae09ff34b18639ee97 branch: main author: Dong-hee Na <donghee.na at python.org> committer: corona10 <donghee.na92 at gmail.com> date: 2023-05-23T22:52:36+09:00 summary: gh-104469: Convert _testcapi/long to use AC (gh-104720) files: A Modules/_testcapi/clinic/long.c.h M Modules/_testcapi/long.c diff --git a/Modules/_testcapi/clinic/long.c.h b/Modules/_testcapi/clinic/long.c.h new file mode 100644 index 000000000000..95885e0ae17a --- /dev/null +++ b/Modules/_testcapi/clinic/long.c.h @@ -0,0 +1,166 @@ +/*[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(_testcapi_test_long_api__doc__, +"test_long_api($module, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_LONG_API_METHODDEF \ + {"test_long_api", (PyCFunction)_testcapi_test_long_api, METH_NOARGS, _testcapi_test_long_api__doc__}, + +static PyObject * +_testcapi_test_long_api_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_api(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_api_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_longlong_api__doc__, +"test_longlong_api($module, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_LONGLONG_API_METHODDEF \ + {"test_longlong_api", (PyCFunction)_testcapi_test_longlong_api, METH_NOARGS, _testcapi_test_longlong_api__doc__}, + +static PyObject * +_testcapi_test_longlong_api_impl(PyObject *module); + +static PyObject * +_testcapi_test_longlong_api(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_longlong_api_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_long_and_overflow__doc__, +"test_long_and_overflow($module, /)\n" +"--\n" +"\n" +"Test the PyLong_AsLongAndOverflow API.\n" +"\n" +"General conversion to PY_LONG is tested by test_long_api_inner.\n" +"This test will concentrate on proper handling of overflow."); + +#define _TESTCAPI_TEST_LONG_AND_OVERFLOW_METHODDEF \ + {"test_long_and_overflow", (PyCFunction)_testcapi_test_long_and_overflow, METH_NOARGS, _testcapi_test_long_and_overflow__doc__}, + +static PyObject * +_testcapi_test_long_and_overflow_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_and_overflow(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_and_overflow_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_long_long_and_overflow__doc__, +"test_long_long_and_overflow($module, /)\n" +"--\n" +"\n" +"Test the PyLong_AsLongLongAndOverflow API.\n" +"\n" +"General conversion to long long is tested by test_long_api_inner.\n" +"This test will concentrate on proper handling of overflow."); + +#define _TESTCAPI_TEST_LONG_LONG_AND_OVERFLOW_METHODDEF \ + {"test_long_long_and_overflow", (PyCFunction)_testcapi_test_long_long_and_overflow, METH_NOARGS, _testcapi_test_long_long_and_overflow__doc__}, + +static PyObject * +_testcapi_test_long_long_and_overflow_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_long_and_overflow(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_long_and_overflow_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_long_as_size_t__doc__, +"test_long_as_size_t($module, /)\n" +"--\n" +"\n" +"Test the PyLong_As{Size,Ssize}_t API.\n" +"\n" +"At present this just tests that non-integer arguments are handled correctly.\n" +"It should be extended to test overflow handling."); + +#define _TESTCAPI_TEST_LONG_AS_SIZE_T_METHODDEF \ + {"test_long_as_size_t", (PyCFunction)_testcapi_test_long_as_size_t, METH_NOARGS, _testcapi_test_long_as_size_t__doc__}, + +static PyObject * +_testcapi_test_long_as_size_t_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_as_size_t(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_as_size_t_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_long_as_unsigned_long_long_mask__doc__, +"test_long_as_unsigned_long_long_mask($module, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_LONG_AS_UNSIGNED_LONG_LONG_MASK_METHODDEF \ + {"test_long_as_unsigned_long_long_mask", (PyCFunction)_testcapi_test_long_as_unsigned_long_long_mask, METH_NOARGS, _testcapi_test_long_as_unsigned_long_long_mask__doc__}, + +static PyObject * +_testcapi_test_long_as_unsigned_long_long_mask_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_as_unsigned_long_long_mask(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_as_unsigned_long_long_mask_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_long_as_double__doc__, +"test_long_as_double($module, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_LONG_AS_DOUBLE_METHODDEF \ + {"test_long_as_double", (PyCFunction)_testcapi_test_long_as_double, METH_NOARGS, _testcapi_test_long_as_double__doc__}, + +static PyObject * +_testcapi_test_long_as_double_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_as_double(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_as_double_impl(module); +} + +PyDoc_STRVAR(_testcapi_test_long_numbits__doc__, +"test_long_numbits($module, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_TEST_LONG_NUMBITS_METHODDEF \ + {"test_long_numbits", (PyCFunction)_testcapi_test_long_numbits, METH_NOARGS, _testcapi_test_long_numbits__doc__}, + +static PyObject * +_testcapi_test_long_numbits_impl(PyObject *module); + +static PyObject * +_testcapi_test_long_numbits(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _testcapi_test_long_numbits_impl(module); +} + +PyDoc_STRVAR(_testcapi_call_long_compact_api__doc__, +"call_long_compact_api($module, arg, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF \ + {"call_long_compact_api", (PyCFunction)_testcapi_call_long_compact_api, METH_O, _testcapi_call_long_compact_api__doc__}, +/*[clinic end generated code: output=d000a1b58fa81eab input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/long.c b/Modules/_testcapi/long.c index 61dd96596dad..ede43f60d06f 100644 --- a/Modules/_testcapi/long.c +++ b/Modules/_testcapi/long.c @@ -1,4 +1,10 @@ #include "parts.h" +#include "clinic/long.c.h" + +/*[clinic input] +module _testcapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ static PyObject * @@ -40,8 +46,13 @@ raise_test_long_error(const char* msg) #include "testcapi_long.h" +/*[clinic input] +_testcapi.test_long_api +[clinic start generated code]*/ + static PyObject * -test_long_api(PyObject* self, PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_api_impl(PyObject *module) +/*[clinic end generated code: output=4405798ca1e9f444 input=e9b8880d7331c688]*/ { return TESTNAME(raise_test_long_error); } @@ -68,8 +79,13 @@ raise_test_longlong_error(const char* msg) #include "testcapi_long.h" +/*[clinic input] +_testcapi.test_longlong_api +[clinic start generated code]*/ + static PyObject * -test_longlong_api(PyObject* self, PyObject *args) +_testcapi_test_longlong_api_impl(PyObject *module) +/*[clinic end generated code: output=2b3414ba8c31dfe6 input=ccbb2a48c2b3c4a5]*/ { return TESTNAME(raise_test_longlong_error); } @@ -81,13 +97,19 @@ test_longlong_api(PyObject* self, PyObject *args) #undef F_U_TO_PY #undef F_PY_TO_U -/* Test the PyLong_AsLongAndOverflow API. General conversion to PY_LONG - is tested by test_long_api_inner. This test will concentrate on proper - handling of overflow. -*/ + +/*[clinic input] +_testcapi.test_long_and_overflow + +Test the PyLong_AsLongAndOverflow API. + +General conversion to PY_LONG is tested by test_long_api_inner. +This test will concentrate on proper handling of overflow. +[clinic start generated code]*/ static PyObject * -test_long_and_overflow(PyObject *self, PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_and_overflow_impl(PyObject *module) +/*[clinic end generated code: output=f8460ca115e31d8e input=762f6b62da0a3cdc]*/ { PyObject *num, *one, *temp; long value; @@ -243,13 +265,18 @@ test_long_and_overflow(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } -/* Test the PyLong_AsLongLongAndOverflow API. General conversion to - long long is tested by test_long_api_inner. This test will - concentrate on proper handling of overflow. -*/ +/*[clinic input] +_testcapi.test_long_long_and_overflow + +Test the PyLong_AsLongLongAndOverflow API. + +General conversion to long long is tested by test_long_api_inner. +This test will concentrate on proper handling of overflow. +[clinic start generated code]*/ static PyObject * -test_long_long_and_overflow(PyObject *self, PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_long_and_overflow_impl(PyObject *module) +/*[clinic end generated code: output=0b92330786f45483 input=544bb0aefe5e8a9e]*/ { PyObject *num, *one, *temp; long long value; @@ -405,13 +432,18 @@ test_long_long_and_overflow(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } -/* Test the PyLong_As{Size,Ssize}_t API. At present this just tests that - non-integer arguments are handled correctly. It should be extended to - test overflow handling. - */ +/*[clinic input] +_testcapi.test_long_as_size_t + +Test the PyLong_As{Size,Ssize}_t API. + +At present this just tests that non-integer arguments are handled correctly. +It should be extended to test overflow handling. +[clinic start generated code]*/ static PyObject * -test_long_as_size_t(PyObject *self, PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_as_size_t_impl(PyObject *module) +/*[clinic end generated code: output=f6490ea2b41e6173 input=922990c4a3edfb0d]*/ { size_t out_u; Py_ssize_t out_s; @@ -442,9 +474,13 @@ test_long_as_size_t(PyObject *self, PyObject *Py_UNUSED(ignored)) return Py_None; } +/*[clinic input] +_testcapi.test_long_as_unsigned_long_long_mask +[clinic start generated code]*/ + static PyObject * -test_long_as_unsigned_long_long_mask(PyObject *self, - PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_as_unsigned_long_long_mask_impl(PyObject *module) +/*[clinic end generated code: output=e3e16cd0189440cc input=eb2438493ae7b9af]*/ { unsigned long long res = PyLong_AsUnsignedLongLongMask(NULL); @@ -462,12 +498,13 @@ test_long_as_unsigned_long_long_mask(PyObject *self, Py_RETURN_NONE; } -/* Test the PyLong_AsDouble API. At present this just tests that - non-integer arguments are handled correctly. - */ +/*[clinic input] +_testcapi.test_long_as_double +[clinic start generated code]*/ static PyObject * -test_long_as_double(PyObject *self, PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_as_double_impl(PyObject *module) +/*[clinic end generated code: output=deca0898e15adde5 input=c77bc88ef5a1de76]*/ { double out; @@ -487,9 +524,13 @@ test_long_as_double(PyObject *self, PyObject *Py_UNUSED(ignored)) return Py_None; } -/* Simple test of _PyLong_NumBits and _PyLong_Sign. */ +/*[clinic input] +_testcapi.test_long_numbits +[clinic start generated code]*/ + static PyObject * -test_long_numbits(PyObject *self, PyObject *Py_UNUSED(ignored)) +_testcapi_test_long_numbits_impl(PyObject *module) +/*[clinic end generated code: output=9eaf8458cb15d7f7 input=265c02d48a13059e]*/ { struct triple { long input; @@ -534,8 +575,16 @@ test_long_numbits(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } +/*[clinic input] +_testcapi.call_long_compact_api + arg: object + / +[clinic start generated code]*/ + static PyObject * -check_long_compact_api(PyObject *self, PyObject *arg) +_testcapi_call_long_compact_api(PyObject *module, PyObject *arg) +/*[clinic end generated code: output=7e3894f611b1b2b7 input=87b87396967af14c]*/ + { assert(PyLong_Check(arg)); int is_compact = PyUnstable_Long_IsCompact((PyLongObject*)arg); @@ -547,15 +596,15 @@ check_long_compact_api(PyObject *self, PyObject *arg) } static PyMethodDef test_methods[] = { - {"test_long_and_overflow", test_long_and_overflow, METH_NOARGS}, - {"test_long_api", test_long_api, METH_NOARGS}, - {"test_long_as_double", test_long_as_double, METH_NOARGS}, - {"test_long_as_size_t", test_long_as_size_t, METH_NOARGS}, - {"test_long_as_unsigned_long_long_mask", test_long_as_unsigned_long_long_mask, METH_NOARGS}, - {"test_long_long_and_overflow",test_long_long_and_overflow, METH_NOARGS}, - {"test_long_numbits", test_long_numbits, METH_NOARGS}, - {"test_longlong_api", test_longlong_api, METH_NOARGS}, - {"call_long_compact_api", check_long_compact_api, METH_O}, + _TESTCAPI_TEST_LONG_AND_OVERFLOW_METHODDEF + _TESTCAPI_TEST_LONG_API_METHODDEF + _TESTCAPI_TEST_LONG_AS_DOUBLE_METHODDEF + _TESTCAPI_TEST_LONG_AS_SIZE_T_METHODDEF + _TESTCAPI_TEST_LONG_AS_UNSIGNED_LONG_LONG_MASK_METHODDEF + _TESTCAPI_TEST_LONG_LONG_AND_OVERFLOW_METHODDEF + _TESTCAPI_TEST_LONG_NUMBITS_METHODDEF + _TESTCAPI_TEST_LONGLONG_API_METHODDEF + _TESTCAPI_CALL_LONG_COMPACT_API_METHODDEF {NULL}, }; From webhook-mailer at python.org Tue May 23 10:11:37 2023 From: webhook-mailer at python.org (hugovk) Date: Tue, 23 May 2023 14:11:37 -0000 Subject: [Python-checkins] gh-81005: Refactor str tests to reflect that str and unicode are merged in Python 3 (#13172) Message-ID: <mailman.18.1684851097.17421.python-checkins@python.org> https://github.com/python/cpython/commit/ddb14859535ab8091381b9d0baf32dbe245b5e65 commit: ddb14859535ab8091381b9d0baf32dbe245b5e65 branch: main author: Daniel Fortunov <asqui at users.noreply.github.com> committer: hugovk <hugovk at users.noreply.github.com> date: 2023-05-23T17:11:29+03:00 summary: gh-81005: Refactor str tests to reflect that str and unicode are merged in Python 3 (#13172) Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com> files: A Lib/test/test_str.py A Misc/NEWS.d/next/Tests/2023-05-19-08-06-06.gh-issue-81005.-q7m9W.rst D Lib/test/test_unicode.py M Lib/test/string_tests.py M Lib/test/test_builtin.py M Lib/test/test_userstring.py diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 709cac7a27a4..a6ea2f378b37 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -8,18 +8,12 @@ from collections import UserList import random + class Sequence: def __init__(self, seq='wxyz'): self.seq = seq def __len__(self): return len(self.seq) def __getitem__(self, i): return self.seq[i] -class BadSeq1(Sequence): - def __init__(self): self.seq = [7, 'hello', 123] - def __str__(self): return '{0} {1} {2}'.format(*self.seq) - -class BadSeq2(Sequence): - def __init__(self): self.seq = ['a', 'b', 'c'] - def __len__(self): return 8 class BaseTest: # These tests are for buffers of values (bytes) and not @@ -27,7 +21,7 @@ class BaseTest: # and various string implementations # The type to be tested - # Change in subclasses to change the behaviour of fixtesttype() + # Change in subclasses to change the behaviour of fixtype() type2test = None # Whether the "contained items" of the container are integers in @@ -36,7 +30,7 @@ class BaseTest: contains_bytes = False # All tests pass their arguments to the testing methods - # as str objects. fixtesttype() can be used to propagate + # as str objects. fixtype() can be used to propagate # these arguments to the appropriate type def fixtype(self, obj): if isinstance(obj, str): @@ -1096,7 +1090,7 @@ def test_splitlines(self): self.checkraises(TypeError, 'abc', 'splitlines', 42, 42) -class CommonTest(BaseTest): +class StringLikeTest(BaseTest): # This testcase contains tests that can be used in all # stringlike classes. Currently this is str and UserString. @@ -1127,11 +1121,6 @@ def test_capitalize_nonascii(self): self.checkequal('\u019b\u1d00\u1d86\u0221\u1fb7', '\u019b\u1d00\u1d86\u0221\u1fb7', 'capitalize') - -class MixinStrUnicodeUserStringTest: - # additional tests that only work for - # stringlike objects, i.e. str, UserString - def test_startswith(self): self.checkequal(True, 'hello', 'startswith', 'he') self.checkequal(True, 'hello', 'startswith', 'hello') @@ -1313,8 +1302,11 @@ def test_join(self): self.checkequal(((('a' * i) + '-') * i)[:-1], '-', 'join', ('a' * i,) * i) - #self.checkequal(str(BadSeq1()), ' ', 'join', BadSeq1()) - self.checkequal('a b c', ' ', 'join', BadSeq2()) + class LiesAboutLengthSeq(Sequence): + def __init__(self): self.seq = ['a', 'b', 'c'] + def __len__(self): return 8 + + self.checkequal('a b c', ' ', 'join', LiesAboutLengthSeq()) self.checkraises(TypeError, ' ', 'join') self.checkraises(TypeError, ' ', 'join', None) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 1257b529038a..f5a5c037f1bf 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1614,7 +1614,7 @@ def test_setattr(self): msg = r"^attribute name must be string, not 'int'$" self.assertRaisesRegex(TypeError, msg, setattr, sys, 1, 'spam') - # test_str(): see test_unicode.py and test_bytes.py for str() tests. + # test_str(): see test_str.py and test_bytes.py for str() tests. def test_sum(self): self.assertEqual(sum([]), 0) diff --git a/Lib/test/test_unicode.py b/Lib/test/test_str.py similarity index 99% rename from Lib/test/test_unicode.py rename to Lib/test/test_str.py index 4ebbb9d32a3d..a6bcc2455de1 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_str.py @@ -55,8 +55,7 @@ def duplicate_string(text): class StrSubclass(str): pass -class UnicodeTest(string_tests.CommonTest, - string_tests.MixinStrUnicodeUserStringTest, +class StrTest(string_tests.StringLikeTest, string_tests.MixinStrUnicodeTest, unittest.TestCase): @@ -213,7 +212,7 @@ def test_pickle_iterator(self): self.assertEqual(case, pickled) def test_count(self): - string_tests.CommonTest.test_count(self) + string_tests.StringLikeTest.test_count(self) # check mixed argument types self.checkequalnofix(3, 'aaa', 'count', 'a') self.checkequalnofix(0, 'aaa', 'count', 'b') @@ -243,7 +242,7 @@ class MyStr(str): self.checkequal(3, MyStr('aaa'), 'count', 'a') def test_find(self): - string_tests.CommonTest.test_find(self) + string_tests.StringLikeTest.test_find(self) # test implementation details of the memchr fast path self.checkequal(100, 'a' * 100 + '\u0102', 'find', '\u0102') self.checkequal(-1, 'a' * 100 + '\u0102', 'find', '\u0201') @@ -288,7 +287,7 @@ def test_find(self): self.checkequal(-1, '\u0102' * 100, 'find', '\u0102\U00100304') def test_rfind(self): - string_tests.CommonTest.test_rfind(self) + string_tests.StringLikeTest.test_rfind(self) # test implementation details of the memrchr fast path self.checkequal(0, '\u0102' + 'a' * 100 , 'rfind', '\u0102') self.checkequal(-1, '\u0102' + 'a' * 100 , 'rfind', '\u0201') @@ -329,7 +328,7 @@ def test_rfind(self): self.checkequal(-1, '\u0102' * 100, 'rfind', '\U00100304\u0102') def test_index(self): - string_tests.CommonTest.test_index(self) + string_tests.StringLikeTest.test_index(self) self.checkequalnofix(0, 'abcdefghiabc', 'index', '') self.checkequalnofix(3, 'abcdefghiabc', 'index', 'def') self.checkequalnofix(0, 'abcdefghiabc', 'index', 'abc') @@ -353,7 +352,7 @@ def test_index(self): self.assertRaises(ValueError, ('\u0102' * 100).index, '\u0102\U00100304') def test_rindex(self): - string_tests.CommonTest.test_rindex(self) + string_tests.StringLikeTest.test_rindex(self) self.checkequalnofix(12, 'abcdefghiabc', 'rindex', '') self.checkequalnofix(3, 'abcdefghiabc', 'rindex', 'def') self.checkequalnofix(9, 'abcdefghiabc', 'rindex', 'abc') @@ -449,7 +448,7 @@ def test_maketrans_translate(self): self.assertRaises(TypeError, 'abababc'.translate, 'abc', 'xyz') def test_split(self): - string_tests.CommonTest.test_split(self) + string_tests.StringLikeTest.test_split(self) # test mixed kinds for left, right in ('ba', '\u0101\u0100', '\U00010301\U00010300'): @@ -466,7 +465,7 @@ def test_split(self): left + delim * 2 + right, 'split', delim *2) def test_rsplit(self): - string_tests.CommonTest.test_rsplit(self) + string_tests.StringLikeTest.test_rsplit(self) # test mixed kinds for left, right in ('ba', '??', '\u0101\u0100', '\U00010301\U00010300'): left *= 9 @@ -486,7 +485,7 @@ def test_rsplit(self): left + right, 'rsplit', None) def test_partition(self): - string_tests.MixinStrUnicodeUserStringTest.test_partition(self) + string_tests.StringLikeTest.test_partition(self) # test mixed kinds self.checkequal(('ABCDEFGH', '', ''), 'ABCDEFGH', 'partition', '\u4200') for left, right in ('ba', '\u0101\u0100', '\U00010301\U00010300'): @@ -503,7 +502,7 @@ def test_partition(self): left + delim * 2 + right, 'partition', delim * 2) def test_rpartition(self): - string_tests.MixinStrUnicodeUserStringTest.test_rpartition(self) + string_tests.StringLikeTest.test_rpartition(self) # test mixed kinds self.checkequal(('', '', 'ABCDEFGH'), 'ABCDEFGH', 'rpartition', '\u4200') for left, right in ('ba', '\u0101\u0100', '\U00010301\U00010300'): @@ -520,7 +519,7 @@ def test_rpartition(self): left + delim * 2 + right, 'rpartition', delim * 2) def test_join(self): - string_tests.MixinStrUnicodeUserStringTest.test_join(self) + string_tests.StringLikeTest.test_join(self) class MyWrapper: def __init__(self, sval): self.sval = sval @@ -547,7 +546,7 @@ def test_join_overflow(self): self.assertRaises(OverflowError, ''.join, seq) def test_replace(self): - string_tests.CommonTest.test_replace(self) + string_tests.StringLikeTest.test_replace(self) # method call forwarded from str implementation because of unicode argument self.checkequalnofix('one at two!three!', 'one!two!three!', 'replace', '!', '@', 1) @@ -866,7 +865,7 @@ def test_surrogates(self): def test_lower(self): - string_tests.CommonTest.test_lower(self) + string_tests.StringLikeTest.test_lower(self) self.assertEqual('\U00010427'.lower(), '\U0001044F') self.assertEqual('\U00010427\U00010427'.lower(), '\U0001044F\U0001044F') @@ -897,7 +896,7 @@ def test_casefold(self): self.assertEqual('\u00b5'.casefold(), '\u03bc') def test_upper(self): - string_tests.CommonTest.test_upper(self) + string_tests.StringLikeTest.test_upper(self) self.assertEqual('\U0001044F'.upper(), '\U00010427') self.assertEqual('\U0001044F\U0001044F'.upper(), '\U00010427\U00010427') @@ -914,7 +913,7 @@ def test_upper(self): self.assertEqual('\u2177'.upper(), '\u2167') def test_capitalize(self): - string_tests.CommonTest.test_capitalize(self) + string_tests.StringLikeTest.test_capitalize(self) self.assertEqual('\U0001044F'.capitalize(), '\U00010427') self.assertEqual('\U0001044F\U0001044F'.capitalize(), '\U00010427\U0001044F') @@ -948,7 +947,7 @@ def test_title(self): self.assertEqual('A\u03a3A'.title(), 'A\u03c3a') def test_swapcase(self): - string_tests.CommonTest.test_swapcase(self) + string_tests.StringLikeTest.test_swapcase(self) self.assertEqual('\U0001044F'.swapcase(), '\U00010427') self.assertEqual('\U00010427'.swapcase(), '\U0001044F') self.assertEqual('\U0001044F\U0001044F'.swapcase(), @@ -974,7 +973,7 @@ def test_swapcase(self): self.assertEqual('\u1fd2'.swapcase(), '\u0399\u0308\u0300') def test_center(self): - string_tests.CommonTest.test_center(self) + string_tests.StringLikeTest.test_center(self) self.assertEqual('x'.center(2, '\U0010FFFF'), 'x\U0010FFFF') self.assertEqual('x'.center(3, '\U0010FFFF'), @@ -1475,7 +1474,7 @@ def __format__(self, spec): self.assertEqual('{f:{}}{}{g}'.format(2, 4, f=1, g='g'), ' 14g') def test_formatting(self): - string_tests.MixinStrUnicodeUserStringTest.test_formatting(self) + string_tests.StringLikeTest.test_formatting(self) # Testing Unicode formatting strings... self.assertEqual("%s, %s" % ("abc", "abc"), 'abc, abc') self.assertEqual("%s, %s, %i, %f, %5.2f" % ("abc", "abc", 1, 2, 3), 'abc, abc, 1, 2.000000, 3.00') diff --git a/Lib/test/test_userstring.py b/Lib/test/test_userstring.py index 51b4f6041e49..74df52f5412a 100644 --- a/Lib/test/test_userstring.py +++ b/Lib/test/test_userstring.py @@ -7,8 +7,7 @@ from collections import UserString class UserStringTest( - string_tests.CommonTest, - string_tests.MixinStrUnicodeUserStringTest, + string_tests.StringLikeTest, unittest.TestCase ): diff --git a/Misc/NEWS.d/next/Tests/2023-05-19-08-06-06.gh-issue-81005.-q7m9W.rst b/Misc/NEWS.d/next/Tests/2023-05-19-08-06-06.gh-issue-81005.-q7m9W.rst new file mode 100644 index 000000000000..dfb653241e26 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-05-19-08-06-06.gh-issue-81005.-q7m9W.rst @@ -0,0 +1,2 @@ +String tests are modified to reflect that ``str`` and ``unicode`` are merged +in Python 3. Patch by Daniel Fortunov. From webhook-mailer at python.org Tue May 23 13:40:11 2023 From: webhook-mailer at python.org (vstinner) Date: Tue, 23 May 2023 17:40:11 -0000 Subject: [Python-checkins] gh-104780: Remove 2to3 program and lib2to3 module (#104781) Message-ID: <mailman.19.1684863614.17421.python-checkins@python.org> https://github.com/python/cpython/commit/ae00b810d1d3ad7f1f7e226b02ece37c986330e7 commit: ae00b810d1d3ad7f1f7e226b02ece37c986330e7 branch: main author: Victor Stinner <vstinner at python.org> committer: vstinner <vstinner at python.org> date: 2023-05-23T19:40:02+02:00 summary: gh-104780: Remove 2to3 program and lib2to3 module (#104781) * Remove the Tools/scripts/2to3 script. * Remove the Lib/test/test_lib2to3/ directory. * Doc/tools/extensions/pyspecific.py: remove the "2to3fixer" object type. * Makefile and PC/layout/main.py no longer compile lib2to3 grammar files. * Update Makefile for 2to3 removal. files: A Misc/NEWS.d/next/Library/2023-05-23-03-36-47.gh-issue-104780.P4e3Yf.rst D Doc/library/2to3.rst D Lib/lib2to3/Grammar.txt D Lib/lib2to3/PatternGrammar.txt D Lib/lib2to3/__init__.py D Lib/lib2to3/__main__.py D Lib/lib2to3/btm_matcher.py D Lib/lib2to3/btm_utils.py D Lib/lib2to3/fixer_base.py D Lib/lib2to3/fixer_util.py D Lib/lib2to3/fixes/__init__.py D Lib/lib2to3/fixes/fix_apply.py D Lib/lib2to3/fixes/fix_asserts.py D Lib/lib2to3/fixes/fix_basestring.py D Lib/lib2to3/fixes/fix_buffer.py D Lib/lib2to3/fixes/fix_dict.py D Lib/lib2to3/fixes/fix_except.py D Lib/lib2to3/fixes/fix_exec.py D Lib/lib2to3/fixes/fix_execfile.py D Lib/lib2to3/fixes/fix_exitfunc.py D Lib/lib2to3/fixes/fix_filter.py D Lib/lib2to3/fixes/fix_funcattrs.py D Lib/lib2to3/fixes/fix_future.py D Lib/lib2to3/fixes/fix_getcwdu.py D Lib/lib2to3/fixes/fix_has_key.py D Lib/lib2to3/fixes/fix_idioms.py D Lib/lib2to3/fixes/fix_import.py D Lib/lib2to3/fixes/fix_imports.py D Lib/lib2to3/fixes/fix_imports2.py D Lib/lib2to3/fixes/fix_input.py D Lib/lib2to3/fixes/fix_intern.py D Lib/lib2to3/fixes/fix_isinstance.py D Lib/lib2to3/fixes/fix_itertools.py D Lib/lib2to3/fixes/fix_itertools_imports.py D Lib/lib2to3/fixes/fix_long.py D Lib/lib2to3/fixes/fix_map.py D Lib/lib2to3/fixes/fix_metaclass.py D Lib/lib2to3/fixes/fix_methodattrs.py D Lib/lib2to3/fixes/fix_ne.py D Lib/lib2to3/fixes/fix_next.py D Lib/lib2to3/fixes/fix_nonzero.py D Lib/lib2to3/fixes/fix_numliterals.py D Lib/lib2to3/fixes/fix_operator.py D Lib/lib2to3/fixes/fix_paren.py D Lib/lib2to3/fixes/fix_print.py D Lib/lib2to3/fixes/fix_raise.py D Lib/lib2to3/fixes/fix_raw_input.py D Lib/lib2to3/fixes/fix_reduce.py D Lib/lib2to3/fixes/fix_reload.py D Lib/lib2to3/fixes/fix_renames.py D Lib/lib2to3/fixes/fix_repr.py D Lib/lib2to3/fixes/fix_set_literal.py D Lib/lib2to3/fixes/fix_standarderror.py D Lib/lib2to3/fixes/fix_sys_exc.py D Lib/lib2to3/fixes/fix_throw.py D Lib/lib2to3/fixes/fix_tuple_params.py D Lib/lib2to3/fixes/fix_types.py D Lib/lib2to3/fixes/fix_unicode.py D Lib/lib2to3/fixes/fix_urllib.py D Lib/lib2to3/fixes/fix_ws_comma.py D Lib/lib2to3/fixes/fix_xrange.py D Lib/lib2to3/fixes/fix_xreadlines.py D Lib/lib2to3/fixes/fix_zip.py D Lib/lib2to3/main.py D Lib/lib2to3/patcomp.py D Lib/lib2to3/pgen2/__init__.py D Lib/lib2to3/pgen2/conv.py D Lib/lib2to3/pgen2/driver.py D Lib/lib2to3/pgen2/grammar.py D Lib/lib2to3/pgen2/literals.py D Lib/lib2to3/pgen2/parse.py D Lib/lib2to3/pgen2/pgen.py D Lib/lib2to3/pgen2/token.py D Lib/lib2to3/pgen2/tokenize.py D Lib/lib2to3/pygram.py D Lib/lib2to3/pytree.py D Lib/lib2to3/refactor.py D Lib/test/test_lib2to3/__init__.py D Lib/test/test_lib2to3/__main__.py D Lib/test/test_lib2to3/data/README D Lib/test/test_lib2to3/data/bom.py D Lib/test/test_lib2to3/data/crlf.py D Lib/test/test_lib2to3/data/different_encoding.py D Lib/test/test_lib2to3/data/false_encoding.py D Lib/test/test_lib2to3/data/fixers/bad_order.py D Lib/test/test_lib2to3/data/fixers/myfixes/__init__.py D Lib/test/test_lib2to3/data/fixers/myfixes/fix_explicit.py D Lib/test/test_lib2to3/data/fixers/myfixes/fix_first.py D Lib/test/test_lib2to3/data/fixers/myfixes/fix_last.py D Lib/test/test_lib2to3/data/fixers/myfixes/fix_parrot.py D Lib/test/test_lib2to3/data/fixers/myfixes/fix_preorder.py D Lib/test/test_lib2to3/data/fixers/no_fixer_cls.py D Lib/test/test_lib2to3/data/fixers/parrot_example.py D Lib/test/test_lib2to3/data/infinite_recursion.py D Lib/test/test_lib2to3/data/py2_test_grammar.py D Lib/test/test_lib2to3/data/py3_test_grammar.py D Lib/test/test_lib2to3/pytree_idempotency.py D Lib/test/test_lib2to3/support.py D Lib/test/test_lib2to3/test_all_fixers.py D Lib/test/test_lib2to3/test_fixers.py D Lib/test/test_lib2to3/test_main.py D Lib/test/test_lib2to3/test_parser.py D Lib/test/test_lib2to3/test_pytree.py D Lib/test/test_lib2to3/test_refactor.py D Lib/test/test_lib2to3/test_util.py D Tools/scripts/2to3 M .gitignore M Doc/glossary.rst M Doc/library/development.rst M Doc/tools/.nitignore M Doc/tools/extensions/pyspecific.py M Doc/whatsnew/3.0.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.13.rst M Doc/whatsnew/3.9.rst M Lib/test/test_tools/test_sundry.py M Mac/BuildScript/scripts/postflight.framework M Mac/Makefile.in M Makefile.pre.in M Misc/NEWS.d/3.11.0a1.rst M Misc/NEWS.d/3.8.0a1.rst M Misc/NEWS.d/3.9.0a3.rst M Misc/NEWS.d/3.9.0a6.rst M PC/layout/main.py M PC/layout/support/props.py M PC/layout/support/python.props M Python/stdlib_module_names.h M Tools/README M Tools/msi/bundle/packagegroups/postinstall.wxs M Tools/msi/lib/lib_files.wxs M Tools/msi/msi.props M Tools/peg_generator/Makefile M Tools/peg_generator/scripts/benchmark.py M Tools/scripts/README M Tools/wasm/wasm_assets.py diff --git a/.gitignore b/.gitignore index ef7642b09bc5d..dddf28da01619 100644 --- a/.gitignore +++ b/.gitignore @@ -61,7 +61,6 @@ Doc/.venv/ Doc/env/ Doc/.env/ Include/pydtrace_probes.h -Lib/lib2to3/*.pickle Lib/site-packages/* !Lib/site-packages/README.txt Lib/test/data/* diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 53e8cdcae1cd6..8c493f823a6fa 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -22,15 +22,6 @@ Glossary * The :const:`Ellipsis` built-in constant. - 2to3 - A tool that tries to convert Python 2.x code to Python 3.x code by - handling most of the incompatibilities which can be detected by parsing the - source and traversing the parse tree. - - 2to3 is available in the standard library as :mod:`lib2to3`; a standalone - entry point is provided as :file:`Tools/scripts/2to3`. See - :ref:`2to3-reference`. - abstract base class Abstract base classes complement :term:`duck-typing` by providing a way to define interfaces when other techniques like diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst deleted file mode 100644 index d85ad94e9b7fe..0000000000000 --- a/Doc/library/2to3.rst +++ /dev/null @@ -1,489 +0,0 @@ -.. _2to3-reference: - -2to3 --- Automated Python 2 to 3 code translation -================================================= - -.. sectionauthor:: Benjamin Peterson <benjamin at python.org> - -2to3 is a Python program that reads Python 2.x source code and applies a series -of *fixers* to transform it into valid Python 3.x code. The standard library -contains a rich set of fixers that will handle almost all code. 2to3 supporting -library :mod:`lib2to3` is, however, a flexible and generic library, so it is -possible to write your own fixers for 2to3. - -.. deprecated-removed:: 3.11 3.13 - The ``lib2to3`` module was marked pending for deprecation in Python 3.9 - (raising :exc:`PendingDeprecationWarning` on import) and fully deprecated - in Python 3.11 (raising :exc:`DeprecationWarning`). The ``2to3`` tool is - part of that. It will be removed in Python 3.13. - -.. _2to3-using: - -Using 2to3 ----------- - -2to3 will usually be installed with the Python interpreter as a script. It is -also located in the :file:`Tools/scripts` directory of the Python root. - -2to3's basic arguments are a list of files or directories to transform. The -directories are recursively traversed for Python sources. - -Here is a sample Python 2.x source file, :file:`example.py`:: - - def greet(name): - print "Hello, {0}!".format(name) - print "What's your name?" - name = raw_input() - greet(name) - -It can be converted to Python 3.x code via 2to3 on the command line: - -.. code-block:: shell-session - - $ 2to3 example.py - -A diff against the original source file is printed. 2to3 can also write the -needed modifications right back to the source file. (A backup of the original -file is made unless :option:`!-n` is also given.) Writing the changes back is -enabled with the :option:`!-w` flag: - -.. code-block:: shell-session - - $ 2to3 -w example.py - -After transformation, :file:`example.py` looks like this:: - - def greet(name): - print("Hello, {0}!".format(name)) - print("What's your name?") - name = input() - greet(name) - -Comments and exact indentation are preserved throughout the translation process. - -By default, 2to3 runs a set of :ref:`predefined fixers <2to3-fixers>`. The -:option:`!-l` flag lists all available fixers. An explicit set of fixers to run -can be given with :option:`!-f`. Likewise the :option:`!-x` explicitly disables a -fixer. The following example runs only the ``imports`` and ``has_key`` fixers: - -.. code-block:: shell-session - - $ 2to3 -f imports -f has_key example.py - -This command runs every fixer except the ``apply`` fixer: - -.. code-block:: shell-session - - $ 2to3 -x apply example.py - -Some fixers are *explicit*, meaning they aren't run by default and must be -listed on the command line to be run. Here, in addition to the default fixers, -the ``idioms`` fixer is run: - -.. code-block:: shell-session - - $ 2to3 -f all -f idioms example.py - -Notice how passing ``all`` enables all default fixers. - -Sometimes 2to3 will find a place in your source code that needs to be changed, -but 2to3 cannot fix automatically. In this case, 2to3 will print a warning -beneath the diff for a file. You should address the warning in order to have -compliant 3.x code. - -2to3 can also refactor doctests. To enable this mode, use the :option:`!-d` -flag. Note that *only* doctests will be refactored. This also doesn't require -the module to be valid Python. For example, doctest like examples in a reST -document could also be refactored with this option. - -The :option:`!-v` option enables output of more information on the translation -process. - -Since some print statements can be parsed as function calls or statements, 2to3 -cannot always read files containing the print function. When 2to3 detects the -presence of the ``from __future__ import print_function`` compiler directive, it -modifies its internal grammar to interpret :func:`print` as a function. This -change can also be enabled manually with the :option:`!-p` flag. Use -:option:`!-p` to run fixers on code that already has had its print statements -converted. Also :option:`!-e` can be used to make :func:`exec` a function. - -The :option:`!-o` or :option:`!--output-dir` option allows specification of an -alternate directory for processed output files to be written to. The -:option:`!-n` flag is required when using this as backup files do not make sense -when not overwriting the input files. - -.. versionadded:: 3.2.3 - The :option:`!-o` option was added. - -The :option:`!-W` or :option:`!--write-unchanged-files` flag tells 2to3 to always -write output files even if no changes were required to the file. This is most -useful with :option:`!-o` so that an entire Python source tree is copied with -translation from one directory to another. -This option implies the :option:`!-w` flag as it would not make sense otherwise. - -.. versionadded:: 3.2.3 - The :option:`!-W` flag was added. - -The :option:`!--add-suffix` option specifies a string to append to all output -filenames. The :option:`!-n` flag is required when specifying this as backups -are not necessary when writing to different filenames. Example: - -.. code-block:: shell-session - - $ 2to3 -n -W --add-suffix=3 example.py - -Will cause a converted file named ``example.py3`` to be written. - -.. versionadded:: 3.2.3 - The :option:`!--add-suffix` option was added. - -To translate an entire project from one directory tree to another use: - -.. code-block:: shell-session - - $ 2to3 --output-dir=python3-version/mycode -W -n python2-version/mycode - - -.. _2to3-fixers: - -Fixers ------- - -Each step of transforming code is encapsulated in a fixer. The command ``2to3 --l`` lists them. As :ref:`documented above <2to3-using>`, each can be turned on -and off individually. They are described here in more detail. - - -.. 2to3fixer:: apply - - Removes usage of :func:`apply`. For example ``apply(function, *args, - **kwargs)`` is converted to ``function(*args, **kwargs)``. - -.. 2to3fixer:: asserts - - Replaces deprecated :mod:`unittest` method names with the correct ones. - - ================================ ========================================== - From To - ================================ ========================================== - ``failUnlessEqual(a, b)`` :meth:`assertEqual(a, b) - <unittest.TestCase.assertEqual>` - ``assertEquals(a, b)`` :meth:`assertEqual(a, b) - <unittest.TestCase.assertEqual>` - ``failIfEqual(a, b)`` :meth:`assertNotEqual(a, b) - <unittest.TestCase.assertNotEqual>` - ``assertNotEquals(a, b)`` :meth:`assertNotEqual(a, b) - <unittest.TestCase.assertNotEqual>` - ``failUnless(a)`` :meth:`assertTrue(a) - <unittest.TestCase.assertTrue>` - ``assert_(a)`` :meth:`assertTrue(a) - <unittest.TestCase.assertTrue>` - ``failIf(a)`` :meth:`assertFalse(a) - <unittest.TestCase.assertFalse>` - ``failUnlessRaises(exc, cal)`` :meth:`assertRaises(exc, cal) - <unittest.TestCase.assertRaises>` - ``failUnlessAlmostEqual(a, b)`` :meth:`assertAlmostEqual(a, b) - <unittest.TestCase.assertAlmostEqual>` - ``assertAlmostEquals(a, b)`` :meth:`assertAlmostEqual(a, b) - <unittest.TestCase.assertAlmostEqual>` - ``failIfAlmostEqual(a, b)`` :meth:`assertNotAlmostEqual(a, b) - <unittest.TestCase.assertNotAlmostEqual>` - ``assertNotAlmostEquals(a, b)`` :meth:`assertNotAlmostEqual(a, b) - <unittest.TestCase.assertNotAlmostEqual>` - ================================ ========================================== - -.. 2to3fixer:: basestring - - Converts :class:`basestring` to :class:`str`. - -.. 2to3fixer:: buffer - - Converts :class:`buffer` to :class:`memoryview`. This fixer is optional - because the :class:`memoryview` API is similar but not exactly the same as - that of :class:`buffer`. - -.. 2to3fixer:: dict - - Fixes dictionary iteration methods. :meth:`dict.iteritems` is converted to - :meth:`dict.items`, :meth:`dict.iterkeys` to :meth:`dict.keys`, and - :meth:`dict.itervalues` to :meth:`dict.values`. Similarly, - :meth:`dict.viewitems`, :meth:`dict.viewkeys` and :meth:`dict.viewvalues` are - converted respectively to :meth:`dict.items`, :meth:`dict.keys` and - :meth:`dict.values`. It also wraps existing usages of :meth:`dict.items`, - :meth:`dict.keys`, and :meth:`dict.values` in a call to :class:`list`. - -.. 2to3fixer:: except - - Converts ``except X, T`` to ``except X as T``. - -.. 2to3fixer:: exec - - Converts the ``exec`` statement to the :func:`exec` function. - -.. 2to3fixer:: execfile - - Removes usage of :func:`execfile`. The argument to :func:`execfile` is - wrapped in calls to :func:`open`, :func:`compile`, and :func:`exec`. - -.. 2to3fixer:: exitfunc - - Changes assignment of :attr:`sys.exitfunc` to use of the :mod:`atexit` - module. - -.. 2to3fixer:: filter - - Wraps :func:`filter` usage in a :class:`list` call. - -.. 2to3fixer:: funcattrs - - Fixes function attributes that have been renamed. For example, - ``my_function.func_closure`` is converted to ``my_function.__closure__``. - -.. 2to3fixer:: future - - Removes ``from __future__ import new_feature`` statements. - -.. 2to3fixer:: getcwdu - - Renames :func:`os.getcwdu` to :func:`os.getcwd`. - -.. 2to3fixer:: has_key - - Changes ``dict.has_key(key)`` to ``key in dict``. - -.. 2to3fixer:: idioms - - This optional fixer performs several transformations that make Python code - more idiomatic. Type comparisons like ``type(x) is SomeClass`` and - ``type(x) == SomeClass`` are converted to ``isinstance(x, SomeClass)``. - ``while 1`` becomes ``while True``. This fixer also tries to make use of - :func:`sorted` in appropriate places. For example, this block :: - - L = list(some_iterable) - L.sort() - - is changed to :: - - L = sorted(some_iterable) - -.. 2to3fixer:: import - - Detects sibling imports and converts them to relative imports. - -.. 2to3fixer:: imports - - Handles module renames in the standard library. - -.. 2to3fixer:: imports2 - - Handles other modules renames in the standard library. It is separate from - the :2to3fixer:`imports` fixer only because of technical limitations. - -.. 2to3fixer:: input - - Converts ``input(prompt)`` to ``eval(input(prompt))``. - -.. 2to3fixer:: intern - - Converts :func:`intern` to :func:`sys.intern`. - -.. 2to3fixer:: isinstance - - Fixes duplicate types in the second argument of :func:`isinstance`. For - example, ``isinstance(x, (int, int))`` is converted to ``isinstance(x, - int)`` and ``isinstance(x, (int, float, int))`` is converted to - ``isinstance(x, (int, float))``. - -.. 2to3fixer:: itertools_imports - - Removes imports of :func:`itertools.ifilter`, :func:`itertools.izip`, and - :func:`itertools.imap`. Imports of :func:`itertools.ifilterfalse` are also - changed to :func:`itertools.filterfalse`. - -.. 2to3fixer:: itertools - - Changes usage of :func:`itertools.ifilter`, :func:`itertools.izip`, and - :func:`itertools.imap` to their built-in equivalents. - :func:`itertools.ifilterfalse` is changed to :func:`itertools.filterfalse`. - -.. 2to3fixer:: long - - Renames :class:`long` to :class:`int`. - -.. 2to3fixer:: map - - Wraps :func:`map` in a :class:`list` call. It also changes ``map(None, x)`` - to ``list(x)``. Using ``from future_builtins import map`` disables this - fixer. - -.. 2to3fixer:: metaclass - - Converts the old metaclass syntax (``__metaclass__ = Meta`` in the class - body) to the new (``class X(metaclass=Meta)``). - -.. 2to3fixer:: methodattrs - - Fixes old method attribute names. For example, ``meth.im_func`` is converted - to ``meth.__func__``. - -.. 2to3fixer:: ne - - Converts the old not-equal syntax, ``<>``, to ``!=``. - -.. 2to3fixer:: next - - Converts the use of iterator's :meth:`~iterator.next` methods to the - :func:`next` function. It also renames :meth:`next` methods to - :meth:`~iterator.__next__`. - -.. 2to3fixer:: nonzero - - Renames definitions of methods called :meth:`__nonzero__` - to :meth:`~object.__bool__`. - -.. 2to3fixer:: numliterals - - Converts octal literals into the new syntax. - -.. 2to3fixer:: operator - - Converts calls to various functions in the :mod:`operator` module to other, - but equivalent, function calls. When needed, the appropriate ``import`` - statements are added, e.g. ``import collections.abc``. The following mapping - are made: - - ================================== ============================================= - From To - ================================== ============================================= - ``operator.isCallable(obj)`` ``callable(obj)`` - ``operator.sequenceIncludes(obj)`` ``operator.contains(obj)`` - ``operator.isSequenceType(obj)`` ``isinstance(obj, collections.abc.Sequence)`` - ``operator.isMappingType(obj)`` ``isinstance(obj, collections.abc.Mapping)`` - ``operator.isNumberType(obj)`` ``isinstance(obj, numbers.Number)`` - ``operator.repeat(obj, n)`` ``operator.mul(obj, n)`` - ``operator.irepeat(obj, n)`` ``operator.imul(obj, n)`` - ================================== ============================================= - -.. 2to3fixer:: paren - - Add extra parenthesis where they are required in list comprehensions. For - example, ``[x for x in 1, 2]`` becomes ``[x for x in (1, 2)]``. - -.. 2to3fixer:: print - - Converts the ``print`` statement to the :func:`print` function. - -.. 2to3fixer:: raise - - Converts ``raise E, V`` to ``raise E(V)``, and ``raise E, V, T`` to ``raise - E(V).with_traceback(T)``. If ``E`` is a tuple, the translation will be - incorrect because substituting tuples for exceptions has been removed in 3.0. - -.. 2to3fixer:: raw_input - - Converts :func:`raw_input` to :func:`input`. - -.. 2to3fixer:: reduce - - Handles the move of :func:`reduce` to :func:`functools.reduce`. - -.. 2to3fixer:: reload - - Converts :func:`reload` to :func:`importlib.reload`. - -.. 2to3fixer:: renames - - Changes :data:`sys.maxint` to :data:`sys.maxsize`. - -.. 2to3fixer:: repr - - Replaces backtick repr with the :func:`repr` function. - -.. 2to3fixer:: set_literal - - Replaces use of the :class:`set` constructor with set literals. This fixer - is optional. - -.. 2to3fixer:: standarderror - - Renames :exc:`StandardError` to :exc:`Exception`. - -.. 2to3fixer:: sys_exc - - Changes the deprecated :data:`sys.exc_value`, :data:`sys.exc_type`, - :data:`sys.exc_traceback` to use :func:`sys.exc_info`. - -.. 2to3fixer:: throw - - Fixes the API change in generator's :meth:`throw` method. - -.. 2to3fixer:: tuple_params - - Removes implicit tuple parameter unpacking. This fixer inserts temporary - variables. - -.. 2to3fixer:: types - - Fixes code broken from the removal of some members in the :mod:`types` - module. - -.. 2to3fixer:: unicode - - Renames :class:`unicode` to :class:`str`. - -.. 2to3fixer:: urllib - - Handles the rename of :mod:`urllib` and :mod:`urllib2` to the :mod:`urllib` - package. - -.. 2to3fixer:: ws_comma - - Removes excess whitespace from comma separated items. This fixer is - optional. - -.. 2to3fixer:: xrange - - Renames :func:`xrange` to :func:`range` and wraps existing :func:`range` - calls with :class:`list`. - -.. 2to3fixer:: xreadlines - - Changes ``for x in file.xreadlines()`` to ``for x in file``. - -.. 2to3fixer:: zip - - Wraps :func:`zip` usage in a :class:`list` call. This is disabled when - ``from future_builtins import zip`` appears. - - -:mod:`lib2to3` --- 2to3's library ---------------------------------- - -.. module:: lib2to3 - :synopsis: The 2to3 library - -.. moduleauthor:: Guido van Rossum -.. moduleauthor:: Collin Winter -.. moduleauthor:: Benjamin Peterson <benjamin at python.org> - -**Source code:** :source:`Lib/lib2to3/` - --------------- - -.. deprecated-removed:: 3.11 3.13 - Python 3.9 switched to a PEG parser (see :pep:`617`) while lib2to3 is - using a less flexible LL(1) parser. Python 3.10 includes new language - syntax that is not parsable by lib2to3's LL(1) parser (see :pep:`634`). - The ``lib2to3`` module was marked pending for deprecation in Python 3.9 - (raising :exc:`PendingDeprecationWarning` on import) and fully deprecated - in Python 3.11 (raising :exc:`DeprecationWarning`). - It will be removed from the standard library in Python 3.13. - Consider third-party alternatives such as `LibCST`_ or `parso`_. - -.. note:: - - The :mod:`lib2to3` API should be considered unstable and may change - drastically in the future. - -.. _LibCST: https://libcst.readthedocs.io/ -.. _parso: https://parso.readthedocs.io/ diff --git a/Doc/library/development.rst b/Doc/library/development.rst index 9edce758688e2..b1979b921e7d5 100644 --- a/Doc/library/development.rst +++ b/Doc/library/development.rst @@ -8,8 +8,7 @@ The modules described in this chapter help you write software. For example, the :mod:`pydoc` module takes a module and generates documentation based on the module's contents. The :mod:`doctest` and :mod:`unittest` modules contains frameworks for writing unit tests that automatically exercise code and verify -that the expected output is produced. :program:`2to3` can translate Python 2.x -source code into valid Python 3.x code. +that the expected output is produced. The list of modules described in this chapter is: @@ -23,5 +22,4 @@ The list of modules described in this chapter is: unittest.rst unittest.mock.rst unittest.mock-examples.rst - 2to3.rst test.rst diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 554e31ff51dd3..7a711031d74e9 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -72,7 +72,6 @@ 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 diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 3a5b26f777961..8a2eb07a69a69 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -710,7 +710,6 @@ def setup(app): app.add_builder(PydocTopicsBuilder) app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command) - app.add_object_type('2to3fixer', '2to3fixer', '%s (2to3 fixer)') app.add_directive_to_domain('py', 'decorator', PyDecoratorFunction) app.add_directive_to_domain('py', 'decoratormethod', PyDecoratorMethod) app.add_directive_to_domain('py', 'coroutinefunction', PyCoroutineFunction) diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index f9ac13036cbc8..b8cd7c48b359b 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -911,7 +911,7 @@ best strategy is the following: tests still pass. 3. Run the ``2to3`` source-to-source translator over your source code - tree. (See :ref:`2to3-reference` for more on this tool.) Run the + tree. Run the result of the translation under Python 3.0. Manually fix up any remaining issues, fixing problems until all tests pass again. diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 1a4a9936aca68..8aadc2a0a581f 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1748,7 +1748,7 @@ Modules warnings have now been updated to note they will be removed in Python 3.12. (Contributed by Hugo van Kemenade in :issue:`47022`.) -* The :mod:`lib2to3` package and :ref:`2to3 <2to3-reference>` tool +* The :mod:`!lib2to3` package and ``2to3`` tool are now deprecated and may not be able to parse Python 3.10 or newer. See :pep:`617`, introducing the new PEG parser, for details. (Contributed by Victor Stinner in :issue:`40360`.) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 602a865b5930e..e0c3c2a3592ec 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -107,6 +107,10 @@ Removed `Exscript <https://pypi.org/project/Exscript/>`_ instead. (Contributed by Victor Stinner in :gh:`104773`.) +* Remove the ``2to3`` program and the :mod:`!lib2to3` module, + deprecated in Python 3.11. + (Contributed by Victor Stinner in :gh:`104780`.) + * Namespaces ``typing.io`` and ``typing.re``, deprecated in Python 3.8, are now removed. The items in those namespaces can be imported directly from :mod:`typing`. (Contributed by Sebastian Rittau in :gh:`92871`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index fd86db9630235..532cabdd7a75b 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -935,10 +935,10 @@ Deprecated * :func:`smtpd.MailmanProxy` is now deprecated as it is unusable without an external module, ``mailman``. (Contributed by Samuel Colvin in :issue:`35800`.) -* The :mod:`lib2to3` module now emits a :exc:`PendingDeprecationWarning`. +* The :mod:`!lib2to3` module now emits a :exc:`PendingDeprecationWarning`. Python 3.9 switched to a PEG parser (see :pep:`617`), and Python 3.10 may include new language syntax that is not parsable by lib2to3's LL(1) parser. - The ``lib2to3`` module may be removed from the standard library in a future + The :mod:`!lib2to3` module may be removed from the standard library in a future Python version. Consider third-party alternatives such as `LibCST`_ or `parso`_. (Contributed by Carl Meyer in :issue:`40360`.) diff --git a/Lib/lib2to3/Grammar.txt b/Lib/lib2to3/Grammar.txt deleted file mode 100644 index fa7b15061d941..0000000000000 --- a/Lib/lib2to3/Grammar.txt +++ /dev/null @@ -1,196 +0,0 @@ -# Grammar for 2to3. This grammar supports Python 2.x and 3.x. - -# NOTE WELL: You should also follow all the steps listed at -# https://devguide.python.org/grammar/ - -# Start symbols for the grammar: -# file_input is a module or sequence of commands read from an input file; -# single_input is a single interactive statement; -# eval_input is the input for the eval() and input() functions. -# NB: compound_stmt in single_input is followed by extra NEWLINE! -file_input: (NEWLINE | stmt)* ENDMARKER -single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE -eval_input: testlist NEWLINE* ENDMARKER - -decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE -decorators: decorator+ -decorated: decorators (classdef | funcdef | async_funcdef) -async_funcdef: ASYNC funcdef -funcdef: 'def' NAME parameters ['->' test] ':' suite -parameters: '(' [typedargslist] ')' - -# The following definition for typedarglist is equivalent to this set of rules: -# -# arguments = argument (',' argument)* -# argument = tfpdef ['=' test] -# kwargs = '**' tname [','] -# args = '*' [tname] -# kwonly_kwargs = (',' argument)* [',' [kwargs]] -# args_kwonly_kwargs = args kwonly_kwargs | kwargs -# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] -# typedargslist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs -# typedarglist = arguments ',' '/' [',' [typedargslist_no_posonly]])|(typedargslist_no_posonly)" -# -# It needs to be fully expanded to allow our LL(1) parser to work on it. - -typedargslist: tfpdef ['=' test] (',' tfpdef ['=' test])* ',' '/' [ - ',' [((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])* - [',' ['**' tname [',']]] | '**' tname [',']) - | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])] - ] | ((tfpdef ['=' test] ',')* ('*' [tname] (',' tname ['=' test])* - [',' ['**' tname [',']]] | '**' tname [',']) - | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) - -tname: NAME [':' test] -tfpdef: tname | '(' tfplist ')' -tfplist: tfpdef (',' tfpdef)* [','] - -# The following definition for varargslist is equivalent to this set of rules: -# -# arguments = argument (',' argument )* -# argument = vfpdef ['=' test] -# kwargs = '**' vname [','] -# args = '*' [vname] -# kwonly_kwargs = (',' argument )* [',' [kwargs]] -# args_kwonly_kwargs = args kwonly_kwargs | kwargs -# poskeyword_args_kwonly_kwargs = arguments [',' [args_kwonly_kwargs]] -# vararglist_no_posonly = poskeyword_args_kwonly_kwargs | args_kwonly_kwargs -# varargslist = arguments ',' '/' [','[(vararglist_no_posonly)]] | (vararglist_no_posonly) -# -# It needs to be fully expanded to allow our LL(1) parser to work on it. - -varargslist: vfpdef ['=' test ](',' vfpdef ['=' test])* ',' '/' [',' [ - ((vfpdef ['=' test] ',')* ('*' [vname] (',' vname ['=' test])* - [',' ['**' vname [',']]] | '**' vname [',']) - | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) - ]] | ((vfpdef ['=' test] ',')* - ('*' [vname] (',' vname ['=' test])* [',' ['**' vname [',']]]| '**' vname [',']) - | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) - -vname: NAME -vfpdef: vname | '(' vfplist ')' -vfplist: vfpdef (',' vfpdef)* [','] - -stmt: simple_stmt | compound_stmt -simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE -small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | - import_stmt | global_stmt | exec_stmt | assert_stmt) -expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | - ('=' (yield_expr|testlist_star_expr))*) -annassign: ':' test ['=' test] -testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [','] -augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | - '<<=' | '>>=' | '**=' | '//=') -# For normal and annotated assignments, additional restrictions enforced by the interpreter -print_stmt: 'print' ( [ test (',' test)* [','] ] | - '>>' test [ (',' test)+ [','] ] ) -del_stmt: 'del' exprlist -pass_stmt: 'pass' -flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt -break_stmt: 'break' -continue_stmt: 'continue' -return_stmt: 'return' [testlist_star_expr] -yield_stmt: yield_expr -raise_stmt: 'raise' [test ['from' test | ',' test [',' test]]] -import_stmt: import_name | import_from -import_name: 'import' dotted_as_names -import_from: ('from' ('.'* dotted_name | '.'+) - 'import' ('*' | '(' import_as_names ')' | import_as_names)) -import_as_name: NAME ['as' NAME] -dotted_as_name: dotted_name ['as' NAME] -import_as_names: import_as_name (',' import_as_name)* [','] -dotted_as_names: dotted_as_name (',' dotted_as_name)* -dotted_name: NAME ('.' NAME)* -global_stmt: ('global' | 'nonlocal') NAME (',' NAME)* -exec_stmt: 'exec' expr ['in' test [',' test]] -assert_stmt: 'assert' test [',' test] - -compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt -async_stmt: ASYNC (funcdef | with_stmt | for_stmt) -if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite] -while_stmt: 'while' namedexpr_test ':' suite ['else' ':' suite] -for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] -try_stmt: ('try' ':' suite - ((except_clause ':' suite)+ - ['else' ':' suite] - ['finally' ':' suite] | - 'finally' ':' suite)) -with_stmt: 'with' with_item (',' with_item)* ':' suite -with_item: test ['as' expr] -with_var: 'as' expr -# NB compile.c makes sure that the default except clause is last -except_clause: 'except' [test [(',' | 'as') test]] -suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT - -# Backward compatibility cruft to support: -# [ x for x in lambda: True, lambda: False if x() ] -# even while also allowing: -# lambda x: 5 if x else 2 -# (But not a mix of the two) -testlist_safe: old_test [(',' old_test)+ [',']] -old_test: or_test | old_lambdef -old_lambdef: 'lambda' [varargslist] ':' old_test - -namedexpr_test: test [':=' test] -test: or_test ['if' or_test 'else' test] | lambdef -or_test: and_test ('or' and_test)* -and_test: not_test ('and' not_test)* -not_test: 'not' not_test | comparison -comparison: expr (comp_op expr)* -comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' -star_expr: '*' expr -expr: xor_expr ('|' xor_expr)* -xor_expr: and_expr ('^' and_expr)* -and_expr: shift_expr ('&' shift_expr)* -shift_expr: arith_expr (('<<'|'>>') arith_expr)* -arith_expr: term (('+'|'-') term)* -term: factor (('*'|'@'|'/'|'%'|'//') factor)* -factor: ('+'|'-'|'~') factor | power -power: [AWAIT] atom trailer* ['**' factor] -atom: ('(' [yield_expr|testlist_gexp] ')' | - '[' [listmaker] ']' | - '{' [dictsetmaker] '}' | - '`' testlist1 '`' | - NAME | NUMBER | STRING+ | '.' '.' '.') -listmaker: (namedexpr_test|star_expr) ( comp_for | (',' (namedexpr_test|star_expr))* [','] ) -testlist_gexp: (namedexpr_test|star_expr) ( comp_for | (',' (namedexpr_test|star_expr))* [','] ) -lambdef: 'lambda' [varargslist] ':' test -trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME -subscriptlist: subscript (',' subscript)* [','] -subscript: test | [test] ':' [test] [sliceop] -sliceop: ':' [test] -exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] -testlist: test (',' test)* [','] -dictsetmaker: ( ((test ':' test | '**' expr) - (comp_for | (',' (test ':' test | '**' expr))* [','])) | - ((test | star_expr) - (comp_for | (',' (test | star_expr))* [','])) ) - -classdef: 'class' NAME ['(' [arglist] ')'] ':' suite - -arglist: argument (',' argument)* [','] - -# "test '=' test" is really "keyword '=' test", but we have no such token. -# These need to be in a single rule to avoid grammar that is ambiguous -# to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, -# we explicitly match '*' here, too, to give it proper precedence. -# Illegal combinations and orderings are blocked in ast.c: -# multiple (test comp_for) arguments are blocked; keyword unpackings -# that precede iterable unpackings are blocked; etc. -argument: ( test [comp_for] | - test ':=' test | - test '=' test | - '**' test | - '*' test ) - -comp_iter: comp_for | comp_if -comp_for: [ASYNC] 'for' exprlist 'in' testlist_safe [comp_iter] -comp_if: 'if' old_test [comp_iter] - -testlist1: test (',' test)* - -# not used in grammar, but may appear in "node" passed from Parser to Compiler -encoding_decl: NAME - -yield_expr: 'yield' [yield_arg] -yield_arg: 'from' test | testlist_star_expr diff --git a/Lib/lib2to3/PatternGrammar.txt b/Lib/lib2to3/PatternGrammar.txt deleted file mode 100644 index 36bf8148273bd..0000000000000 --- a/Lib/lib2to3/PatternGrammar.txt +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -# A grammar to describe tree matching patterns. -# Not shown here: -# - 'TOKEN' stands for any token (leaf node) -# - 'any' stands for any node (leaf or interior) -# With 'any' we can still specify the sub-structure. - -# The start symbol is 'Matcher'. - -Matcher: Alternatives ENDMARKER - -Alternatives: Alternative ('|' Alternative)* - -Alternative: (Unit | NegatedUnit)+ - -Unit: [NAME '='] ( STRING [Repeater] - | NAME [Details] [Repeater] - | '(' Alternatives ')' [Repeater] - | '[' Alternatives ']' - ) - -NegatedUnit: 'not' (STRING | NAME [Details] | '(' Alternatives ')') - -Repeater: '*' | '+' | '{' NUMBER [',' NUMBER] '}' - -Details: '<' Alternatives '>' diff --git a/Lib/lib2to3/__init__.py b/Lib/lib2to3/__init__.py deleted file mode 100644 index 177405c8090d3..0000000000000 --- a/Lib/lib2to3/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -import warnings - - -warnings.warn( - "lib2to3 package is deprecated and may not be able to parse Python 3.10+", - DeprecationWarning, - stacklevel=2, -) diff --git a/Lib/lib2to3/__main__.py b/Lib/lib2to3/__main__.py deleted file mode 100644 index 80688baf27abf..0000000000000 --- a/Lib/lib2to3/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -import sys -from .main import main - -sys.exit(main("lib2to3.fixes")) diff --git a/Lib/lib2to3/btm_matcher.py b/Lib/lib2to3/btm_matcher.py deleted file mode 100644 index 3b78868038bda..0000000000000 --- a/Lib/lib2to3/btm_matcher.py +++ /dev/null @@ -1,163 +0,0 @@ -"""A bottom-up tree matching algorithm implementation meant to speed -up 2to3's matching process. After the tree patterns are reduced to -their rarest linear path, a linear Aho-Corasick automaton is -created. The linear automaton traverses the linear paths from the -leaves to the root of the AST and returns a set of nodes for further -matching. This reduces significantly the number of candidate nodes.""" - -__author__ = "George Boutsioukis <gboutsioukis at gmail.com>" - -import logging -import itertools -from collections import defaultdict - -from . import pytree -from .btm_utils import reduce_tree - -class BMNode(object): - """Class for a node of the Aho-Corasick automaton used in matching""" - count = itertools.count() - def __init__(self): - self.transition_table = {} - self.fixers = [] - self.id = next(BMNode.count) - self.content = '' - -class BottomMatcher(object): - """The main matcher class. After instantiating the patterns should - be added using the add_fixer method""" - - def __init__(self): - self.match = set() - self.root = BMNode() - self.nodes = [self.root] - self.fixers = [] - self.logger = logging.getLogger("RefactoringTool") - - def add_fixer(self, fixer): - """Reduces a fixer's pattern tree to a linear path and adds it - to the matcher(a common Aho-Corasick automaton). The fixer is - appended on the matching states and called when they are - reached""" - self.fixers.append(fixer) - tree = reduce_tree(fixer.pattern_tree) - linear = tree.get_linear_subpattern() - match_nodes = self.add(linear, start=self.root) - for match_node in match_nodes: - match_node.fixers.append(fixer) - - def add(self, pattern, start): - "Recursively adds a linear pattern to the AC automaton" - #print("adding pattern", pattern, "to", start) - if not pattern: - #print("empty pattern") - return [start] - if isinstance(pattern[0], tuple): - #alternatives - #print("alternatives") - match_nodes = [] - for alternative in pattern[0]: - #add all alternatives, and add the rest of the pattern - #to each end node - end_nodes = self.add(alternative, start=start) - for end in end_nodes: - match_nodes.extend(self.add(pattern[1:], end)) - return match_nodes - else: - #single token - #not last - if pattern[0] not in start.transition_table: - #transition did not exist, create new - next_node = BMNode() - start.transition_table[pattern[0]] = next_node - else: - #transition exists already, follow - next_node = start.transition_table[pattern[0]] - - if pattern[1:]: - end_nodes = self.add(pattern[1:], start=next_node) - else: - end_nodes = [next_node] - return end_nodes - - def run(self, leaves): - """The main interface with the bottom matcher. The tree is - traversed from the bottom using the constructed - automaton. Nodes are only checked once as the tree is - retraversed. When the automaton fails, we give it one more - shot(in case the above tree matches as a whole with the - rejected leaf), then we break for the next leaf. There is the - special case of multiple arguments(see code comments) where we - recheck the nodes - - Args: - The leaves of the AST tree to be matched - - Returns: - A dictionary of node matches with fixers as the keys - """ - current_ac_node = self.root - results = defaultdict(list) - for leaf in leaves: - current_ast_node = leaf - while current_ast_node: - current_ast_node.was_checked = True - for child in current_ast_node.children: - # multiple statements, recheck - if isinstance(child, pytree.Leaf) and child.value == ";": - current_ast_node.was_checked = False - break - if current_ast_node.type == 1: - #name - node_token = current_ast_node.value - else: - node_token = current_ast_node.type - - if node_token in current_ac_node.transition_table: - #token matches - current_ac_node = current_ac_node.transition_table[node_token] - for fixer in current_ac_node.fixers: - results[fixer].append(current_ast_node) - else: - #matching failed, reset automaton - current_ac_node = self.root - if (current_ast_node.parent is not None - and current_ast_node.parent.was_checked): - #the rest of the tree upwards has been checked, next leaf - break - - #recheck the rejected node once from the root - if node_token in current_ac_node.transition_table: - #token matches - current_ac_node = current_ac_node.transition_table[node_token] - for fixer in current_ac_node.fixers: - results[fixer].append(current_ast_node) - - current_ast_node = current_ast_node.parent - return results - - def print_ac(self): - "Prints a graphviz diagram of the BM automaton(for debugging)" - print("digraph g{") - def print_node(node): - for subnode_key in node.transition_table.keys(): - subnode = node.transition_table[subnode_key] - print("%d -> %d [label=%s] //%s" % - (node.id, subnode.id, type_repr(subnode_key), str(subnode.fixers))) - if subnode_key == 1: - print(subnode.content) - print_node(subnode) - print_node(self.root) - print("}") - -# taken from pytree.py for debugging; only used by print_ac -_type_reprs = {} -def type_repr(type_num): - global _type_reprs - if not _type_reprs: - from .pygram import python_symbols - # printing tokens is possible but not as useful - # from .pgen2 import token // token.__dict__.items(): - for name, val in python_symbols.__dict__.items(): - if type(val) == int: _type_reprs[val] = name - return _type_reprs.setdefault(type_num, type_num) diff --git a/Lib/lib2to3/btm_utils.py b/Lib/lib2to3/btm_utils.py deleted file mode 100644 index b61afdba69307..0000000000000 --- a/Lib/lib2to3/btm_utils.py +++ /dev/null @@ -1,280 +0,0 @@ -"Utility functions used by the btm_matcher module" - -from . import pytree -from .pgen2 import grammar, token -from .pygram import pattern_symbols, python_symbols - -syms = pattern_symbols -pysyms = python_symbols -tokens = grammar.opmap -token_labels = token - -TYPE_ANY = -1 -TYPE_ALTERNATIVES = -2 -TYPE_GROUP = -3 - -class MinNode(object): - """This class serves as an intermediate representation of the - pattern tree during the conversion to sets of leaf-to-root - subpatterns""" - - def __init__(self, type=None, name=None): - self.type = type - self.name = name - self.children = [] - self.leaf = False - self.parent = None - self.alternatives = [] - self.group = [] - - def __repr__(self): - return str(self.type) + ' ' + str(self.name) - - def leaf_to_root(self): - """Internal method. Returns a characteristic path of the - pattern tree. This method must be run for all leaves until the - linear subpatterns are merged into a single""" - node = self - subp = [] - while node: - if node.type == TYPE_ALTERNATIVES: - node.alternatives.append(subp) - if len(node.alternatives) == len(node.children): - #last alternative - subp = [tuple(node.alternatives)] - node.alternatives = [] - node = node.parent - continue - else: - node = node.parent - subp = None - break - - if node.type == TYPE_GROUP: - node.group.append(subp) - #probably should check the number of leaves - if len(node.group) == len(node.children): - subp = get_characteristic_subpattern(node.group) - node.group = [] - node = node.parent - continue - else: - node = node.parent - subp = None - break - - if node.type == token_labels.NAME and node.name: - #in case of type=name, use the name instead - subp.append(node.name) - else: - subp.append(node.type) - - node = node.parent - return subp - - def get_linear_subpattern(self): - """Drives the leaf_to_root method. The reason that - leaf_to_root must be run multiple times is because we need to - reject 'group' matches; for example the alternative form - (a | b c) creates a group [b c] that needs to be matched. Since - matching multiple linear patterns overcomes the automaton's - capabilities, leaf_to_root merges each group into a single - choice based on 'characteristic'ity, - - i.e. (a|b c) -> (a|b) if b more characteristic than c - - Returns: The most 'characteristic'(as defined by - get_characteristic_subpattern) path for the compiled pattern - tree. - """ - - for l in self.leaves(): - subp = l.leaf_to_root() - if subp: - return subp - - def leaves(self): - "Generator that returns the leaves of the tree" - for child in self.children: - yield from child.leaves() - if not self.children: - yield self - -def reduce_tree(node, parent=None): - """ - Internal function. Reduces a compiled pattern tree to an - intermediate representation suitable for feeding the - automaton. This also trims off any optional pattern elements(like - [a], a*). - """ - - new_node = None - #switch on the node type - if node.type == syms.Matcher: - #skip - node = node.children[0] - - if node.type == syms.Alternatives : - #2 cases - if len(node.children) <= 2: - #just a single 'Alternative', skip this node - new_node = reduce_tree(node.children[0], parent) - else: - #real alternatives - new_node = MinNode(type=TYPE_ALTERNATIVES) - #skip odd children('|' tokens) - for child in node.children: - if node.children.index(child)%2: - continue - reduced = reduce_tree(child, new_node) - if reduced is not None: - new_node.children.append(reduced) - elif node.type == syms.Alternative: - if len(node.children) > 1: - - new_node = MinNode(type=TYPE_GROUP) - for child in node.children: - reduced = reduce_tree(child, new_node) - if reduced: - new_node.children.append(reduced) - if not new_node.children: - # delete the group if all of the children were reduced to None - new_node = None - - else: - new_node = reduce_tree(node.children[0], parent) - - elif node.type == syms.Unit: - if (isinstance(node.children[0], pytree.Leaf) and - node.children[0].value == '('): - #skip parentheses - return reduce_tree(node.children[1], parent) - if ((isinstance(node.children[0], pytree.Leaf) and - node.children[0].value == '[') - or - (len(node.children)>1 and - hasattr(node.children[1], "value") and - node.children[1].value == '[')): - #skip whole unit if its optional - return None - - leaf = True - details_node = None - alternatives_node = None - has_repeater = False - repeater_node = None - has_variable_name = False - - for child in node.children: - if child.type == syms.Details: - leaf = False - details_node = child - elif child.type == syms.Repeater: - has_repeater = True - repeater_node = child - elif child.type == syms.Alternatives: - alternatives_node = child - if hasattr(child, 'value') and child.value == '=': # variable name - has_variable_name = True - - #skip variable name - if has_variable_name: - #skip variable name, '=' - name_leaf = node.children[2] - if hasattr(name_leaf, 'value') and name_leaf.value == '(': - # skip parenthesis - name_leaf = node.children[3] - else: - name_leaf = node.children[0] - - #set node type - if name_leaf.type == token_labels.NAME: - #(python) non-name or wildcard - if name_leaf.value == 'any': - new_node = MinNode(type=TYPE_ANY) - else: - if hasattr(token_labels, name_leaf.value): - new_node = MinNode(type=getattr(token_labels, name_leaf.value)) - else: - new_node = MinNode(type=getattr(pysyms, name_leaf.value)) - - elif name_leaf.type == token_labels.STRING: - #(python) name or character; remove the apostrophes from - #the string value - name = name_leaf.value.strip("'") - if name in tokens: - new_node = MinNode(type=tokens[name]) - else: - new_node = MinNode(type=token_labels.NAME, name=name) - elif name_leaf.type == syms.Alternatives: - new_node = reduce_tree(alternatives_node, parent) - - #handle repeaters - if has_repeater: - if repeater_node.children[0].value == '*': - #reduce to None - new_node = None - elif repeater_node.children[0].value == '+': - #reduce to a single occurrence i.e. do nothing - pass - else: - #TODO: handle {min, max} repeaters - raise NotImplementedError - - #add children - if details_node and new_node is not None: - for child in details_node.children[1:-1]: - #skip '<', '>' markers - reduced = reduce_tree(child, new_node) - if reduced is not None: - new_node.children.append(reduced) - if new_node: - new_node.parent = parent - return new_node - - -def get_characteristic_subpattern(subpatterns): - """Picks the most characteristic from a list of linear patterns - Current order used is: - names > common_names > common_chars - """ - if not isinstance(subpatterns, list): - return subpatterns - if len(subpatterns)==1: - return subpatterns[0] - - # first pick out the ones containing variable names - subpatterns_with_names = [] - subpatterns_with_common_names = [] - common_names = ['in', 'for', 'if' , 'not', 'None'] - subpatterns_with_common_chars = [] - common_chars = "[]().,:" - for subpattern in subpatterns: - if any(rec_test(subpattern, lambda x: type(x) is str)): - if any(rec_test(subpattern, - lambda x: isinstance(x, str) and x in common_chars)): - subpatterns_with_common_chars.append(subpattern) - elif any(rec_test(subpattern, - lambda x: isinstance(x, str) and x in common_names)): - subpatterns_with_common_names.append(subpattern) - - else: - subpatterns_with_names.append(subpattern) - - if subpatterns_with_names: - subpatterns = subpatterns_with_names - elif subpatterns_with_common_names: - subpatterns = subpatterns_with_common_names - elif subpatterns_with_common_chars: - subpatterns = subpatterns_with_common_chars - # of the remaining subpatterns pick out the longest one - return max(subpatterns, key=len) - -def rec_test(sequence, test_func): - """Tests test_func on all items of sequence and items of included - sub-iterables""" - for x in sequence: - if isinstance(x, (list, tuple)): - yield from rec_test(x, test_func) - else: - yield test_func(x) diff --git a/Lib/lib2to3/fixer_base.py b/Lib/lib2to3/fixer_base.py deleted file mode 100644 index df581a4deab9e..0000000000000 --- a/Lib/lib2to3/fixer_base.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Base class for fixers (optional, but recommended).""" - -# Python imports -import itertools - -# Local imports -from .patcomp import PatternCompiler -from . import pygram -from .fixer_util import does_tree_import - -class BaseFix(object): - - """Optional base class for fixers. - - The subclass name must be FixFooBar where FooBar is the result of - removing underscores and capitalizing the words of the fix name. - For example, the class name for a fixer named 'has_key' should be - FixHasKey. - """ - - PATTERN = None # Most subclasses should override with a string literal - pattern = None # Compiled pattern, set by compile_pattern() - pattern_tree = None # Tree representation of the pattern - options = None # Options object passed to initializer - filename = None # The filename (set by set_filename) - numbers = itertools.count(1) # For new_name() - used_names = set() # A set of all used NAMEs - order = "post" # Does the fixer prefer pre- or post-order traversal - explicit = False # Is this ignored by refactor.py -f all? - run_order = 5 # Fixers will be sorted by run order before execution - # Lower numbers will be run first. - _accept_type = None # [Advanced and not public] This tells RefactoringTool - # which node type to accept when there's not a pattern. - - keep_line_order = False # For the bottom matcher: match with the - # original line order - BM_compatible = False # Compatibility with the bottom matching - # module; every fixer should set this - # manually - - # Shortcut for access to Python grammar symbols - syms = pygram.python_symbols - - def __init__(self, options, log): - """Initializer. Subclass may override. - - Args: - options: a dict containing the options passed to RefactoringTool - that could be used to customize the fixer through the command line. - log: a list to append warnings and other messages to. - """ - self.options = options - self.log = log - self.compile_pattern() - - def compile_pattern(self): - """Compiles self.PATTERN into self.pattern. - - Subclass may override if it doesn't want to use - self.{pattern,PATTERN} in .match(). - """ - if self.PATTERN is not None: - PC = PatternCompiler() - self.pattern, self.pattern_tree = PC.compile_pattern(self.PATTERN, - with_tree=True) - - def set_filename(self, filename): - """Set the filename. - - The main refactoring tool should call this. - """ - self.filename = filename - - def match(self, node): - """Returns match for a given parse tree node. - - Should return a true or false object (not necessarily a bool). - It may return a non-empty dict of matching sub-nodes as - returned by a matching pattern. - - Subclass may override. - """ - results = {"node": node} - return self.pattern.match(node, results) and results - - def transform(self, node, results): - """Returns the transformation for a given parse tree node. - - Args: - node: the root of the parse tree that matched the fixer. - results: a dict mapping symbolic names to part of the match. - - Returns: - None, or a node that is a modified copy of the - argument node. The node argument may also be modified in-place to - effect the same change. - - Subclass *must* override. - """ - raise NotImplementedError() - - def new_name(self, template="xxx_todo_changeme"): - """Return a string suitable for use as an identifier - - The new name is guaranteed not to conflict with other identifiers. - """ - name = template - while name in self.used_names: - name = template + str(next(self.numbers)) - self.used_names.add(name) - return name - - def log_message(self, message): - if self.first_log: - self.first_log = False - self.log.append("### In file %s ###" % self.filename) - self.log.append(message) - - def cannot_convert(self, node, reason=None): - """Warn the user that a given chunk of code is not valid Python 3, - but that it cannot be converted automatically. - - First argument is the top-level node for the code in question. - Optional second argument is why it can't be converted. - """ - lineno = node.get_lineno() - for_output = node.clone() - for_output.prefix = "" - msg = "Line %d: could not convert: %s" - self.log_message(msg % (lineno, for_output)) - if reason: - self.log_message(reason) - - def warning(self, node, reason): - """Used for warning the user about possible uncertainty in the - translation. - - First argument is the top-level node for the code in question. - Optional second argument is why it can't be converted. - """ - lineno = node.get_lineno() - self.log_message("Line %d: %s" % (lineno, reason)) - - def start_tree(self, tree, filename): - """Some fixers need to maintain tree-wide state. - This method is called once, at the start of tree fix-up. - - tree - the root node of the tree to be processed. - filename - the name of the file the tree came from. - """ - self.used_names = tree.used_names - self.set_filename(filename) - self.numbers = itertools.count(1) - self.first_log = True - - def finish_tree(self, tree, filename): - """Some fixers need to maintain tree-wide state. - This method is called once, at the conclusion of tree fix-up. - - tree - the root node of the tree to be processed. - filename - the name of the file the tree came from. - """ - pass - - -class ConditionalFix(BaseFix): - """ Base class for fixers which not execute if an import is found. """ - - # This is the name of the import which, if found, will cause the test to be skipped - skip_on = None - - def start_tree(self, *args): - super(ConditionalFix, self).start_tree(*args) - self._should_skip = None - - def should_skip(self, node): - if self._should_skip is not None: - return self._should_skip - pkg = self.skip_on.split(".") - name = pkg[-1] - pkg = ".".join(pkg[:-1]) - self._should_skip = does_tree_import(pkg, name, node) - return self._should_skip diff --git a/Lib/lib2to3/fixer_util.py b/Lib/lib2to3/fixer_util.py deleted file mode 100644 index c2a3a47f50328..0000000000000 --- a/Lib/lib2to3/fixer_util.py +++ /dev/null @@ -1,453 +0,0 @@ -"""Utility functions, node construction macros, etc.""" -# Author: Collin Winter - -# Local imports -from .pgen2 import token -from .pytree import Leaf, Node -from .pygram import python_symbols as syms -from . import patcomp - - -########################################################### -### Common node-construction "macros" -########################################################### - -def KeywordArg(keyword, value): - return Node(syms.argument, - [keyword, Leaf(token.EQUAL, "="), value]) - -def LParen(): - return Leaf(token.LPAR, "(") - -def RParen(): - return Leaf(token.RPAR, ")") - -def Assign(target, source): - """Build an assignment statement""" - if not isinstance(target, list): - target = [target] - if not isinstance(source, list): - source.prefix = " " - source = [source] - - return Node(syms.atom, - target + [Leaf(token.EQUAL, "=", prefix=" ")] + source) - -def Name(name, prefix=None): - """Return a NAME leaf""" - return Leaf(token.NAME, name, prefix=prefix) - -def Attr(obj, attr): - """A node tuple for obj.attr""" - return [obj, Node(syms.trailer, [Dot(), attr])] - -def Comma(): - """A comma leaf""" - return Leaf(token.COMMA, ",") - -def Dot(): - """A period (.) leaf""" - return Leaf(token.DOT, ".") - -def ArgList(args, lparen=LParen(), rparen=RParen()): - """A parenthesised argument list, used by Call()""" - node = Node(syms.trailer, [lparen.clone(), rparen.clone()]) - if args: - node.insert_child(1, Node(syms.arglist, args)) - return node - -def Call(func_name, args=None, prefix=None): - """A function call""" - node = Node(syms.power, [func_name, ArgList(args)]) - if prefix is not None: - node.prefix = prefix - return node - -def Newline(): - """A newline literal""" - return Leaf(token.NEWLINE, "\n") - -def BlankLine(): - """A blank line""" - return Leaf(token.NEWLINE, "") - -def Number(n, prefix=None): - return Leaf(token.NUMBER, n, prefix=prefix) - -def Subscript(index_node): - """A numeric or string subscript""" - return Node(syms.trailer, [Leaf(token.LBRACE, "["), - index_node, - Leaf(token.RBRACE, "]")]) - -def String(string, prefix=None): - """A string leaf""" - return Leaf(token.STRING, string, prefix=prefix) - -def ListComp(xp, fp, it, test=None): - """A list comprehension of the form [xp for fp in it if test]. - - If test is None, the "if test" part is omitted. - """ - xp.prefix = "" - fp.prefix = " " - it.prefix = " " - for_leaf = Leaf(token.NAME, "for") - for_leaf.prefix = " " - in_leaf = Leaf(token.NAME, "in") - in_leaf.prefix = " " - inner_args = [for_leaf, fp, in_leaf, it] - if test: - test.prefix = " " - if_leaf = Leaf(token.NAME, "if") - if_leaf.prefix = " " - inner_args.append(Node(syms.comp_if, [if_leaf, test])) - inner = Node(syms.listmaker, [xp, Node(syms.comp_for, inner_args)]) - return Node(syms.atom, - [Leaf(token.LBRACE, "["), - inner, - Leaf(token.RBRACE, "]")]) - -def FromImport(package_name, name_leafs): - """ Return an import statement in the form: - from package import name_leafs""" - # XXX: May not handle dotted imports properly (eg, package_name='foo.bar') - #assert package_name == '.' or '.' not in package_name, "FromImport has "\ - # "not been tested with dotted package names -- use at your own "\ - # "peril!" - - for leaf in name_leafs: - # Pull the leaves out of their old tree - leaf.remove() - - children = [Leaf(token.NAME, "from"), - Leaf(token.NAME, package_name, prefix=" "), - Leaf(token.NAME, "import", prefix=" "), - Node(syms.import_as_names, name_leafs)] - imp = Node(syms.import_from, children) - return imp - -def ImportAndCall(node, results, names): - """Returns an import statement and calls a method - of the module: - - import module - module.name()""" - obj = results["obj"].clone() - if obj.type == syms.arglist: - newarglist = obj.clone() - else: - newarglist = Node(syms.arglist, [obj.clone()]) - after = results["after"] - if after: - after = [n.clone() for n in after] - new = Node(syms.power, - Attr(Name(names[0]), Name(names[1])) + - [Node(syms.trailer, - [results["lpar"].clone(), - newarglist, - results["rpar"].clone()])] + after) - new.prefix = node.prefix - return new - - -########################################################### -### Determine whether a node represents a given literal -########################################################### - -def is_tuple(node): - """Does the node represent a tuple literal?""" - if isinstance(node, Node) and node.children == [LParen(), RParen()]: - return True - return (isinstance(node, Node) - and len(node.children) == 3 - and isinstance(node.children[0], Leaf) - and isinstance(node.children[1], Node) - and isinstance(node.children[2], Leaf) - and node.children[0].value == "(" - and node.children[2].value == ")") - -def is_list(node): - """Does the node represent a list literal?""" - return (isinstance(node, Node) - and len(node.children) > 1 - and isinstance(node.children[0], Leaf) - and isinstance(node.children[-1], Leaf) - and node.children[0].value == "[" - and node.children[-1].value == "]") - - -########################################################### -### Misc -########################################################### - -def parenthesize(node): - return Node(syms.atom, [LParen(), node, RParen()]) - - -consuming_calls = {"sorted", "list", "set", "any", "all", "tuple", "sum", - "min", "max", "enumerate"} - -def attr_chain(obj, attr): - """Follow an attribute chain. - - If you have a chain of objects where a.foo -> b, b.foo-> c, etc, - use this to iterate over all objects in the chain. Iteration is - terminated by getattr(x, attr) is None. - - Args: - obj: the starting object - attr: the name of the chaining attribute - - Yields: - Each successive object in the chain. - """ - next = getattr(obj, attr) - while next: - yield next - next = getattr(next, attr) - -p0 = """for_stmt< 'for' any 'in' node=any ':' any* > - | comp_for< 'for' any 'in' node=any any* > - """ -p1 = """ -power< - ( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' | - 'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) ) - trailer< '(' node=any ')' > - any* -> -""" -p2 = """ -power< - ( 'sorted' | 'enumerate' ) - trailer< '(' arglist<node=any any*> ')' > - any* -> -""" -pats_built = False -def in_special_context(node): - """ Returns true if node is in an environment where all that is required - of it is being iterable (ie, it doesn't matter if it returns a list - or an iterator). - See test_map_nochange in test_fixers.py for some examples and tests. - """ - global p0, p1, p2, pats_built - if not pats_built: - p0 = patcomp.compile_pattern(p0) - p1 = patcomp.compile_pattern(p1) - p2 = patcomp.compile_pattern(p2) - pats_built = True - patterns = [p0, p1, p2] - for pattern, parent in zip(patterns, attr_chain(node, "parent")): - results = {} - if pattern.match(parent, results) and results["node"] is node: - return True - return False - -def is_probably_builtin(node): - """ - Check that something isn't an attribute or function name etc. - """ - prev = node.prev_sibling - if prev is not None and prev.type == token.DOT: - # Attribute lookup. - return False - parent = node.parent - if parent.type in (syms.funcdef, syms.classdef): - return False - if parent.type == syms.expr_stmt and parent.children[0] is node: - # Assignment. - return False - if parent.type == syms.parameters or \ - (parent.type == syms.typedargslist and ( - (prev is not None and prev.type == token.COMMA) or - parent.children[0] is node - )): - # The name of an argument. - return False - return True - -def find_indentation(node): - """Find the indentation of *node*.""" - while node is not None: - if node.type == syms.suite and len(node.children) > 2: - indent = node.children[1] - if indent.type == token.INDENT: - return indent.value - node = node.parent - return "" - -########################################################### -### The following functions are to find bindings in a suite -########################################################### - -def make_suite(node): - if node.type == syms.suite: - return node - node = node.clone() - parent, node.parent = node.parent, None - suite = Node(syms.suite, [node]) - suite.parent = parent - return suite - -def find_root(node): - """Find the top level namespace.""" - # Scamper up to the top level namespace - while node.type != syms.file_input: - node = node.parent - if not node: - raise ValueError("root found before file_input node was found.") - return node - -def does_tree_import(package, name, node): - """ Returns true if name is imported from package at the - top level of the tree which node belongs to. - To cover the case of an import like 'import foo', use - None for the package and 'foo' for the name. """ - binding = find_binding(name, find_root(node), package) - return bool(binding) - -def is_import(node): - """Returns true if the node is an import statement.""" - return node.type in (syms.import_name, syms.import_from) - -def touch_import(package, name, node): - """ Works like `does_tree_import` but adds an import statement - if it was not imported. """ - def is_import_stmt(node): - return (node.type == syms.simple_stmt and node.children and - is_import(node.children[0])) - - root = find_root(node) - - if does_tree_import(package, name, root): - return - - # figure out where to insert the new import. First try to find - # the first import and then skip to the last one. - insert_pos = offset = 0 - for idx, node in enumerate(root.children): - if not is_import_stmt(node): - continue - for offset, node2 in enumerate(root.children[idx:]): - if not is_import_stmt(node2): - break - insert_pos = idx + offset - break - - # if there are no imports where we can insert, find the docstring. - # if that also fails, we stick to the beginning of the file - if insert_pos == 0: - for idx, node in enumerate(root.children): - if (node.type == syms.simple_stmt and node.children and - node.children[0].type == token.STRING): - insert_pos = idx + 1 - break - - if package is None: - import_ = Node(syms.import_name, [ - Leaf(token.NAME, "import"), - Leaf(token.NAME, name, prefix=" ") - ]) - else: - import_ = FromImport(package, [Leaf(token.NAME, name, prefix=" ")]) - - children = [import_, Newline()] - root.insert_child(insert_pos, Node(syms.simple_stmt, children)) - - -_def_syms = {syms.classdef, syms.funcdef} -def find_binding(name, node, package=None): - """ Returns the node which binds variable name, otherwise None. - If optional argument package is supplied, only imports will - be returned. - See test cases for examples.""" - for child in node.children: - ret = None - if child.type == syms.for_stmt: - if _find(name, child.children[1]): - return child - n = find_binding(name, make_suite(child.children[-1]), package) - if n: ret = n - elif child.type in (syms.if_stmt, syms.while_stmt): - n = find_binding(name, make_suite(child.children[-1]), package) - if n: ret = n - elif child.type == syms.try_stmt: - n = find_binding(name, make_suite(child.children[2]), package) - if n: - ret = n - else: - for i, kid in enumerate(child.children[3:]): - if kid.type == token.COLON and kid.value == ":": - # i+3 is the colon, i+4 is the suite - n = find_binding(name, make_suite(child.children[i+4]), package) - if n: ret = n - elif child.type in _def_syms and child.children[1].value == name: - ret = child - elif _is_import_binding(child, name, package): - ret = child - elif child.type == syms.simple_stmt: - ret = find_binding(name, child, package) - elif child.type == syms.expr_stmt: - if _find(name, child.children[0]): - ret = child - - if ret: - if not package: - return ret - if is_import(ret): - return ret - return None - -_block_syms = {syms.funcdef, syms.classdef, syms.trailer} -def _find(name, node): - nodes = [node] - while nodes: - node = nodes.pop() - if node.type > 256 and node.type not in _block_syms: - nodes.extend(node.children) - elif node.type == token.NAME and node.value == name: - return node - return None - -def _is_import_binding(node, name, package=None): - """ Will return node if node will import name, or node - will import * from package. None is returned otherwise. - See test cases for examples. """ - - if node.type == syms.import_name and not package: - imp = node.children[1] - if imp.type == syms.dotted_as_names: - for child in imp.children: - if child.type == syms.dotted_as_name: - if child.children[2].value == name: - return node - elif child.type == token.NAME and child.value == name: - return node - elif imp.type == syms.dotted_as_name: - last = imp.children[-1] - if last.type == token.NAME and last.value == name: - return node - elif imp.type == token.NAME and imp.value == name: - return node - elif node.type == syms.import_from: - # str(...) is used to make life easier here, because - # from a.b import parses to ['import', ['a', '.', 'b'], ...] - if package and str(node.children[1]).strip() != package: - return None - n = node.children[3] - if package and _find("as", n): - # See test_from_import_as for explanation - return None - elif n.type == syms.import_as_names and _find(name, n): - return node - elif n.type == syms.import_as_name: - child = n.children[2] - if child.type == token.NAME and child.value == name: - return node - elif n.type == token.NAME and n.value == name: - return node - elif package and n.type == token.STAR: - return node - return None diff --git a/Lib/lib2to3/fixes/__init__.py b/Lib/lib2to3/fixes/__init__.py deleted file mode 100644 index b93054b3ecf3a..0000000000000 --- a/Lib/lib2to3/fixes/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Dummy file to make this directory a package. diff --git a/Lib/lib2to3/fixes/fix_apply.py b/Lib/lib2to3/fixes/fix_apply.py deleted file mode 100644 index 6408582c42647..0000000000000 --- a/Lib/lib2to3/fixes/fix_apply.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for apply(). - -This converts apply(func, v, k) into (func)(*v, **k).""" - -# Local imports -from .. import pytree -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Call, Comma, parenthesize - -class FixApply(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - power< 'apply' - trailer< - '(' - arglist< - (not argument<NAME '=' any>) func=any ',' - (not argument<NAME '=' any>) args=any [',' - (not argument<NAME '=' any>) kwds=any] [','] - > - ')' - > - > - """ - - def transform(self, node, results): - syms = self.syms - assert results - func = results["func"] - args = results["args"] - kwds = results.get("kwds") - # I feel like we should be able to express this logic in the - # PATTERN above but I don't know how to do it so... - if args: - if (args.type == self.syms.argument and - args.children[0].value in {'**', '*'}): - return # Make no change. - if kwds and (kwds.type == self.syms.argument and - kwds.children[0].value == '**'): - return # Make no change. - prefix = node.prefix - func = func.clone() - if (func.type not in (token.NAME, syms.atom) and - (func.type != syms.power or - func.children[-2].type == token.DOUBLESTAR)): - # Need to parenthesize - func = parenthesize(func) - func.prefix = "" - args = args.clone() - args.prefix = "" - if kwds is not None: - kwds = kwds.clone() - kwds.prefix = "" - l_newargs = [pytree.Leaf(token.STAR, "*"), args] - if kwds is not None: - l_newargs.extend([Comma(), - pytree.Leaf(token.DOUBLESTAR, "**"), - kwds]) - l_newargs[-2].prefix = " " # that's the ** token - # XXX Sometimes we could be cleverer, e.g. apply(f, (x, y) + t) - # can be translated into f(x, y, *t) instead of f(*(x, y) + t) - #new = pytree.Node(syms.power, (func, ArgList(l_newargs))) - return Call(func, l_newargs, prefix=prefix) diff --git a/Lib/lib2to3/fixes/fix_asserts.py b/Lib/lib2to3/fixes/fix_asserts.py deleted file mode 100644 index 5bcec885f52cb..0000000000000 --- a/Lib/lib2to3/fixes/fix_asserts.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Fixer that replaces deprecated unittest method names.""" - -# Author: Ezio Melotti - -from ..fixer_base import BaseFix -from ..fixer_util import Name - -NAMES = dict( - assert_="assertTrue", - assertEquals="assertEqual", - assertNotEquals="assertNotEqual", - assertAlmostEquals="assertAlmostEqual", - assertNotAlmostEquals="assertNotAlmostEqual", - assertRegexpMatches="assertRegex", - assertRaisesRegexp="assertRaisesRegex", - failUnlessEqual="assertEqual", - failIfEqual="assertNotEqual", - failUnlessAlmostEqual="assertAlmostEqual", - failIfAlmostEqual="assertNotAlmostEqual", - failUnless="assertTrue", - failUnlessRaises="assertRaises", - failIf="assertFalse", -) - - -class FixAsserts(BaseFix): - - PATTERN = """ - power< any+ trailer< '.' meth=(%s)> any* > - """ % '|'.join(map(repr, NAMES)) - - def transform(self, node, results): - name = results["meth"][0] - name.replace(Name(NAMES[str(name)], prefix=name.prefix)) diff --git a/Lib/lib2to3/fixes/fix_basestring.py b/Lib/lib2to3/fixes/fix_basestring.py deleted file mode 100644 index 5fe69a0f03b1b..0000000000000 --- a/Lib/lib2to3/fixes/fix_basestring.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Fixer for basestring -> str.""" -# Author: Christian Heimes - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -class FixBasestring(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = "'basestring'" - - def transform(self, node, results): - return Name("str", prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_buffer.py b/Lib/lib2to3/fixes/fix_buffer.py deleted file mode 100644 index f9a1958ad3b93..0000000000000 --- a/Lib/lib2to3/fixes/fix_buffer.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that changes buffer(...) into memoryview(...).""" - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - - -class FixBuffer(fixer_base.BaseFix): - BM_compatible = True - - explicit = True # The user must ask for this fixer - - PATTERN = """ - power< name='buffer' trailer< '(' [any] ')' > any* > - """ - - def transform(self, node, results): - name = results["name"] - name.replace(Name("memoryview", prefix=name.prefix)) diff --git a/Lib/lib2to3/fixes/fix_dict.py b/Lib/lib2to3/fixes/fix_dict.py deleted file mode 100644 index d3655c9f1b2d9..0000000000000 --- a/Lib/lib2to3/fixes/fix_dict.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for dict methods. - -d.keys() -> list(d.keys()) -d.items() -> list(d.items()) -d.values() -> list(d.values()) - -d.iterkeys() -> iter(d.keys()) -d.iteritems() -> iter(d.items()) -d.itervalues() -> iter(d.values()) - -d.viewkeys() -> d.keys() -d.viewitems() -> d.items() -d.viewvalues() -> d.values() - -Except in certain very specific contexts: the iter() can be dropped -when the context is list(), sorted(), iter() or for...in; the list() -can be dropped when the context is list() or sorted() (but not iter() -or for...in!). Special contexts that apply to both: list(), sorted(), tuple() -set(), any(), all(), sum(). - -Note: iter(d.keys()) could be written as iter(d) but since the -original d.iterkeys() was also redundant we don't fix this. And there -are (rare) contexts where it makes a difference (e.g. when passing it -as an argument to a function that introspects the argument). -""" - -# Local imports -from .. import pytree -from .. import patcomp -from .. import fixer_base -from ..fixer_util import Name, Call, Dot -from .. import fixer_util - - -iter_exempt = fixer_util.consuming_calls | {"iter"} - - -class FixDict(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - power< head=any+ - trailer< '.' method=('keys'|'items'|'values'| - 'iterkeys'|'iteritems'|'itervalues'| - 'viewkeys'|'viewitems'|'viewvalues') > - parens=trailer< '(' ')' > - tail=any* - > - """ - - def transform(self, node, results): - head = results["head"] - method = results["method"][0] # Extract node for method name - tail = results["tail"] - syms = self.syms - method_name = method.value - isiter = method_name.startswith("iter") - isview = method_name.startswith("view") - if isiter or isview: - method_name = method_name[4:] - assert method_name in ("keys", "items", "values"), repr(method) - head = [n.clone() for n in head] - tail = [n.clone() for n in tail] - special = not tail and self.in_special_context(node, isiter) - args = head + [pytree.Node(syms.trailer, - [Dot(), - Name(method_name, - prefix=method.prefix)]), - results["parens"].clone()] - new = pytree.Node(syms.power, args) - if not (special or isview): - new.prefix = "" - new = Call(Name("iter" if isiter else "list"), [new]) - if tail: - new = pytree.Node(syms.power, [new] + tail) - new.prefix = node.prefix - return new - - P1 = "power< func=NAME trailer< '(' node=any ')' > any* >" - p1 = patcomp.compile_pattern(P1) - - P2 = """for_stmt< 'for' any 'in' node=any ':' any* > - | comp_for< 'for' any 'in' node=any any* > - """ - p2 = patcomp.compile_pattern(P2) - - def in_special_context(self, node, isiter): - if node.parent is None: - return False - results = {} - if (node.parent.parent is not None and - self.p1.match(node.parent.parent, results) and - results["node"] is node): - if isiter: - # iter(d.iterkeys()) -> iter(d.keys()), etc. - return results["func"].value in iter_exempt - else: - # list(d.keys()) -> list(d.keys()), etc. - return results["func"].value in fixer_util.consuming_calls - if not isiter: - return False - # for ... in d.iterkeys() -> for ... in d.keys(), etc. - return self.p2.match(node.parent, results) and results["node"] is node diff --git a/Lib/lib2to3/fixes/fix_except.py b/Lib/lib2to3/fixes/fix_except.py deleted file mode 100644 index 49bd3d5ab7d6c..0000000000000 --- a/Lib/lib2to3/fixes/fix_except.py +++ /dev/null @@ -1,93 +0,0 @@ -"""Fixer for except statements with named exceptions. - -The following cases will be converted: - -- "except E, T:" where T is a name: - - except E as T: - -- "except E, T:" where T is not a name, tuple or list: - - except E as t: - T = t - - This is done because the target of an "except" clause must be a - name. - -- "except E, T:" where T is a tuple or list literal: - - except E as t: - T = t.args -""" -# Author: Collin Winter - -# Local imports -from .. import pytree -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Assign, Attr, Name, is_tuple, is_list, syms - -def find_excepts(nodes): - for i, n in enumerate(nodes): - if n.type == syms.except_clause: - if n.children[0].value == 'except': - yield (n, nodes[i+2]) - -class FixExcept(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - try_stmt< 'try' ':' (simple_stmt | suite) - cleanup=(except_clause ':' (simple_stmt | suite))+ - tail=(['except' ':' (simple_stmt | suite)] - ['else' ':' (simple_stmt | suite)] - ['finally' ':' (simple_stmt | suite)]) > - """ - - def transform(self, node, results): - syms = self.syms - - tail = [n.clone() for n in results["tail"]] - - try_cleanup = [ch.clone() for ch in results["cleanup"]] - for except_clause, e_suite in find_excepts(try_cleanup): - if len(except_clause.children) == 4: - (E, comma, N) = except_clause.children[1:4] - comma.replace(Name("as", prefix=" ")) - - if N.type != token.NAME: - # Generate a new N for the except clause - new_N = Name(self.new_name(), prefix=" ") - target = N.clone() - target.prefix = "" - N.replace(new_N) - new_N = new_N.clone() - - # Insert "old_N = new_N" as the first statement in - # the except body. This loop skips leading whitespace - # and indents - #TODO(cwinter) suite-cleanup - suite_stmts = e_suite.children - for i, stmt in enumerate(suite_stmts): - if isinstance(stmt, pytree.Node): - break - - # The assignment is different if old_N is a tuple or list - # In that case, the assignment is old_N = new_N.args - if is_tuple(N) or is_list(N): - assign = Assign(target, Attr(new_N, Name('args'))) - else: - assign = Assign(target, new_N) - - #TODO(cwinter) stopgap until children becomes a smart list - for child in reversed(suite_stmts[:i]): - e_suite.insert_child(0, child) - e_suite.insert_child(i, assign) - elif N.prefix == "": - # No space after a comma is legal; no space after "as", - # not so much. - N.prefix = " " - - #TODO(cwinter) fix this when children becomes a smart list - children = [c.clone() for c in node.children[:3]] + try_cleanup + tail - return pytree.Node(node.type, children) diff --git a/Lib/lib2to3/fixes/fix_exec.py b/Lib/lib2to3/fixes/fix_exec.py deleted file mode 100644 index ab921ee80cdf3..0000000000000 --- a/Lib/lib2to3/fixes/fix_exec.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for exec. - -This converts usages of the exec statement into calls to a built-in -exec() function. - -exec code in ns1, ns2 -> exec(code, ns1, ns2) -""" - -# Local imports -from .. import fixer_base -from ..fixer_util import Comma, Name, Call - - -class FixExec(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - exec_stmt< 'exec' a=any 'in' b=any [',' c=any] > - | - exec_stmt< 'exec' (not atom<'(' [any] ')'>) a=any > - """ - - def transform(self, node, results): - assert results - syms = self.syms - a = results["a"] - b = results.get("b") - c = results.get("c") - args = [a.clone()] - args[0].prefix = "" - if b is not None: - args.extend([Comma(), b.clone()]) - if c is not None: - args.extend([Comma(), c.clone()]) - - return Call(Name("exec"), args, prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_execfile.py b/Lib/lib2to3/fixes/fix_execfile.py deleted file mode 100644 index b6c786fd4e8b6..0000000000000 --- a/Lib/lib2to3/fixes/fix_execfile.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for execfile. - -This converts usages of the execfile function into calls to the built-in -exec() function. -""" - -from .. import fixer_base -from ..fixer_util import (Comma, Name, Call, LParen, RParen, Dot, Node, - ArgList, String, syms) - - -class FixExecfile(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - power< 'execfile' trailer< '(' arglist< filename=any [',' globals=any [',' locals=any ] ] > ')' > > - | - power< 'execfile' trailer< '(' filename=any ')' > > - """ - - def transform(self, node, results): - assert results - filename = results["filename"] - globals = results.get("globals") - locals = results.get("locals") - - # Copy over the prefix from the right parentheses end of the execfile - # call. - execfile_paren = node.children[-1].children[-1].clone() - # Construct open().read(). - open_args = ArgList([filename.clone(), Comma(), String('"rb"', ' ')], - rparen=execfile_paren) - open_call = Node(syms.power, [Name("open"), open_args]) - read = [Node(syms.trailer, [Dot(), Name('read')]), - Node(syms.trailer, [LParen(), RParen()])] - open_expr = [open_call] + read - # Wrap the open call in a compile call. This is so the filename will be - # preserved in the execed code. - filename_arg = filename.clone() - filename_arg.prefix = " " - exec_str = String("'exec'", " ") - compile_args = open_expr + [Comma(), filename_arg, Comma(), exec_str] - compile_call = Call(Name("compile"), compile_args, "") - # Finally, replace the execfile call with an exec call. - args = [compile_call] - if globals is not None: - args.extend([Comma(), globals.clone()]) - if locals is not None: - args.extend([Comma(), locals.clone()]) - return Call(Name("exec"), args, prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_exitfunc.py b/Lib/lib2to3/fixes/fix_exitfunc.py deleted file mode 100644 index 2e47887afead3..0000000000000 --- a/Lib/lib2to3/fixes/fix_exitfunc.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -Convert use of sys.exitfunc to use the atexit module. -""" - -# Author: Benjamin Peterson - -from lib2to3 import pytree, fixer_base -from lib2to3.fixer_util import Name, Attr, Call, Comma, Newline, syms - - -class FixExitfunc(fixer_base.BaseFix): - keep_line_order = True - BM_compatible = True - - PATTERN = """ - ( - sys_import=import_name<'import' - ('sys' - | - dotted_as_names< (any ',')* 'sys' (',' any)* > - ) - > - | - expr_stmt< - power< 'sys' trailer< '.' 'exitfunc' > > - '=' func=any > - ) - """ - - def __init__(self, *args): - super(FixExitfunc, self).__init__(*args) - - def start_tree(self, tree, filename): - super(FixExitfunc, self).start_tree(tree, filename) - self.sys_import = None - - def transform(self, node, results): - # First, find the sys import. We'll just hope it's global scope. - if "sys_import" in results: - if self.sys_import is None: - self.sys_import = results["sys_import"] - return - - func = results["func"].clone() - func.prefix = "" - register = pytree.Node(syms.power, - Attr(Name("atexit"), Name("register")) - ) - call = Call(register, [func], node.prefix) - node.replace(call) - - if self.sys_import is None: - # That's interesting. - self.warning(node, "Can't find sys import; Please add an atexit " - "import at the top of your file.") - return - - # Now add an atexit import after the sys import. - names = self.sys_import.children[1] - if names.type == syms.dotted_as_names: - names.append_child(Comma()) - names.append_child(Name("atexit", " ")) - else: - containing_stmt = self.sys_import.parent - position = containing_stmt.children.index(self.sys_import) - stmt_container = containing_stmt.parent - new_import = pytree.Node(syms.import_name, - [Name("import"), Name("atexit", " ")] - ) - new = pytree.Node(syms.simple_stmt, [new_import]) - containing_stmt.insert_child(position + 1, Newline()) - containing_stmt.insert_child(position + 2, new) diff --git a/Lib/lib2to3/fixes/fix_filter.py b/Lib/lib2to3/fixes/fix_filter.py deleted file mode 100644 index 38e9078f11ac8..0000000000000 --- a/Lib/lib2to3/fixes/fix_filter.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that changes filter(F, X) into list(filter(F, X)). - -We avoid the transformation if the filter() call is directly contained -in iter(<>), list(<>), tuple(<>), sorted(<>), ...join(<>), or -for V in <>:. - -NOTE: This is still not correct if the original code was depending on -filter(F, X) to return a string if X is a string and a tuple if X is a -tuple. That would require type inference, which we don't do. Let -Python 2.6 figure it out. -""" - -# Local imports -from .. import fixer_base -from ..pytree import Node -from ..pygram import python_symbols as syms -from ..fixer_util import Name, ArgList, ListComp, in_special_context, parenthesize - - -class FixFilter(fixer_base.ConditionalFix): - BM_compatible = True - - PATTERN = """ - filter_lambda=power< - 'filter' - trailer< - '(' - arglist< - lambdef< 'lambda' - (fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any - > - ',' - it=any - > - ')' - > - [extra_trailers=trailer*] - > - | - power< - 'filter' - trailer< '(' arglist< none='None' ',' seq=any > ')' > - [extra_trailers=trailer*] - > - | - power< - 'filter' - args=trailer< '(' [any] ')' > - [extra_trailers=trailer*] - > - """ - - skip_on = "future_builtins.filter" - - def transform(self, node, results): - if self.should_skip(node): - return - - trailers = [] - if 'extra_trailers' in results: - for t in results['extra_trailers']: - trailers.append(t.clone()) - - if "filter_lambda" in results: - xp = results.get("xp").clone() - if xp.type == syms.test: - xp.prefix = "" - xp = parenthesize(xp) - - new = ListComp(results.get("fp").clone(), - results.get("fp").clone(), - results.get("it").clone(), xp) - new = Node(syms.power, [new] + trailers, prefix="") - - elif "none" in results: - new = ListComp(Name("_f"), - Name("_f"), - results["seq"].clone(), - Name("_f")) - new = Node(syms.power, [new] + trailers, prefix="") - - else: - if in_special_context(node): - return None - - args = results['args'].clone() - new = Node(syms.power, [Name("filter"), args], prefix="") - new = Node(syms.power, [Name("list"), ArgList([new])] + trailers) - new.prefix = "" - new.prefix = node.prefix - return new diff --git a/Lib/lib2to3/fixes/fix_funcattrs.py b/Lib/lib2to3/fixes/fix_funcattrs.py deleted file mode 100644 index 67f3e18e061bd..0000000000000 --- a/Lib/lib2to3/fixes/fix_funcattrs.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Fix function attribute names (f.func_x -> f.__x__).""" -# Author: Collin Winter - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - - -class FixFuncattrs(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - power< any+ trailer< '.' attr=('func_closure' | 'func_doc' | 'func_globals' - | 'func_name' | 'func_defaults' | 'func_code' - | 'func_dict') > any* > - """ - - def transform(self, node, results): - attr = results["attr"][0] - attr.replace(Name(("__%s__" % attr.value[5:]), - prefix=attr.prefix)) diff --git a/Lib/lib2to3/fixes/fix_future.py b/Lib/lib2to3/fixes/fix_future.py deleted file mode 100644 index fbcb86af07913..0000000000000 --- a/Lib/lib2to3/fixes/fix_future.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Remove __future__ imports - -from __future__ import foo is replaced with an empty line. -""" -# Author: Christian Heimes - -# Local imports -from .. import fixer_base -from ..fixer_util import BlankLine - -class FixFuture(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """import_from< 'from' module_name="__future__" 'import' any >""" - - # This should be run last -- some things check for the import - run_order = 10 - - def transform(self, node, results): - new = BlankLine() - new.prefix = node.prefix - return new diff --git a/Lib/lib2to3/fixes/fix_getcwdu.py b/Lib/lib2to3/fixes/fix_getcwdu.py deleted file mode 100644 index 087eaedcb26f9..0000000000000 --- a/Lib/lib2to3/fixes/fix_getcwdu.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -Fixer that changes os.getcwdu() to os.getcwd(). -""" -# Author: Victor Stinner - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -class FixGetcwdu(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - power< 'os' trailer< dot='.' name='getcwdu' > any* > - """ - - def transform(self, node, results): - name = results["name"] - name.replace(Name("getcwd", prefix=name.prefix)) diff --git a/Lib/lib2to3/fixes/fix_has_key.py b/Lib/lib2to3/fixes/fix_has_key.py deleted file mode 100644 index 439708c992340..0000000000000 --- a/Lib/lib2to3/fixes/fix_has_key.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for has_key(). - -Calls to .has_key() methods are expressed in terms of the 'in' -operator: - - d.has_key(k) -> k in d - -CAVEATS: -1) While the primary target of this fixer is dict.has_key(), the - fixer will change any has_key() method call, regardless of its - class. - -2) Cases like this will not be converted: - - m = d.has_key - if m(k): - ... - - Only *calls* to has_key() are converted. While it is possible to - convert the above to something like - - m = d.__contains__ - if m(k): - ... - - this is currently not done. -""" - -# Local imports -from .. import pytree -from .. import fixer_base -from ..fixer_util import Name, parenthesize - - -class FixHasKey(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - anchor=power< - before=any+ - trailer< '.' 'has_key' > - trailer< - '(' - ( not(arglist | argument<any '=' any>) arg=any - | arglist<(not argument<any '=' any>) arg=any ','> - ) - ')' - > - after=any* - > - | - negation=not_test< - 'not' - anchor=power< - before=any+ - trailer< '.' 'has_key' > - trailer< - '(' - ( not(arglist | argument<any '=' any>) arg=any - | arglist<(not argument<any '=' any>) arg=any ','> - ) - ')' - > - > - > - """ - - def transform(self, node, results): - assert results - syms = self.syms - if (node.parent.type == syms.not_test and - self.pattern.match(node.parent)): - # Don't transform a node matching the first alternative of the - # pattern when its parent matches the second alternative - return None - negation = results.get("negation") - anchor = results["anchor"] - prefix = node.prefix - before = [n.clone() for n in results["before"]] - arg = results["arg"].clone() - after = results.get("after") - if after: - after = [n.clone() for n in after] - if arg.type in (syms.comparison, syms.not_test, syms.and_test, - syms.or_test, syms.test, syms.lambdef, syms.argument): - arg = parenthesize(arg) - if len(before) == 1: - before = before[0] - else: - before = pytree.Node(syms.power, before) - before.prefix = " " - n_op = Name("in", prefix=" ") - if negation: - n_not = Name("not", prefix=" ") - n_op = pytree.Node(syms.comp_op, (n_not, n_op)) - new = pytree.Node(syms.comparison, (arg, n_op, before)) - if after: - new = parenthesize(new) - new = pytree.Node(syms.power, (new,) + tuple(after)) - if node.parent.type in (syms.comparison, syms.expr, syms.xor_expr, - syms.and_expr, syms.shift_expr, - syms.arith_expr, syms.term, - syms.factor, syms.power): - new = parenthesize(new) - new.prefix = prefix - return new diff --git a/Lib/lib2to3/fixes/fix_idioms.py b/Lib/lib2to3/fixes/fix_idioms.py deleted file mode 100644 index 6905913d7cb79..0000000000000 --- a/Lib/lib2to3/fixes/fix_idioms.py +++ /dev/null @@ -1,152 +0,0 @@ -"""Adjust some old Python 2 idioms to their modern counterparts. - -* Change some type comparisons to isinstance() calls: - type(x) == T -> isinstance(x, T) - type(x) is T -> isinstance(x, T) - type(x) != T -> not isinstance(x, T) - type(x) is not T -> not isinstance(x, T) - -* Change "while 1:" into "while True:". - -* Change both - - v = list(EXPR) - v.sort() - foo(v) - -and the more general - - v = EXPR - v.sort() - foo(v) - -into - - v = sorted(EXPR) - foo(v) -""" -# Author: Jacques Frechet, Collin Winter - -# Local imports -from .. import fixer_base -from ..fixer_util import Call, Comma, Name, Node, BlankLine, syms - -CMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)" -TYPE = "power< 'type' trailer< '(' x=any ')' > >" - -class FixIdioms(fixer_base.BaseFix): - explicit = True # The user must ask for this fixer - - PATTERN = r""" - isinstance=comparison< %s %s T=any > - | - isinstance=comparison< T=any %s %s > - | - while_stmt< 'while' while='1' ':' any+ > - | - sorted=any< - any* - simple_stmt< - expr_stmt< id1=any '=' - power< list='list' trailer< '(' (not arglist<any+>) any ')' > > - > - '\n' - > - sort= - simple_stmt< - power< id2=any - trailer< '.' 'sort' > trailer< '(' ')' > - > - '\n' - > - next=any* - > - | - sorted=any< - any* - simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' > - sort= - simple_stmt< - power< id2=any - trailer< '.' 'sort' > trailer< '(' ')' > - > - '\n' - > - next=any* - > - """ % (TYPE, CMP, CMP, TYPE) - - def match(self, node): - r = super(FixIdioms, self).match(node) - # If we've matched one of the sort/sorted subpatterns above, we - # want to reject matches where the initial assignment and the - # subsequent .sort() call involve different identifiers. - if r and "sorted" in r: - if r["id1"] == r["id2"]: - return r - return None - return r - - def transform(self, node, results): - if "isinstance" in results: - return self.transform_isinstance(node, results) - elif "while" in results: - return self.transform_while(node, results) - elif "sorted" in results: - return self.transform_sort(node, results) - else: - raise RuntimeError("Invalid match") - - def transform_isinstance(self, node, results): - x = results["x"].clone() # The thing inside of type() - T = results["T"].clone() # The type being compared against - x.prefix = "" - T.prefix = " " - test = Call(Name("isinstance"), [x, Comma(), T]) - if "n" in results: - test.prefix = " " - test = Node(syms.not_test, [Name("not"), test]) - test.prefix = node.prefix - return test - - def transform_while(self, node, results): - one = results["while"] - one.replace(Name("True", prefix=one.prefix)) - - def transform_sort(self, node, results): - sort_stmt = results["sort"] - next_stmt = results["next"] - list_call = results.get("list") - simple_expr = results.get("expr") - - if list_call: - list_call.replace(Name("sorted", prefix=list_call.prefix)) - elif simple_expr: - new = simple_expr.clone() - new.prefix = "" - simple_expr.replace(Call(Name("sorted"), [new], - prefix=simple_expr.prefix)) - else: - raise RuntimeError("should not have reached here") - sort_stmt.remove() - - btwn = sort_stmt.prefix - # Keep any prefix lines between the sort_stmt and the list_call and - # shove them right after the sorted() call. - if "\n" in btwn: - if next_stmt: - # The new prefix should be everything from the sort_stmt's - # prefix up to the last newline, then the old prefix after a new - # line. - prefix_lines = (btwn.rpartition("\n")[0], next_stmt[0].prefix) - next_stmt[0].prefix = "\n".join(prefix_lines) - else: - assert list_call.parent - assert list_call.next_sibling is None - # Put a blank line after list_call and set its prefix. - end_line = BlankLine() - list_call.parent.append_child(end_line) - assert list_call.next_sibling is end_line - # The new prefix should be everything up to the first new line - # of sort_stmt's prefix. - end_line.prefix = btwn.rpartition("\n")[0] diff --git a/Lib/lib2to3/fixes/fix_import.py b/Lib/lib2to3/fixes/fix_import.py deleted file mode 100644 index 734ca294699c3..0000000000000 --- a/Lib/lib2to3/fixes/fix_import.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Fixer for import statements. -If spam is being imported from the local directory, this import: - from spam import eggs -Becomes: - from .spam import eggs - -And this import: - import spam -Becomes: - from . import spam -""" - -# Local imports -from .. import fixer_base -from os.path import dirname, join, exists, sep -from ..fixer_util import FromImport, syms, token - - -def traverse_imports(names): - """ - Walks over all the names imported in a dotted_as_names node. - """ - pending = [names] - while pending: - node = pending.pop() - if node.type == token.NAME: - yield node.value - elif node.type == syms.dotted_name: - yield "".join([ch.value for ch in node.children]) - elif node.type == syms.dotted_as_name: - pending.append(node.children[0]) - elif node.type == syms.dotted_as_names: - pending.extend(node.children[::-2]) - else: - raise AssertionError("unknown node type") - - -class FixImport(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - import_from< 'from' imp=any 'import' ['('] any [')'] > - | - import_name< 'import' imp=any > - """ - - def start_tree(self, tree, name): - super(FixImport, self).start_tree(tree, name) - self.skip = "absolute_import" in tree.future_features - - def transform(self, node, results): - if self.skip: - return - imp = results['imp'] - - if node.type == syms.import_from: - # Some imps are top-level (eg: 'import ham') - # some are first level (eg: 'import ham.eggs') - # some are third level (eg: 'import ham.eggs as spam') - # Hence, the loop - while not hasattr(imp, 'value'): - imp = imp.children[0] - if self.probably_a_local_import(imp.value): - imp.value = "." + imp.value - imp.changed() - else: - have_local = False - have_absolute = False - for mod_name in traverse_imports(imp): - if self.probably_a_local_import(mod_name): - have_local = True - else: - have_absolute = True - if have_absolute: - if have_local: - # We won't handle both sibling and absolute imports in the - # same statement at the moment. - self.warning(node, "absolute and local imports together") - return - - new = FromImport(".", [imp]) - new.prefix = node.prefix - return new - - def probably_a_local_import(self, imp_name): - if imp_name.startswith("."): - # Relative imports are certainly not local imports. - return False - imp_name = imp_name.split(".", 1)[0] - base_path = dirname(self.filename) - base_path = join(base_path, imp_name) - # If there is no __init__.py next to the file its not in a package - # so can't be a relative import. - if not exists(join(dirname(base_path), "__init__.py")): - return False - for ext in [".py", sep, ".pyc", ".so", ".sl", ".pyd"]: - if exists(base_path + ext): - return True - return False diff --git a/Lib/lib2to3/fixes/fix_imports.py b/Lib/lib2to3/fixes/fix_imports.py deleted file mode 100644 index aaf4f2f642efb..0000000000000 --- a/Lib/lib2to3/fixes/fix_imports.py +++ /dev/null @@ -1,145 +0,0 @@ -"""Fix incompatible imports and module references.""" -# Authors: Collin Winter, Nick Edds - -# Local imports -from .. import fixer_base -from ..fixer_util import Name, attr_chain - -MAPPING = {'StringIO': 'io', - 'cStringIO': 'io', - 'cPickle': 'pickle', - '__builtin__' : 'builtins', - 'copy_reg': 'copyreg', - 'Queue': 'queue', - 'SocketServer': 'socketserver', - 'ConfigParser': 'configparser', - 'repr': 'reprlib', - 'FileDialog': 'tkinter.filedialog', - 'tkFileDialog': 'tkinter.filedialog', - 'SimpleDialog': 'tkinter.simpledialog', - 'tkSimpleDialog': 'tkinter.simpledialog', - 'tkColorChooser': 'tkinter.colorchooser', - 'tkCommonDialog': 'tkinter.commondialog', - 'Dialog': 'tkinter.dialog', - 'Tkdnd': 'tkinter.dnd', - 'tkFont': 'tkinter.font', - 'tkMessageBox': 'tkinter.messagebox', - 'ScrolledText': 'tkinter.scrolledtext', - 'Tkconstants': 'tkinter.constants', - 'Tix': 'tkinter.tix', - 'ttk': 'tkinter.ttk', - 'Tkinter': 'tkinter', - 'markupbase': '_markupbase', - '_winreg': 'winreg', - 'thread': '_thread', - 'dummy_thread': '_dummy_thread', - # anydbm and whichdb are handled by fix_imports2 - 'dbhash': 'dbm.bsd', - 'dumbdbm': 'dbm.dumb', - 'dbm': 'dbm.ndbm', - 'gdbm': 'dbm.gnu', - 'xmlrpclib': 'xmlrpc.client', - 'DocXMLRPCServer': 'xmlrpc.server', - 'SimpleXMLRPCServer': 'xmlrpc.server', - 'httplib': 'http.client', - 'htmlentitydefs' : 'html.entities', - 'HTMLParser' : 'html.parser', - 'Cookie': 'http.cookies', - 'cookielib': 'http.cookiejar', - 'BaseHTTPServer': 'http.server', - 'SimpleHTTPServer': 'http.server', - 'CGIHTTPServer': 'http.server', - #'test.test_support': 'test.support', - 'commands': 'subprocess', - 'UserString' : 'collections', - 'UserList' : 'collections', - 'urlparse' : 'urllib.parse', - 'robotparser' : 'urllib.robotparser', -} - - -def alternates(members): - return "(" + "|".join(map(repr, members)) + ")" - - -def build_pattern(mapping=MAPPING): - mod_list = ' | '.join(["module_name='%s'" % key for key in mapping]) - bare_names = alternates(mapping.keys()) - - yield """name_import=import_name< 'import' ((%s) | - multiple_imports=dotted_as_names< any* (%s) any* >) > - """ % (mod_list, mod_list) - yield """import_from< 'from' (%s) 'import' ['('] - ( any | import_as_name< any 'as' any > | - import_as_names< any* >) [')'] > - """ % mod_list - yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > | - multiple_imports=dotted_as_names< - any* dotted_as_name< (%s) 'as' any > any* >) > - """ % (mod_list, mod_list) - - # Find usages of module members in code e.g. thread.foo(bar) - yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names - - -class FixImports(fixer_base.BaseFix): - - BM_compatible = True - keep_line_order = True - # This is overridden in fix_imports2. - mapping = MAPPING - - # We want to run this fixer late, so fix_import doesn't try to make stdlib - # renames into relative imports. - run_order = 6 - - def build_pattern(self): - return "|".join(build_pattern(self.mapping)) - - def compile_pattern(self): - # We override this, so MAPPING can be pragmatically altered and the - # changes will be reflected in PATTERN. - self.PATTERN = self.build_pattern() - super(FixImports, self).compile_pattern() - - # Don't match the node if it's within another match. - def match(self, node): - match = super(FixImports, self).match - results = match(node) - if results: - # Module usage could be in the trailer of an attribute lookup, so we - # might have nested matches when "bare_with_attr" is present. - if "bare_with_attr" not in results and \ - any(match(obj) for obj in attr_chain(node, "parent")): - return False - return results - return False - - def start_tree(self, tree, filename): - super(FixImports, self).start_tree(tree, filename) - self.replace = {} - - def transform(self, node, results): - import_mod = results.get("module_name") - if import_mod: - mod_name = import_mod.value - new_name = self.mapping[mod_name] - import_mod.replace(Name(new_name, prefix=import_mod.prefix)) - if "name_import" in results: - # If it's not a "from x import x, y" or "import x as y" import, - # marked its usage to be replaced. - self.replace[mod_name] = new_name - if "multiple_imports" in results: - # This is a nasty hack to fix multiple imports on a line (e.g., - # "import StringIO, urlparse"). The problem is that I can't - # figure out an easy way to make a pattern recognize the keys of - # MAPPING randomly sprinkled in an import statement. - results = self.match(node) - if results: - self.transform(node, results) - else: - # Replace usage of the module. - bare_name = results["bare_with_attr"][0] - new_name = self.replace.get(bare_name.value) - if new_name: - bare_name.replace(Name(new_name, prefix=bare_name.prefix)) diff --git a/Lib/lib2to3/fixes/fix_imports2.py b/Lib/lib2to3/fixes/fix_imports2.py deleted file mode 100644 index 9a33c67b1dc19..0000000000000 --- a/Lib/lib2to3/fixes/fix_imports2.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Fix incompatible imports and module references that must be fixed after -fix_imports.""" -from . import fix_imports - - -MAPPING = { - 'whichdb': 'dbm', - 'anydbm': 'dbm', - } - - -class FixImports2(fix_imports.FixImports): - - run_order = 7 - - mapping = MAPPING diff --git a/Lib/lib2to3/fixes/fix_input.py b/Lib/lib2to3/fixes/fix_input.py deleted file mode 100644 index 9cf9a48c471f3..0000000000000 --- a/Lib/lib2to3/fixes/fix_input.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Fixer that changes input(...) into eval(input(...)).""" -# Author: Andre Roberge - -# Local imports -from .. import fixer_base -from ..fixer_util import Call, Name -from .. import patcomp - - -context = patcomp.compile_pattern("power< 'eval' trailer< '(' any ')' > >") - - -class FixInput(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< 'input' args=trailer< '(' [any] ')' > > - """ - - def transform(self, node, results): - # If we're already wrapped in an eval() call, we're done. - if context.match(node.parent.parent): - return - - new = node.clone() - new.prefix = "" - return Call(Name("eval"), [new], prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_intern.py b/Lib/lib2to3/fixes/fix_intern.py deleted file mode 100644 index d752843092aac..0000000000000 --- a/Lib/lib2to3/fixes/fix_intern.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2006 Georg Brandl. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for intern(). - -intern(s) -> sys.intern(s)""" - -# Local imports -from .. import fixer_base -from ..fixer_util import ImportAndCall, touch_import - - -class FixIntern(fixer_base.BaseFix): - BM_compatible = True - order = "pre" - - PATTERN = """ - power< 'intern' - trailer< lpar='(' - ( not(arglist | argument<any '=' any>) obj=any - | obj=arglist<(not argument<any '=' any>) any ','> ) - rpar=')' > - after=any* - > - """ - - def transform(self, node, results): - if results: - # I feel like we should be able to express this logic in the - # PATTERN above but I don't know how to do it so... - obj = results['obj'] - if obj: - if (obj.type == self.syms.argument and - obj.children[0].value in {'**', '*'}): - return # Make no change. - names = ('sys', 'intern') - new = ImportAndCall(node, results, names) - touch_import(None, 'sys', node) - return new diff --git a/Lib/lib2to3/fixes/fix_isinstance.py b/Lib/lib2to3/fixes/fix_isinstance.py deleted file mode 100644 index bebb1de120424..0000000000000 --- a/Lib/lib2to3/fixes/fix_isinstance.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2008 Armin Ronacher. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that cleans up a tuple argument to isinstance after the tokens -in it were fixed. This is mainly used to remove double occurrences of -tokens as a leftover of the long -> int / unicode -> str conversion. - -eg. isinstance(x, (int, long)) -> isinstance(x, (int, int)) - -> isinstance(x, int) -""" - -from .. import fixer_base -from ..fixer_util import token - - -class FixIsinstance(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< - 'isinstance' - trailer< '(' arglist< any ',' atom< '(' - args=testlist_gexp< any+ > - ')' > > ')' > - > - """ - - run_order = 6 - - def transform(self, node, results): - names_inserted = set() - testlist = results["args"] - args = testlist.children - new_args = [] - iterator = enumerate(args) - for idx, arg in iterator: - if arg.type == token.NAME and arg.value in names_inserted: - if idx < len(args) - 1 and args[idx + 1].type == token.COMMA: - next(iterator) - continue - else: - new_args.append(arg) - if arg.type == token.NAME: - names_inserted.add(arg.value) - if new_args and new_args[-1].type == token.COMMA: - del new_args[-1] - if len(new_args) == 1: - atom = testlist.parent - new_args[0].prefix = atom.prefix - atom.replace(new_args[0]) - else: - args[:] = new_args - node.changed() diff --git a/Lib/lib2to3/fixes/fix_itertools.py b/Lib/lib2to3/fixes/fix_itertools.py deleted file mode 100644 index 8e78d6c689f43..0000000000000 --- a/Lib/lib2to3/fixes/fix_itertools.py +++ /dev/null @@ -1,43 +0,0 @@ -""" Fixer for itertools.(imap|ifilter|izip) --> (map|filter|zip) and - itertools.ifilterfalse --> itertools.filterfalse (bugs 2360-2363) - - imports from itertools are fixed in fix_itertools_import.py - - If itertools is imported as something else (ie: import itertools as it; - it.izip(spam, eggs)) method calls will not get fixed. - """ - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -class FixItertools(fixer_base.BaseFix): - BM_compatible = True - it_funcs = "('imap'|'ifilter'|'izip'|'izip_longest'|'ifilterfalse')" - PATTERN = """ - power< it='itertools' - trailer< - dot='.' func=%(it_funcs)s > trailer< '(' [any] ')' > > - | - power< func=%(it_funcs)s trailer< '(' [any] ')' > > - """ %(locals()) - - # Needs to be run after fix_(map|zip|filter) - run_order = 6 - - def transform(self, node, results): - prefix = None - func = results['func'][0] - if ('it' in results and - func.value not in ('ifilterfalse', 'izip_longest')): - dot, it = (results['dot'], results['it']) - # Remove the 'itertools' - prefix = it.prefix - it.remove() - # Replace the node which contains ('.', 'function') with the - # function (to be consistent with the second part of the pattern) - dot.remove() - func.parent.replace(func) - - prefix = prefix or func.prefix - func.replace(Name(func.value[1:], prefix=prefix)) diff --git a/Lib/lib2to3/fixes/fix_itertools_imports.py b/Lib/lib2to3/fixes/fix_itertools_imports.py deleted file mode 100644 index 0ddbc7b842299..0000000000000 --- a/Lib/lib2to3/fixes/fix_itertools_imports.py +++ /dev/null @@ -1,57 +0,0 @@ -""" Fixer for imports of itertools.(imap|ifilter|izip|ifilterfalse) """ - -# Local imports -from lib2to3 import fixer_base -from lib2to3.fixer_util import BlankLine, syms, token - - -class FixItertoolsImports(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - import_from< 'from' 'itertools' 'import' imports=any > - """ %(locals()) - - def transform(self, node, results): - imports = results['imports'] - if imports.type == syms.import_as_name or not imports.children: - children = [imports] - else: - children = imports.children - for child in children[::2]: - if child.type == token.NAME: - member = child.value - name_node = child - elif child.type == token.STAR: - # Just leave the import as is. - return - else: - assert child.type == syms.import_as_name - name_node = child.children[0] - member_name = name_node.value - if member_name in ('imap', 'izip', 'ifilter'): - child.value = None - child.remove() - elif member_name in ('ifilterfalse', 'izip_longest'): - node.changed() - name_node.value = ('filterfalse' if member_name[1] == 'f' - else 'zip_longest') - - # Make sure the import statement is still sane - children = imports.children[:] or [imports] - remove_comma = True - for child in children: - if remove_comma and child.type == token.COMMA: - child.remove() - else: - remove_comma ^= True - - while children and children[-1].type == token.COMMA: - children.pop().remove() - - # If there are no imports left, just get rid of the entire statement - if (not (imports.children or getattr(imports, 'value', None)) or - imports.parent is None): - p = node.prefix - node = BlankLine() - node.prefix = p - return node diff --git a/Lib/lib2to3/fixes/fix_long.py b/Lib/lib2to3/fixes/fix_long.py deleted file mode 100644 index f227c9f498153..0000000000000 --- a/Lib/lib2to3/fixes/fix_long.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that turns 'long' into 'int' everywhere. -""" - -# Local imports -from lib2to3 import fixer_base -from lib2to3.fixer_util import is_probably_builtin - - -class FixLong(fixer_base.BaseFix): - BM_compatible = True - PATTERN = "'long'" - - def transform(self, node, results): - if is_probably_builtin(node): - node.value = "int" - node.changed() diff --git a/Lib/lib2to3/fixes/fix_map.py b/Lib/lib2to3/fixes/fix_map.py deleted file mode 100644 index 78cf81c6f9409..0000000000000 --- a/Lib/lib2to3/fixes/fix_map.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that changes map(F, ...) into list(map(F, ...)) unless there -exists a 'from future_builtins import map' statement in the top-level -namespace. - -As a special case, map(None, X) is changed into list(X). (This is -necessary because the semantics are changed in this case -- the new -map(None, X) is equivalent to [(x,) for x in X].) - -We avoid the transformation (except for the special case mentioned -above) if the map() call is directly contained in iter(<>), list(<>), -tuple(<>), sorted(<>), ...join(<>), or for V in <>:. - -NOTE: This is still not correct if the original code was depending on -map(F, X, Y, ...) to go on until the longest argument is exhausted, -substituting None for missing values -- like zip(), it now stops as -soon as the shortest argument is exhausted. -""" - -# Local imports -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Name, ArgList, Call, ListComp, in_special_context -from ..pygram import python_symbols as syms -from ..pytree import Node - - -class FixMap(fixer_base.ConditionalFix): - BM_compatible = True - - PATTERN = """ - map_none=power< - 'map' - trailer< '(' arglist< 'None' ',' arg=any [','] > ')' > - [extra_trailers=trailer*] - > - | - map_lambda=power< - 'map' - trailer< - '(' - arglist< - lambdef< 'lambda' - (fp=NAME | vfpdef< '(' fp=NAME ')'> ) ':' xp=any - > - ',' - it=any - > - ')' - > - [extra_trailers=trailer*] - > - | - power< - 'map' args=trailer< '(' [any] ')' > - [extra_trailers=trailer*] - > - """ - - skip_on = 'future_builtins.map' - - def transform(self, node, results): - if self.should_skip(node): - return - - trailers = [] - if 'extra_trailers' in results: - for t in results['extra_trailers']: - trailers.append(t.clone()) - - if node.parent.type == syms.simple_stmt: - self.warning(node, "You should use a for loop here") - new = node.clone() - new.prefix = "" - new = Call(Name("list"), [new]) - elif "map_lambda" in results: - new = ListComp(results["xp"].clone(), - results["fp"].clone(), - results["it"].clone()) - new = Node(syms.power, [new] + trailers, prefix="") - - else: - if "map_none" in results: - new = results["arg"].clone() - new.prefix = "" - else: - if "args" in results: - args = results["args"] - if args.type == syms.trailer and \ - args.children[1].type == syms.arglist and \ - args.children[1].children[0].type == token.NAME and \ - args.children[1].children[0].value == "None": - self.warning(node, "cannot convert map(None, ...) " - "with multiple arguments because map() " - "now truncates to the shortest sequence") - return - - new = Node(syms.power, [Name("map"), args.clone()]) - new.prefix = "" - - if in_special_context(node): - return None - - new = Node(syms.power, [Name("list"), ArgList([new])] + trailers) - new.prefix = "" - - new.prefix = node.prefix - return new diff --git a/Lib/lib2to3/fixes/fix_metaclass.py b/Lib/lib2to3/fixes/fix_metaclass.py deleted file mode 100644 index fe547b2228072..0000000000000 --- a/Lib/lib2to3/fixes/fix_metaclass.py +++ /dev/null @@ -1,228 +0,0 @@ -"""Fixer for __metaclass__ = X -> (metaclass=X) methods. - - The various forms of classef (inherits nothing, inherits once, inherits - many) don't parse the same in the CST so we look at ALL classes for - a __metaclass__ and if we find one normalize the inherits to all be - an arglist. - - For one-liner classes ('class X: pass') there is no indent/dedent so - we normalize those into having a suite. - - Moving the __metaclass__ into the classdef can also cause the class - body to be empty so there is some special casing for that as well. - - This fixer also tries very hard to keep original indenting and spacing - in all those corner cases. - -""" -# Author: Jack Diederich - -# Local imports -from .. import fixer_base -from ..pygram import token -from ..fixer_util import syms, Node, Leaf - - -def has_metaclass(parent): - """ we have to check the cls_node without changing it. - There are two possibilities: - 1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta') - 2) clsdef => simple_stmt => expr_stmt => Leaf('__meta') - """ - for node in parent.children: - if node.type == syms.suite: - return has_metaclass(node) - elif node.type == syms.simple_stmt and node.children: - expr_node = node.children[0] - if expr_node.type == syms.expr_stmt and expr_node.children: - left_side = expr_node.children[0] - if isinstance(left_side, Leaf) and \ - left_side.value == '__metaclass__': - return True - return False - - -def fixup_parse_tree(cls_node): - """ one-line classes don't get a suite in the parse tree so we add - one to normalize the tree - """ - for node in cls_node.children: - if node.type == syms.suite: - # already in the preferred format, do nothing - return - - # !%@#! one-liners have no suite node, we have to fake one up - for i, node in enumerate(cls_node.children): - if node.type == token.COLON: - break - else: - raise ValueError("No class suite and no ':'!") - - # move everything into a suite node - suite = Node(syms.suite, []) - while cls_node.children[i+1:]: - move_node = cls_node.children[i+1] - suite.append_child(move_node.clone()) - move_node.remove() - cls_node.append_child(suite) - node = suite - - -def fixup_simple_stmt(parent, i, stmt_node): - """ if there is a semi-colon all the parts count as part of the same - simple_stmt. We just want the __metaclass__ part so we move - everything after the semi-colon into its own simple_stmt node - """ - for semi_ind, node in enumerate(stmt_node.children): - if node.type == token.SEMI: # *sigh* - break - else: - return - - node.remove() # kill the semicolon - new_expr = Node(syms.expr_stmt, []) - new_stmt = Node(syms.simple_stmt, [new_expr]) - while stmt_node.children[semi_ind:]: - move_node = stmt_node.children[semi_ind] - new_expr.append_child(move_node.clone()) - move_node.remove() - parent.insert_child(i, new_stmt) - new_leaf1 = new_stmt.children[0].children[0] - old_leaf1 = stmt_node.children[0].children[0] - new_leaf1.prefix = old_leaf1.prefix - - -def remove_trailing_newline(node): - if node.children and node.children[-1].type == token.NEWLINE: - node.children[-1].remove() - - -def find_metas(cls_node): - # find the suite node (Mmm, sweet nodes) - for node in cls_node.children: - if node.type == syms.suite: - break - else: - raise ValueError("No class suite!") - - # look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ] - for i, simple_node in list(enumerate(node.children)): - if simple_node.type == syms.simple_stmt and simple_node.children: - expr_node = simple_node.children[0] - if expr_node.type == syms.expr_stmt and expr_node.children: - # Check if the expr_node is a simple assignment. - left_node = expr_node.children[0] - if isinstance(left_node, Leaf) and \ - left_node.value == '__metaclass__': - # We found an assignment to __metaclass__. - fixup_simple_stmt(node, i, simple_node) - remove_trailing_newline(simple_node) - yield (node, i, simple_node) - - -def fixup_indent(suite): - """ If an INDENT is followed by a thing with a prefix then nuke the prefix - Otherwise we get in trouble when removing __metaclass__ at suite start - """ - kids = suite.children[::-1] - # find the first indent - while kids: - node = kids.pop() - if node.type == token.INDENT: - break - - # find the first Leaf - while kids: - node = kids.pop() - if isinstance(node, Leaf) and node.type != token.DEDENT: - if node.prefix: - node.prefix = '' - return - else: - kids.extend(node.children[::-1]) - - -class FixMetaclass(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - classdef<any*> - """ - - def transform(self, node, results): - if not has_metaclass(node): - return - - fixup_parse_tree(node) - - # find metaclasses, keep the last one - last_metaclass = None - for suite, i, stmt in find_metas(node): - last_metaclass = stmt - stmt.remove() - - text_type = node.children[0].type # always Leaf(nnn, 'class') - - # figure out what kind of classdef we have - if len(node.children) == 7: - # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite]) - # 0 1 2 3 4 5 6 - if node.children[3].type == syms.arglist: - arglist = node.children[3] - # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite]) - else: - parent = node.children[3].clone() - arglist = Node(syms.arglist, [parent]) - node.set_child(3, arglist) - elif len(node.children) == 6: - # Node(classdef, ['class', 'name', '(', ')', ':', suite]) - # 0 1 2 3 4 5 - arglist = Node(syms.arglist, []) - node.insert_child(3, arglist) - elif len(node.children) == 4: - # Node(classdef, ['class', 'name', ':', suite]) - # 0 1 2 3 - arglist = Node(syms.arglist, []) - node.insert_child(2, Leaf(token.RPAR, ')')) - node.insert_child(2, arglist) - node.insert_child(2, Leaf(token.LPAR, '(')) - else: - raise ValueError("Unexpected class definition") - - # now stick the metaclass in the arglist - meta_txt = last_metaclass.children[0].children[0] - meta_txt.value = 'metaclass' - orig_meta_prefix = meta_txt.prefix - - if arglist.children: - arglist.append_child(Leaf(token.COMMA, ',')) - meta_txt.prefix = ' ' - else: - meta_txt.prefix = '' - - # compact the expression "metaclass = Meta" -> "metaclass=Meta" - expr_stmt = last_metaclass.children[0] - assert expr_stmt.type == syms.expr_stmt - expr_stmt.children[1].prefix = '' - expr_stmt.children[2].prefix = '' - - arglist.append_child(last_metaclass) - - fixup_indent(suite) - - # check for empty suite - if not suite.children: - # one-liner that was just __metaclass_ - suite.remove() - pass_leaf = Leaf(text_type, 'pass') - pass_leaf.prefix = orig_meta_prefix - node.append_child(pass_leaf) - node.append_child(Leaf(token.NEWLINE, '\n')) - - elif len(suite.children) > 1 and \ - (suite.children[-2].type == token.INDENT and - suite.children[-1].type == token.DEDENT): - # there was only one line in the class body and it was __metaclass__ - pass_leaf = Leaf(text_type, 'pass') - suite.insert_child(-1, pass_leaf) - suite.insert_child(-1, Leaf(token.NEWLINE, '\n')) diff --git a/Lib/lib2to3/fixes/fix_methodattrs.py b/Lib/lib2to3/fixes/fix_methodattrs.py deleted file mode 100644 index 7f9004f00e6e8..0000000000000 --- a/Lib/lib2to3/fixes/fix_methodattrs.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Fix bound method attributes (method.im_? -> method.__?__). -""" -# Author: Christian Heimes - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -MAP = { - "im_func" : "__func__", - "im_self" : "__self__", - "im_class" : "__self__.__class__" - } - -class FixMethodattrs(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< any+ trailer< '.' attr=('im_func' | 'im_self' | 'im_class') > any* > - """ - - def transform(self, node, results): - attr = results["attr"][0] - new = MAP[attr.value] - attr.replace(Name(new, prefix=attr.prefix)) diff --git a/Lib/lib2to3/fixes/fix_ne.py b/Lib/lib2to3/fixes/fix_ne.py deleted file mode 100644 index e3ee10f4a63e0..0000000000000 --- a/Lib/lib2to3/fixes/fix_ne.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that turns <> into !=.""" - -# Local imports -from .. import pytree -from ..pgen2 import token -from .. import fixer_base - - -class FixNe(fixer_base.BaseFix): - # This is so simple that we don't need the pattern compiler. - - _accept_type = token.NOTEQUAL - - def match(self, node): - # Override - return node.value == "<>" - - def transform(self, node, results): - new = pytree.Leaf(token.NOTEQUAL, "!=", prefix=node.prefix) - return new diff --git a/Lib/lib2to3/fixes/fix_next.py b/Lib/lib2to3/fixes/fix_next.py deleted file mode 100644 index 9f6305e1d49dc..0000000000000 --- a/Lib/lib2to3/fixes/fix_next.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Fixer for it.next() -> next(it), per PEP 3114.""" -# Author: Collin Winter - -# Things that currently aren't covered: -# - listcomp "next" names aren't warned -# - "with" statement targets aren't checked - -# Local imports -from ..pgen2 import token -from ..pygram import python_symbols as syms -from .. import fixer_base -from ..fixer_util import Name, Call, find_binding - -bind_warning = "Calls to builtin next() possibly shadowed by global binding" - - -class FixNext(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > > - | - power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > > - | - classdef< 'class' any+ ':' - suite< any* - funcdef< 'def' - name='next' - parameters< '(' NAME ')' > any+ > - any* > > - | - global=global_stmt< 'global' any* 'next' any* > - """ - - order = "pre" # Pre-order tree traversal - - def start_tree(self, tree, filename): - super(FixNext, self).start_tree(tree, filename) - - n = find_binding('next', tree) - if n: - self.warning(n, bind_warning) - self.shadowed_next = True - else: - self.shadowed_next = False - - def transform(self, node, results): - assert results - - base = results.get("base") - attr = results.get("attr") - name = results.get("name") - - if base: - if self.shadowed_next: - attr.replace(Name("__next__", prefix=attr.prefix)) - else: - base = [n.clone() for n in base] - base[0].prefix = "" - node.replace(Call(Name("next", prefix=node.prefix), base)) - elif name: - n = Name("__next__", prefix=name.prefix) - name.replace(n) - elif attr: - # We don't do this transformation if we're assigning to "x.next". - # Unfortunately, it doesn't seem possible to do this in PATTERN, - # so it's being done here. - if is_assign_target(node): - head = results["head"] - if "".join([str(n) for n in head]).strip() == '__builtin__': - self.warning(node, bind_warning) - return - attr.replace(Name("__next__")) - elif "global" in results: - self.warning(node, bind_warning) - self.shadowed_next = True - - -### The following functions help test if node is part of an assignment -### target. - -def is_assign_target(node): - assign = find_assign(node) - if assign is None: - return False - - for child in assign.children: - if child.type == token.EQUAL: - return False - elif is_subtree(child, node): - return True - return False - -def find_assign(node): - if node.type == syms.expr_stmt: - return node - if node.type == syms.simple_stmt or node.parent is None: - return None - return find_assign(node.parent) - -def is_subtree(root, node): - if root == node: - return True - return any(is_subtree(c, node) for c in root.children) diff --git a/Lib/lib2to3/fixes/fix_nonzero.py b/Lib/lib2to3/fixes/fix_nonzero.py deleted file mode 100644 index c2295969a7728..0000000000000 --- a/Lib/lib2to3/fixes/fix_nonzero.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Fixer for __nonzero__ -> __bool__ methods.""" -# Author: Collin Winter - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -class FixNonzero(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - classdef< 'class' any+ ':' - suite< any* - funcdef< 'def' name='__nonzero__' - parameters< '(' NAME ')' > any+ > - any* > > - """ - - def transform(self, node, results): - name = results["name"] - new = Name("__bool__", prefix=name.prefix) - name.replace(new) diff --git a/Lib/lib2to3/fixes/fix_numliterals.py b/Lib/lib2to3/fixes/fix_numliterals.py deleted file mode 100644 index 79207d4aa368a..0000000000000 --- a/Lib/lib2to3/fixes/fix_numliterals.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Fixer that turns 1L into 1, 0755 into 0o755. -""" -# Copyright 2007 Georg Brandl. -# Licensed to PSF under a Contributor Agreement. - -# Local imports -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Number - - -class FixNumliterals(fixer_base.BaseFix): - # This is so simple that we don't need the pattern compiler. - - _accept_type = token.NUMBER - - def match(self, node): - # Override - return (node.value.startswith("0") or node.value[-1] in "Ll") - - def transform(self, node, results): - val = node.value - if val[-1] in 'Ll': - val = val[:-1] - elif val.startswith('0') and val.isdigit() and len(set(val)) > 1: - val = "0o" + val[1:] - - return Number(val, prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_operator.py b/Lib/lib2to3/fixes/fix_operator.py deleted file mode 100644 index d303cd2018bef..0000000000000 --- a/Lib/lib2to3/fixes/fix_operator.py +++ /dev/null @@ -1,97 +0,0 @@ -"""Fixer for operator functions. - -operator.isCallable(obj) -> callable(obj) -operator.sequenceIncludes(obj) -> operator.contains(obj) -operator.isSequenceType(obj) -> isinstance(obj, collections.abc.Sequence) -operator.isMappingType(obj) -> isinstance(obj, collections.abc.Mapping) -operator.isNumberType(obj) -> isinstance(obj, numbers.Number) -operator.repeat(obj, n) -> operator.mul(obj, n) -operator.irepeat(obj, n) -> operator.imul(obj, n) -""" - -import collections.abc - -# Local imports -from lib2to3 import fixer_base -from lib2to3.fixer_util import Call, Name, String, touch_import - - -def invocation(s): - def dec(f): - f.invocation = s - return f - return dec - - -class FixOperator(fixer_base.BaseFix): - BM_compatible = True - order = "pre" - - methods = """ - method=('isCallable'|'sequenceIncludes' - |'isSequenceType'|'isMappingType'|'isNumberType' - |'repeat'|'irepeat') - """ - obj = "'(' obj=any ')'" - PATTERN = """ - power< module='operator' - trailer< '.' %(methods)s > trailer< %(obj)s > > - | - power< %(methods)s trailer< %(obj)s > > - """ % dict(methods=methods, obj=obj) - - def transform(self, node, results): - method = self._check_method(node, results) - if method is not None: - return method(node, results) - - @invocation("operator.contains(%s)") - def _sequenceIncludes(self, node, results): - return self._handle_rename(node, results, "contains") - - @invocation("callable(%s)") - def _isCallable(self, node, results): - obj = results["obj"] - return Call(Name("callable"), [obj.clone()], prefix=node.prefix) - - @invocation("operator.mul(%s)") - def _repeat(self, node, results): - return self._handle_rename(node, results, "mul") - - @invocation("operator.imul(%s)") - def _irepeat(self, node, results): - return self._handle_rename(node, results, "imul") - - @invocation("isinstance(%s, collections.abc.Sequence)") - def _isSequenceType(self, node, results): - return self._handle_type2abc(node, results, "collections.abc", "Sequence") - - @invocation("isinstance(%s, collections.abc.Mapping)") - def _isMappingType(self, node, results): - return self._handle_type2abc(node, results, "collections.abc", "Mapping") - - @invocation("isinstance(%s, numbers.Number)") - def _isNumberType(self, node, results): - return self._handle_type2abc(node, results, "numbers", "Number") - - def _handle_rename(self, node, results, name): - method = results["method"][0] - method.value = name - method.changed() - - def _handle_type2abc(self, node, results, module, abc): - touch_import(None, module, node) - obj = results["obj"] - args = [obj.clone(), String(", " + ".".join([module, abc]))] - return Call(Name("isinstance"), args, prefix=node.prefix) - - def _check_method(self, node, results): - method = getattr(self, "_" + results["method"][0].value) - if isinstance(method, collections.abc.Callable): - if "module" in results: - return method - else: - sub = (str(results["obj"]),) - invocation_str = method.invocation % sub - self.warning(node, "You should use '%s' here." % invocation_str) - return None diff --git a/Lib/lib2to3/fixes/fix_paren.py b/Lib/lib2to3/fixes/fix_paren.py deleted file mode 100644 index df3da5f5232c9..0000000000000 --- a/Lib/lib2to3/fixes/fix_paren.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Fixer that adds parentheses where they are required - -This converts ``[x for x in 1, 2]`` to ``[x for x in (1, 2)]``.""" - -# By Taek Joo Kim and Benjamin Peterson - -# Local imports -from .. import fixer_base -from ..fixer_util import LParen, RParen - -# XXX This doesn't support nested for loops like [x for x in 1, 2 for x in 1, 2] -class FixParen(fixer_base.BaseFix): - BM_compatible = True - - PATTERN = """ - atom< ('[' | '(') - (listmaker< any - comp_for< - 'for' NAME 'in' - target=testlist_safe< any (',' any)+ [','] - > - [any] - > - > - | - testlist_gexp< any - comp_for< - 'for' NAME 'in' - target=testlist_safe< any (',' any)+ [','] - > - [any] - > - >) - (']' | ')') > - """ - - def transform(self, node, results): - target = results["target"] - - lparen = LParen() - lparen.prefix = target.prefix - target.prefix = "" # Make it hug the parentheses - target.insert_child(0, lparen) - target.append_child(RParen()) diff --git a/Lib/lib2to3/fixes/fix_print.py b/Lib/lib2to3/fixes/fix_print.py deleted file mode 100644 index 8780322265f6f..0000000000000 --- a/Lib/lib2to3/fixes/fix_print.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for print. - -Change: - 'print' into 'print()' - 'print ...' into 'print(...)' - 'print ... ,' into 'print(..., end=" ")' - 'print >>x, ...' into 'print(..., file=x)' - -No changes are applied if print_function is imported from __future__ - -""" - -# Local imports -from .. import patcomp -from .. import pytree -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Name, Call, Comma, String - - -parend_expr = patcomp.compile_pattern( - """atom< '(' [atom|STRING|NAME] ')' >""" - ) - - -class FixPrint(fixer_base.BaseFix): - - BM_compatible = True - - PATTERN = """ - simple_stmt< any* bare='print' any* > | print_stmt - """ - - def transform(self, node, results): - assert results - - bare_print = results.get("bare") - - if bare_print: - # Special-case print all by itself - bare_print.replace(Call(Name("print"), [], - prefix=bare_print.prefix)) - return - assert node.children[0] == Name("print") - args = node.children[1:] - if len(args) == 1 and parend_expr.match(args[0]): - # We don't want to keep sticking parens around an - # already-parenthesised expression. - return - - sep = end = file = None - if args and args[-1] == Comma(): - args = args[:-1] - end = " " - if args and args[0] == pytree.Leaf(token.RIGHTSHIFT, ">>"): - assert len(args) >= 2 - file = args[1].clone() - args = args[3:] # Strip a possible comma after the file expression - # Now synthesize a print(args, sep=..., end=..., file=...) node. - l_args = [arg.clone() for arg in args] - if l_args: - l_args[0].prefix = "" - if sep is not None or end is not None or file is not None: - if sep is not None: - self.add_kwarg(l_args, "sep", String(repr(sep))) - if end is not None: - self.add_kwarg(l_args, "end", String(repr(end))) - if file is not None: - self.add_kwarg(l_args, "file", file) - n_stmt = Call(Name("print"), l_args) - n_stmt.prefix = node.prefix - return n_stmt - - def add_kwarg(self, l_nodes, s_kwd, n_expr): - # XXX All this prefix-setting may lose comments (though rarely) - n_expr.prefix = "" - n_argument = pytree.Node(self.syms.argument, - (Name(s_kwd), - pytree.Leaf(token.EQUAL, "="), - n_expr)) - if l_nodes: - l_nodes.append(Comma()) - n_argument.prefix = " " - l_nodes.append(n_argument) diff --git a/Lib/lib2to3/fixes/fix_raise.py b/Lib/lib2to3/fixes/fix_raise.py deleted file mode 100644 index 05aa21e74a30f..0000000000000 --- a/Lib/lib2to3/fixes/fix_raise.py +++ /dev/null @@ -1,90 +0,0 @@ -"""Fixer for 'raise E, V, T' - -raise -> raise -raise E -> raise E -raise E, V -> raise E(V) -raise E, V, T -> raise E(V).with_traceback(T) -raise E, None, T -> raise E.with_traceback(T) - -raise (((E, E'), E''), E'''), V -> raise E(V) -raise "foo", V, T -> warns about string exceptions - - -CAVEATS: -1) "raise E, V" will be incorrectly translated if V is an exception - instance. The correct Python 3 idiom is - - raise E from V - - but since we can't detect instance-hood by syntax alone and since - any client code would have to be changed as well, we don't automate - this. -""" -# Author: Collin Winter - -# Local imports -from .. import pytree -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Name, Call, Attr, ArgList, is_tuple - -class FixRaise(fixer_base.BaseFix): - - BM_compatible = True - PATTERN = """ - raise_stmt< 'raise' exc=any [',' val=any [',' tb=any]] > - """ - - def transform(self, node, results): - syms = self.syms - - exc = results["exc"].clone() - if exc.type == token.STRING: - msg = "Python 3 does not support string exceptions" - self.cannot_convert(node, msg) - return - - # Python 2 supports - # raise ((((E1, E2), E3), E4), E5), V - # as a synonym for - # raise E1, V - # Since Python 3 will not support this, we recurse down any tuple - # literals, always taking the first element. - if is_tuple(exc): - while is_tuple(exc): - # exc.children[1:-1] is the unparenthesized tuple - # exc.children[1].children[0] is the first element of the tuple - exc = exc.children[1].children[0].clone() - exc.prefix = " " - - if "val" not in results: - # One-argument raise - new = pytree.Node(syms.raise_stmt, [Name("raise"), exc]) - new.prefix = node.prefix - return new - - val = results["val"].clone() - if is_tuple(val): - args = [c.clone() for c in val.children[1:-1]] - else: - val.prefix = "" - args = [val] - - if "tb" in results: - tb = results["tb"].clone() - tb.prefix = "" - - e = exc - # If there's a traceback and None is passed as the value, then don't - # add a call, since the user probably just wants to add a - # traceback. See issue #9661. - if val.type != token.NAME or val.value != "None": - e = Call(exc, args) - with_tb = Attr(e, Name('with_traceback')) + [ArgList([tb])] - new = pytree.Node(syms.simple_stmt, [Name("raise")] + with_tb) - new.prefix = node.prefix - return new - else: - return pytree.Node(syms.raise_stmt, - [Name("raise"), Call(exc, args)], - prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_raw_input.py b/Lib/lib2to3/fixes/fix_raw_input.py deleted file mode 100644 index a51bb694b9e01..0000000000000 --- a/Lib/lib2to3/fixes/fix_raw_input.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Fixer that changes raw_input(...) into input(...).""" -# Author: Andre Roberge - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -class FixRawInput(fixer_base.BaseFix): - - BM_compatible = True - PATTERN = """ - power< name='raw_input' trailer< '(' [any] ')' > any* > - """ - - def transform(self, node, results): - name = results["name"] - name.replace(Name("input", prefix=name.prefix)) diff --git a/Lib/lib2to3/fixes/fix_reduce.py b/Lib/lib2to3/fixes/fix_reduce.py deleted file mode 100644 index 00e5aa1c33d48..0000000000000 --- a/Lib/lib2to3/fixes/fix_reduce.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2008 Armin Ronacher. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for reduce(). - -Makes sure reduce() is imported from the functools module if reduce is -used in that module. -""" - -from lib2to3 import fixer_base -from lib2to3.fixer_util import touch_import - - - -class FixReduce(fixer_base.BaseFix): - - BM_compatible = True - order = "pre" - - PATTERN = """ - power< 'reduce' - trailer< '(' - arglist< ( - (not(argument<any '=' any>) any ',' - not(argument<any '=' any>) any) | - (not(argument<any '=' any>) any ',' - not(argument<any '=' any>) any ',' - not(argument<any '=' any>) any) - ) > - ')' > - > - """ - - def transform(self, node, results): - touch_import('functools', 'reduce', node) diff --git a/Lib/lib2to3/fixes/fix_reload.py b/Lib/lib2to3/fixes/fix_reload.py deleted file mode 100644 index b30841131c51f..0000000000000 --- a/Lib/lib2to3/fixes/fix_reload.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Fixer for reload(). - -reload(s) -> importlib.reload(s)""" - -# Local imports -from .. import fixer_base -from ..fixer_util import ImportAndCall, touch_import - - -class FixReload(fixer_base.BaseFix): - BM_compatible = True - order = "pre" - - PATTERN = """ - power< 'reload' - trailer< lpar='(' - ( not(arglist | argument<any '=' any>) obj=any - | obj=arglist<(not argument<any '=' any>) any ','> ) - rpar=')' > - after=any* - > - """ - - def transform(self, node, results): - if results: - # I feel like we should be able to express this logic in the - # PATTERN above but I don't know how to do it so... - obj = results['obj'] - if obj: - if (obj.type == self.syms.argument and - obj.children[0].value in {'**', '*'}): - return # Make no change. - names = ('importlib', 'reload') - new = ImportAndCall(node, results, names) - touch_import(None, 'importlib', node) - return new diff --git a/Lib/lib2to3/fixes/fix_renames.py b/Lib/lib2to3/fixes/fix_renames.py deleted file mode 100644 index c0e3705ab7be1..0000000000000 --- a/Lib/lib2to3/fixes/fix_renames.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Fix incompatible renames - -Fixes: - * sys.maxint -> sys.maxsize -""" -# Author: Christian Heimes -# based on Collin Winter's fix_import - -# Local imports -from .. import fixer_base -from ..fixer_util import Name, attr_chain - -MAPPING = {"sys": {"maxint" : "maxsize"}, - } -LOOKUP = {} - -def alternates(members): - return "(" + "|".join(map(repr, members)) + ")" - - -def build_pattern(): - #bare = set() - for module, replace in list(MAPPING.items()): - for old_attr, new_attr in list(replace.items()): - LOOKUP[(module, old_attr)] = new_attr - #bare.add(module) - #bare.add(old_attr) - #yield """ - # import_name< 'import' (module=%r - # | dotted_as_names< any* module=%r any* >) > - # """ % (module, module) - yield """ - import_from< 'from' module_name=%r 'import' - ( attr_name=%r | import_as_name< attr_name=%r 'as' any >) > - """ % (module, old_attr, old_attr) - yield """ - power< module_name=%r trailer< '.' attr_name=%r > any* > - """ % (module, old_attr) - #yield """bare_name=%s""" % alternates(bare) - - -class FixRenames(fixer_base.BaseFix): - BM_compatible = True - PATTERN = "|".join(build_pattern()) - - order = "pre" # Pre-order tree traversal - - # Don't match the node if it's within another match - def match(self, node): - match = super(FixRenames, self).match - results = match(node) - if results: - if any(match(obj) for obj in attr_chain(node, "parent")): - return False - return results - return False - - #def start_tree(self, tree, filename): - # super(FixRenames, self).start_tree(tree, filename) - # self.replace = {} - - def transform(self, node, results): - mod_name = results.get("module_name") - attr_name = results.get("attr_name") - #bare_name = results.get("bare_name") - #import_mod = results.get("module") - - if mod_name and attr_name: - new_attr = LOOKUP[(mod_name.value, attr_name.value)] - attr_name.replace(Name(new_attr, prefix=attr_name.prefix)) diff --git a/Lib/lib2to3/fixes/fix_repr.py b/Lib/lib2to3/fixes/fix_repr.py deleted file mode 100644 index 1150bb8b9db2a..0000000000000 --- a/Lib/lib2to3/fixes/fix_repr.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that transforms `xyzzy` into repr(xyzzy).""" - -# Local imports -from .. import fixer_base -from ..fixer_util import Call, Name, parenthesize - - -class FixRepr(fixer_base.BaseFix): - - BM_compatible = True - PATTERN = """ - atom < '`' expr=any '`' > - """ - - def transform(self, node, results): - expr = results["expr"].clone() - - if expr.type == self.syms.testlist1: - expr = parenthesize(expr) - return Call(Name("repr"), [expr], prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_set_literal.py b/Lib/lib2to3/fixes/fix_set_literal.py deleted file mode 100644 index 762550cf73dc0..0000000000000 --- a/Lib/lib2to3/fixes/fix_set_literal.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Optional fixer to transform set() calls to set literals. -""" - -# Author: Benjamin Peterson - -from lib2to3 import fixer_base, pytree -from lib2to3.fixer_util import token, syms - - - -class FixSetLiteral(fixer_base.BaseFix): - - BM_compatible = True - explicit = True - - PATTERN = """power< 'set' trailer< '(' - (atom=atom< '[' (items=listmaker< any ((',' any)* [',']) > - | - single=any) ']' > - | - atom< '(' items=testlist_gexp< any ((',' any)* [',']) > ')' > - ) - ')' > > - """ - - def transform(self, node, results): - single = results.get("single") - if single: - # Make a fake listmaker - fake = pytree.Node(syms.listmaker, [single.clone()]) - single.replace(fake) - items = fake - else: - items = results["items"] - - # Build the contents of the literal - literal = [pytree.Leaf(token.LBRACE, "{")] - literal.extend(n.clone() for n in items.children) - literal.append(pytree.Leaf(token.RBRACE, "}")) - # Set the prefix of the right brace to that of the ')' or ']' - literal[-1].prefix = items.next_sibling.prefix - maker = pytree.Node(syms.dictsetmaker, literal) - maker.prefix = node.prefix - - # If the original was a one tuple, we need to remove the extra comma. - if len(maker.children) == 4: - n = maker.children[2] - n.remove() - maker.children[-1].prefix = n.prefix - - # Finally, replace the set call with our shiny new literal. - return maker diff --git a/Lib/lib2to3/fixes/fix_standarderror.py b/Lib/lib2to3/fixes/fix_standarderror.py deleted file mode 100644 index dc742167e6e9d..0000000000000 --- a/Lib/lib2to3/fixes/fix_standarderror.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for StandardError -> Exception.""" - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - - -class FixStandarderror(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - 'StandardError' - """ - - def transform(self, node, results): - return Name("Exception", prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_sys_exc.py b/Lib/lib2to3/fixes/fix_sys_exc.py deleted file mode 100644 index f6039690374ab..0000000000000 --- a/Lib/lib2to3/fixes/fix_sys_exc.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Fixer for sys.exc_{type, value, traceback} - -sys.exc_type -> sys.exc_info()[0] -sys.exc_value -> sys.exc_info()[1] -sys.exc_traceback -> sys.exc_info()[2] -""" - -# By Jeff Balogh and Benjamin Peterson - -# Local imports -from .. import fixer_base -from ..fixer_util import Attr, Call, Name, Number, Subscript, Node, syms - -class FixSysExc(fixer_base.BaseFix): - # This order matches the ordering of sys.exc_info(). - exc_info = ["exc_type", "exc_value", "exc_traceback"] - BM_compatible = True - PATTERN = """ - power< 'sys' trailer< dot='.' attribute=(%s) > > - """ % '|'.join("'%s'" % e for e in exc_info) - - def transform(self, node, results): - sys_attr = results["attribute"][0] - index = Number(self.exc_info.index(sys_attr.value)) - - call = Call(Name("exc_info"), prefix=sys_attr.prefix) - attr = Attr(Name("sys"), call) - attr[1].children[0].prefix = results["dot"].prefix - attr.append(Subscript(index)) - return Node(syms.power, attr, prefix=node.prefix) diff --git a/Lib/lib2to3/fixes/fix_throw.py b/Lib/lib2to3/fixes/fix_throw.py deleted file mode 100644 index aac29169b4e98..0000000000000 --- a/Lib/lib2to3/fixes/fix_throw.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Fixer for generator.throw(E, V, T). - -g.throw(E) -> g.throw(E) -g.throw(E, V) -> g.throw(E(V)) -g.throw(E, V, T) -> g.throw(E(V).with_traceback(T)) - -g.throw("foo"[, V[, T]]) will warn about string exceptions.""" -# Author: Collin Winter - -# Local imports -from .. import pytree -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Name, Call, ArgList, Attr, is_tuple - -class FixThrow(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< any trailer< '.' 'throw' > - trailer< '(' args=arglist< exc=any ',' val=any [',' tb=any] > ')' > - > - | - power< any trailer< '.' 'throw' > trailer< '(' exc=any ')' > > - """ - - def transform(self, node, results): - syms = self.syms - - exc = results["exc"].clone() - if exc.type is token.STRING: - self.cannot_convert(node, "Python 3 does not support string exceptions") - return - - # Leave "g.throw(E)" alone - val = results.get("val") - if val is None: - return - - val = val.clone() - if is_tuple(val): - args = [c.clone() for c in val.children[1:-1]] - else: - val.prefix = "" - args = [val] - - throw_args = results["args"] - - if "tb" in results: - tb = results["tb"].clone() - tb.prefix = "" - - e = Call(exc, args) - with_tb = Attr(e, Name('with_traceback')) + [ArgList([tb])] - throw_args.replace(pytree.Node(syms.power, with_tb)) - else: - throw_args.replace(Call(exc, args)) diff --git a/Lib/lib2to3/fixes/fix_tuple_params.py b/Lib/lib2to3/fixes/fix_tuple_params.py deleted file mode 100644 index cad755ffdbefb..0000000000000 --- a/Lib/lib2to3/fixes/fix_tuple_params.py +++ /dev/null @@ -1,175 +0,0 @@ -"""Fixer for function definitions with tuple parameters. - -def func(((a, b), c), d): - ... - - -> - -def func(x, d): - ((a, b), c) = x - ... - -It will also support lambdas: - - lambda (x, y): x + y -> lambda t: t[0] + t[1] - - # The parens are a syntax error in Python 3 - lambda (x): x + y -> lambda x: x + y -""" -# Author: Collin Winter - -# Local imports -from .. import pytree -from ..pgen2 import token -from .. import fixer_base -from ..fixer_util import Assign, Name, Newline, Number, Subscript, syms - -def is_docstring(stmt): - return isinstance(stmt, pytree.Node) and \ - stmt.children[0].type == token.STRING - -class FixTupleParams(fixer_base.BaseFix): - run_order = 4 #use a lower order since lambda is part of other - #patterns - BM_compatible = True - - PATTERN = """ - funcdef< 'def' any parameters< '(' args=any ')' > - ['->' any] ':' suite=any+ > - | - lambda= - lambdef< 'lambda' args=vfpdef< '(' inner=any ')' > - ':' body=any - > - """ - - def transform(self, node, results): - if "lambda" in results: - return self.transform_lambda(node, results) - - new_lines = [] - suite = results["suite"] - args = results["args"] - # This crap is so "def foo(...): x = 5; y = 7" is handled correctly. - # TODO(cwinter): suite-cleanup - if suite[0].children[1].type == token.INDENT: - start = 2 - indent = suite[0].children[1].value - end = Newline() - else: - start = 0 - indent = "; " - end = pytree.Leaf(token.INDENT, "") - - # We need access to self for new_name(), and making this a method - # doesn't feel right. Closing over self and new_lines makes the - # code below cleaner. - def handle_tuple(tuple_arg, add_prefix=False): - n = Name(self.new_name()) - arg = tuple_arg.clone() - arg.prefix = "" - stmt = Assign(arg, n.clone()) - if add_prefix: - n.prefix = " " - tuple_arg.replace(n) - new_lines.append(pytree.Node(syms.simple_stmt, - [stmt, end.clone()])) - - if args.type == syms.tfpdef: - handle_tuple(args) - elif args.type == syms.typedargslist: - for i, arg in enumerate(args.children): - if arg.type == syms.tfpdef: - # Without add_prefix, the emitted code is correct, - # just ugly. - handle_tuple(arg, add_prefix=(i > 0)) - - if not new_lines: - return - - # This isn't strictly necessary, but it plays nicely with other fixers. - # TODO(cwinter) get rid of this when children becomes a smart list - for line in new_lines: - line.parent = suite[0] - - # TODO(cwinter) suite-cleanup - after = start - if start == 0: - new_lines[0].prefix = " " - elif is_docstring(suite[0].children[start]): - new_lines[0].prefix = indent - after = start + 1 - - for line in new_lines: - line.parent = suite[0] - suite[0].children[after:after] = new_lines - for i in range(after+1, after+len(new_lines)+1): - suite[0].children[i].prefix = indent - suite[0].changed() - - def transform_lambda(self, node, results): - args = results["args"] - body = results["body"] - inner = simplify_args(results["inner"]) - - # Replace lambda ((((x)))): x with lambda x: x - if inner.type == token.NAME: - inner = inner.clone() - inner.prefix = " " - args.replace(inner) - return - - params = find_params(args) - to_index = map_to_index(params) - tup_name = self.new_name(tuple_name(params)) - - new_param = Name(tup_name, prefix=" ") - args.replace(new_param.clone()) - for n in body.post_order(): - if n.type == token.NAME and n.value in to_index: - subscripts = [c.clone() for c in to_index[n.value]] - new = pytree.Node(syms.power, - [new_param.clone()] + subscripts) - new.prefix = n.prefix - n.replace(new) - - -### Helper functions for transform_lambda() - -def simplify_args(node): - if node.type in (syms.vfplist, token.NAME): - return node - elif node.type == syms.vfpdef: - # These look like vfpdef< '(' x ')' > where x is NAME - # or another vfpdef instance (leading to recursion). - while node.type == syms.vfpdef: - node = node.children[1] - return node - raise RuntimeError("Received unexpected node %s" % node) - -def find_params(node): - if node.type == syms.vfpdef: - return find_params(node.children[1]) - elif node.type == token.NAME: - return node.value - return [find_params(c) for c in node.children if c.type != token.COMMA] - -def map_to_index(param_list, prefix=[], d=None): - if d is None: - d = {} - for i, obj in enumerate(param_list): - trailer = [Subscript(Number(str(i)))] - if isinstance(obj, list): - map_to_index(obj, trailer, d=d) - else: - d[obj] = prefix + trailer - return d - -def tuple_name(param_list): - l = [] - for obj in param_list: - if isinstance(obj, list): - l.append(tuple_name(obj)) - else: - l.append(obj) - return "_".join(l) diff --git a/Lib/lib2to3/fixes/fix_types.py b/Lib/lib2to3/fixes/fix_types.py deleted file mode 100644 index 67bf51f2f5b85..0000000000000 --- a/Lib/lib2to3/fixes/fix_types.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer for removing uses of the types module. - -These work for only the known names in the types module. The forms above -can include types. or not. ie, It is assumed the module is imported either as: - - import types - from types import ... # either * or specific types - -The import statements are not modified. - -There should be another fixer that handles at least the following constants: - - type([]) -> list - type(()) -> tuple - type('') -> str - -""" - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - -_TYPE_MAPPING = { - 'BooleanType' : 'bool', - 'BufferType' : 'memoryview', - 'ClassType' : 'type', - 'ComplexType' : 'complex', - 'DictType': 'dict', - 'DictionaryType' : 'dict', - 'EllipsisType' : 'type(Ellipsis)', - #'FileType' : 'io.IOBase', - 'FloatType': 'float', - 'IntType': 'int', - 'ListType': 'list', - 'LongType': 'int', - 'ObjectType' : 'object', - 'NoneType': 'type(None)', - 'NotImplementedType' : 'type(NotImplemented)', - 'SliceType' : 'slice', - 'StringType': 'bytes', # XXX ? - 'StringTypes' : '(str,)', # XXX ? - 'TupleType': 'tuple', - 'TypeType' : 'type', - 'UnicodeType': 'str', - 'XRangeType' : 'range', - } - -_pats = ["power< 'types' trailer< '.' name='%s' > >" % t for t in _TYPE_MAPPING] - -class FixTypes(fixer_base.BaseFix): - BM_compatible = True - PATTERN = '|'.join(_pats) - - def transform(self, node, results): - new_value = _TYPE_MAPPING.get(results["name"].value) - if new_value: - return Name(new_value, prefix=node.prefix) - return None diff --git a/Lib/lib2to3/fixes/fix_unicode.py b/Lib/lib2to3/fixes/fix_unicode.py deleted file mode 100644 index c7982c2b97c3e..0000000000000 --- a/Lib/lib2to3/fixes/fix_unicode.py +++ /dev/null @@ -1,42 +0,0 @@ -r"""Fixer for unicode. - -* Changes unicode to str and unichr to chr. - -* If "...\u..." is not unicode literal change it into "...\\u...". - -* Change u"..." into "...". - -""" - -from ..pgen2 import token -from .. import fixer_base - -_mapping = {"unichr" : "chr", "unicode" : "str"} - -class FixUnicode(fixer_base.BaseFix): - BM_compatible = True - PATTERN = "STRING | 'unicode' | 'unichr'" - - def start_tree(self, tree, filename): - super(FixUnicode, self).start_tree(tree, filename) - self.unicode_literals = 'unicode_literals' in tree.future_features - - def transform(self, node, results): - if node.type == token.NAME: - new = node.clone() - new.value = _mapping[node.value] - return new - elif node.type == token.STRING: - val = node.value - if not self.unicode_literals and val[0] in '\'"' and '\\' in val: - val = r'\\'.join([ - v.replace('\\u', r'\\u').replace('\\U', r'\\U') - for v in val.split(r'\\') - ]) - if val[0] in 'uU': - val = val[1:] - if val == node.value: - return node - new = node.clone() - new.value = val - return new diff --git a/Lib/lib2to3/fixes/fix_urllib.py b/Lib/lib2to3/fixes/fix_urllib.py deleted file mode 100644 index ab892bc52494c..0000000000000 --- a/Lib/lib2to3/fixes/fix_urllib.py +++ /dev/null @@ -1,196 +0,0 @@ -"""Fix changes imports of urllib which are now incompatible. - This is rather similar to fix_imports, but because of the more - complex nature of the fixing for urllib, it has its own fixer. -""" -# Author: Nick Edds - -# Local imports -from lib2to3.fixes.fix_imports import alternates, FixImports -from lib2to3.fixer_util import (Name, Comma, FromImport, Newline, - find_indentation, Node, syms) - -MAPPING = {"urllib": [ - ("urllib.request", - ["URLopener", "FancyURLopener", "urlretrieve", - "_urlopener", "urlopen", "urlcleanup", - "pathname2url", "url2pathname", "getproxies"]), - ("urllib.parse", - ["quote", "quote_plus", "unquote", "unquote_plus", - "urlencode", "splitattr", "splithost", "splitnport", - "splitpasswd", "splitport", "splitquery", "splittag", - "splittype", "splituser", "splitvalue", ]), - ("urllib.error", - ["ContentTooShortError"])], - "urllib2" : [ - ("urllib.request", - ["urlopen", "install_opener", "build_opener", - "Request", "OpenerDirector", "BaseHandler", - "HTTPDefaultErrorHandler", "HTTPRedirectHandler", - "HTTPCookieProcessor", "ProxyHandler", - "HTTPPasswordMgr", - "HTTPPasswordMgrWithDefaultRealm", - "AbstractBasicAuthHandler", - "HTTPBasicAuthHandler", "ProxyBasicAuthHandler", - "AbstractDigestAuthHandler", - "HTTPDigestAuthHandler", "ProxyDigestAuthHandler", - "HTTPHandler", "HTTPSHandler", "FileHandler", - "FTPHandler", "CacheFTPHandler", - "UnknownHandler"]), - ("urllib.error", - ["URLError", "HTTPError"]), - ] -} - -# Duplicate the url parsing functions for urllib2. -MAPPING["urllib2"].append(MAPPING["urllib"][1]) - - -def build_pattern(): - bare = set() - for old_module, changes in MAPPING.items(): - for change in changes: - new_module, members = change - members = alternates(members) - yield """import_name< 'import' (module=%r - | dotted_as_names< any* module=%r any* >) > - """ % (old_module, old_module) - yield """import_from< 'from' mod_member=%r 'import' - ( member=%s | import_as_name< member=%s 'as' any > | - import_as_names< members=any* >) > - """ % (old_module, members, members) - yield """import_from< 'from' module_star=%r 'import' star='*' > - """ % old_module - yield """import_name< 'import' - dotted_as_name< module_as=%r 'as' any > > - """ % old_module - # bare_with_attr has a special significance for FixImports.match(). - yield """power< bare_with_attr=%r trailer< '.' member=%s > any* > - """ % (old_module, members) - - -class FixUrllib(FixImports): - - def build_pattern(self): - return "|".join(build_pattern()) - - def transform_import(self, node, results): - """Transform for the basic import case. Replaces the old - import name with a comma separated list of its - replacements. - """ - import_mod = results.get("module") - pref = import_mod.prefix - - names = [] - - # create a Node list of the replacement modules - for name in MAPPING[import_mod.value][:-1]: - names.extend([Name(name[0], prefix=pref), Comma()]) - names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref)) - import_mod.replace(names) - - def transform_member(self, node, results): - """Transform for imports of specific module elements. Replaces - the module to be imported from with the appropriate new - module. - """ - mod_member = results.get("mod_member") - pref = mod_member.prefix - member = results.get("member") - - # Simple case with only a single member being imported - if member: - # this may be a list of length one, or just a node - if isinstance(member, list): - member = member[0] - new_name = None - for change in MAPPING[mod_member.value]: - if member.value in change[1]: - new_name = change[0] - break - if new_name: - mod_member.replace(Name(new_name, prefix=pref)) - else: - self.cannot_convert(node, "This is an invalid module element") - - # Multiple members being imported - else: - # a dictionary for replacements, order matters - modules = [] - mod_dict = {} - members = results["members"] - for member in members: - # we only care about the actual members - if member.type == syms.import_as_name: - as_name = member.children[2].value - member_name = member.children[0].value - else: - member_name = member.value - as_name = None - if member_name != ",": - for change in MAPPING[mod_member.value]: - if member_name in change[1]: - if change[0] not in mod_dict: - modules.append(change[0]) - mod_dict.setdefault(change[0], []).append(member) - - new_nodes = [] - indentation = find_indentation(node) - first = True - def handle_name(name, prefix): - if name.type == syms.import_as_name: - kids = [Name(name.children[0].value, prefix=prefix), - name.children[1].clone(), - name.children[2].clone()] - return [Node(syms.import_as_name, kids)] - return [Name(name.value, prefix=prefix)] - for module in modules: - elts = mod_dict[module] - names = [] - for elt in elts[:-1]: - names.extend(handle_name(elt, pref)) - names.append(Comma()) - names.extend(handle_name(elts[-1], pref)) - new = FromImport(module, names) - if not first or node.parent.prefix.endswith(indentation): - new.prefix = indentation - new_nodes.append(new) - first = False - if new_nodes: - nodes = [] - for new_node in new_nodes[:-1]: - nodes.extend([new_node, Newline()]) - nodes.append(new_nodes[-1]) - node.replace(nodes) - else: - self.cannot_convert(node, "All module elements are invalid") - - def transform_dot(self, node, results): - """Transform for calls to module members in code.""" - module_dot = results.get("bare_with_attr") - member = results.get("member") - new_name = None - if isinstance(member, list): - member = member[0] - for change in MAPPING[module_dot.value]: - if member.value in change[1]: - new_name = change[0] - break - if new_name: - module_dot.replace(Name(new_name, - prefix=module_dot.prefix)) - else: - self.cannot_convert(node, "This is an invalid module element") - - def transform(self, node, results): - if results.get("module"): - self.transform_import(node, results) - elif results.get("mod_member"): - self.transform_member(node, results) - elif results.get("bare_with_attr"): - self.transform_dot(node, results) - # Renaming and star imports are not supported for these modules. - elif results.get("module_star"): - self.cannot_convert(node, "Cannot handle star imports.") - elif results.get("module_as"): - self.cannot_convert(node, "This module is now multiple modules") diff --git a/Lib/lib2to3/fixes/fix_ws_comma.py b/Lib/lib2to3/fixes/fix_ws_comma.py deleted file mode 100644 index a54a376c472af..0000000000000 --- a/Lib/lib2to3/fixes/fix_ws_comma.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Fixer that changes 'a ,b' into 'a, b'. - -This also changes '{a :b}' into '{a: b}', but does not touch other -uses of colons. It does not touch other uses of whitespace. - -""" - -from .. import pytree -from ..pgen2 import token -from .. import fixer_base - -class FixWsComma(fixer_base.BaseFix): - - explicit = True # The user must ask for this fixers - - PATTERN = """ - any<(not(',') any)+ ',' ((not(',') any)+ ',')* [not(',') any]> - """ - - COMMA = pytree.Leaf(token.COMMA, ",") - COLON = pytree.Leaf(token.COLON, ":") - SEPS = (COMMA, COLON) - - def transform(self, node, results): - new = node.clone() - comma = False - for child in new.children: - if child in self.SEPS: - prefix = child.prefix - if prefix.isspace() and "\n" not in prefix: - child.prefix = "" - comma = True - else: - if comma: - prefix = child.prefix - if not prefix: - child.prefix = " " - comma = False - return new diff --git a/Lib/lib2to3/fixes/fix_xrange.py b/Lib/lib2to3/fixes/fix_xrange.py deleted file mode 100644 index 1e491e166a3f1..0000000000000 --- a/Lib/lib2to3/fixes/fix_xrange.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Fixer that changes xrange(...) into range(...).""" - -# Local imports -from .. import fixer_base -from ..fixer_util import Name, Call, consuming_calls -from .. import patcomp - - -class FixXrange(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< - (name='range'|name='xrange') trailer< '(' args=any ')' > - rest=any* > - """ - - def start_tree(self, tree, filename): - super(FixXrange, self).start_tree(tree, filename) - self.transformed_xranges = set() - - def finish_tree(self, tree, filename): - self.transformed_xranges = None - - def transform(self, node, results): - name = results["name"] - if name.value == "xrange": - return self.transform_xrange(node, results) - elif name.value == "range": - return self.transform_range(node, results) - else: - raise ValueError(repr(name)) - - def transform_xrange(self, node, results): - name = results["name"] - name.replace(Name("range", prefix=name.prefix)) - # This prevents the new range call from being wrapped in a list later. - self.transformed_xranges.add(id(node)) - - def transform_range(self, node, results): - if (id(node) not in self.transformed_xranges and - not self.in_special_context(node)): - range_call = Call(Name("range"), [results["args"].clone()]) - # Encase the range call in list(). - list_call = Call(Name("list"), [range_call], - prefix=node.prefix) - # Put things that were after the range() call after the list call. - for n in results["rest"]: - list_call.append_child(n) - return list_call - - P1 = "power< func=NAME trailer< '(' node=any ')' > any* >" - p1 = patcomp.compile_pattern(P1) - - P2 = """for_stmt< 'for' any 'in' node=any ':' any* > - | comp_for< 'for' any 'in' node=any any* > - | comparison< any 'in' node=any any*> - """ - p2 = patcomp.compile_pattern(P2) - - def in_special_context(self, node): - if node.parent is None: - return False - results = {} - if (node.parent.parent is not None and - self.p1.match(node.parent.parent, results) and - results["node"] is node): - # list(d.keys()) -> list(d.keys()), etc. - return results["func"].value in consuming_calls - # for ... in d.iterkeys() -> for ... in d.keys(), etc. - return self.p2.match(node.parent, results) and results["node"] is node diff --git a/Lib/lib2to3/fixes/fix_xreadlines.py b/Lib/lib2to3/fixes/fix_xreadlines.py deleted file mode 100644 index 3e3f71ab04557..0000000000000 --- a/Lib/lib2to3/fixes/fix_xreadlines.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Fix "for x in f.xreadlines()" -> "for x in f". - -This fixer will also convert g(f.xreadlines) into g(f.__iter__).""" -# Author: Collin Winter - -# Local imports -from .. import fixer_base -from ..fixer_util import Name - - -class FixXreadlines(fixer_base.BaseFix): - BM_compatible = True - PATTERN = """ - power< call=any+ trailer< '.' 'xreadlines' > trailer< '(' ')' > > - | - power< any+ trailer< '.' no_call='xreadlines' > > - """ - - def transform(self, node, results): - no_call = results.get("no_call") - - if no_call: - no_call.replace(Name("__iter__", prefix=no_call.prefix)) - else: - node.replace([x.clone() for x in results["call"]]) diff --git a/Lib/lib2to3/fixes/fix_zip.py b/Lib/lib2to3/fixes/fix_zip.py deleted file mode 100644 index 52c28df6aab41..0000000000000 --- a/Lib/lib2to3/fixes/fix_zip.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Fixer that changes zip(seq0, seq1, ...) into list(zip(seq0, seq1, ...) -unless there exists a 'from future_builtins import zip' statement in the -top-level namespace. - -We avoid the transformation if the zip() call is directly contained in -iter(<>), list(<>), tuple(<>), sorted(<>), ...join(<>), or for V in <>:. -""" - -# Local imports -from .. import fixer_base -from ..pytree import Node -from ..pygram import python_symbols as syms -from ..fixer_util import Name, ArgList, in_special_context - - -class FixZip(fixer_base.ConditionalFix): - - BM_compatible = True - PATTERN = """ - power< 'zip' args=trailer< '(' [any] ')' > [trailers=trailer*] - > - """ - - skip_on = "future_builtins.zip" - - def transform(self, node, results): - if self.should_skip(node): - return - - if in_special_context(node): - return None - - args = results['args'].clone() - args.prefix = "" - - trailers = [] - if 'trailers' in results: - trailers = [n.clone() for n in results['trailers']] - for n in trailers: - n.prefix = "" - - new = Node(syms.power, [Name("zip"), args], prefix="") - new = Node(syms.power, [Name("list"), ArgList([new])] + trailers) - new.prefix = node.prefix - return new diff --git a/Lib/lib2to3/main.py b/Lib/lib2to3/main.py deleted file mode 100644 index f2849fd6be3fd..0000000000000 --- a/Lib/lib2to3/main.py +++ /dev/null @@ -1,273 +0,0 @@ -""" -Main program for 2to3. -""" - -from __future__ import with_statement, print_function - -import sys -import os -import difflib -import logging -import shutil -import optparse - -from . import refactor - - -def diff_texts(a, b, filename): - """Return a unified diff of two strings.""" - a = a.splitlines() - b = b.splitlines() - return difflib.unified_diff(a, b, filename, filename, - "(original)", "(refactored)", - lineterm="") - - -class StdoutRefactoringTool(refactor.MultiprocessRefactoringTool): - """ - A refactoring tool that can avoid overwriting its input files. - Prints output to stdout. - - Output files can optionally be written to a different directory and or - have an extra file suffix appended to their name for use in situations - where you do not want to replace the input files. - """ - - def __init__(self, fixers, options, explicit, nobackups, show_diffs, - input_base_dir='', output_dir='', append_suffix=''): - """ - Args: - fixers: A list of fixers to import. - options: A dict with RefactoringTool configuration. - explicit: A list of fixers to run even if they are explicit. - nobackups: If true no backup '.bak' files will be created for those - files that are being refactored. - show_diffs: Should diffs of the refactoring be printed to stdout? - input_base_dir: The base directory for all input files. This class - will strip this path prefix off of filenames before substituting - it with output_dir. Only meaningful if output_dir is supplied. - All files processed by refactor() must start with this path. - output_dir: If supplied, all converted files will be written into - this directory tree instead of input_base_dir. - append_suffix: If supplied, all files output by this tool will have - this appended to their filename. Useful for changing .py to - .py3 for example by passing append_suffix='3'. - """ - self.nobackups = nobackups - self.show_diffs = show_diffs - if input_base_dir and not input_base_dir.endswith(os.sep): - input_base_dir += os.sep - self._input_base_dir = input_base_dir - self._output_dir = output_dir - self._append_suffix = append_suffix - super(StdoutRefactoringTool, self).__init__(fixers, options, explicit) - - def log_error(self, msg, *args, **kwargs): - self.errors.append((msg, args, kwargs)) - self.logger.error(msg, *args, **kwargs) - - def write_file(self, new_text, filename, old_text, encoding): - orig_filename = filename - if self._output_dir: - if filename.startswith(self._input_base_dir): - filename = os.path.join(self._output_dir, - filename[len(self._input_base_dir):]) - else: - raise ValueError('filename %s does not start with the ' - 'input_base_dir %s' % ( - filename, self._input_base_dir)) - if self._append_suffix: - filename += self._append_suffix - if orig_filename != filename: - output_dir = os.path.dirname(filename) - if not os.path.isdir(output_dir) and output_dir: - os.makedirs(output_dir) - self.log_message('Writing converted %s to %s.', orig_filename, - filename) - if not self.nobackups: - # Make backup - backup = filename + ".bak" - if os.path.lexists(backup): - try: - os.remove(backup) - except OSError: - self.log_message("Can't remove backup %s", backup) - try: - os.rename(filename, backup) - except OSError: - self.log_message("Can't rename %s to %s", filename, backup) - # Actually write the new file - write = super(StdoutRefactoringTool, self).write_file - write(new_text, filename, old_text, encoding) - if not self.nobackups: - shutil.copymode(backup, filename) - if orig_filename != filename: - # Preserve the file mode in the new output directory. - shutil.copymode(orig_filename, filename) - - def print_output(self, old, new, filename, equal): - if equal: - self.log_message("No changes to %s", filename) - else: - self.log_message("Refactored %s", filename) - if self.show_diffs: - diff_lines = diff_texts(old, new, filename) - try: - if self.output_lock is not None: - with self.output_lock: - for line in diff_lines: - print(line) - sys.stdout.flush() - else: - for line in diff_lines: - print(line) - except UnicodeEncodeError: - warn("couldn't encode %s's diff for your terminal" % - (filename,)) - return - -def warn(msg): - print("WARNING: %s" % (msg,), file=sys.stderr) - - -def main(fixer_pkg, args=None): - """Main program. - - Args: - fixer_pkg: the name of a package where the fixers are located. - args: optional; a list of command line arguments. If omitted, - sys.argv[1:] is used. - - Returns a suggested exit status (0, 1, 2). - """ - # Set up option parser - parser = optparse.OptionParser(usage="2to3 [options] file|dir ...") - parser.add_option("-d", "--doctests_only", action="store_true", - help="Fix up doctests only") - parser.add_option("-f", "--fix", action="append", default=[], - help="Each FIX specifies a transformation; default: all") - parser.add_option("-j", "--processes", action="store", default=1, - type="int", help="Run 2to3 concurrently") - parser.add_option("-x", "--nofix", action="append", default=[], - help="Prevent a transformation from being run") - parser.add_option("-l", "--list-fixes", action="store_true", - help="List available transformations") - parser.add_option("-p", "--print-function", action="store_true", - help="Modify the grammar so that print() is a function") - parser.add_option("-e", "--exec-function", action="store_true", - help="Modify the grammar so that exec() is a function") - parser.add_option("-v", "--verbose", action="store_true", - help="More verbose logging") - parser.add_option("--no-diffs", action="store_true", - help="Don't show diffs of the refactoring") - parser.add_option("-w", "--write", action="store_true", - help="Write back modified files") - parser.add_option("-n", "--nobackups", action="store_true", default=False, - help="Don't write backups for modified files") - parser.add_option("-o", "--output-dir", action="store", type="str", - default="", help="Put output files in this directory " - "instead of overwriting the input files. Requires -n.") - parser.add_option("-W", "--write-unchanged-files", action="store_true", - help="Also write files even if no changes were required" - " (useful with --output-dir); implies -w.") - parser.add_option("--add-suffix", action="store", type="str", default="", - help="Append this string to all output filenames." - " Requires -n if non-empty. " - "ex: --add-suffix='3' will generate .py3 files.") - - # Parse command line arguments - refactor_stdin = False - flags = {} - options, args = parser.parse_args(args) - if options.write_unchanged_files: - flags["write_unchanged_files"] = True - if not options.write: - warn("--write-unchanged-files/-W implies -w.") - options.write = True - # If we allowed these, the original files would be renamed to backup names - # but not replaced. - if options.output_dir and not options.nobackups: - parser.error("Can't use --output-dir/-o without -n.") - if options.add_suffix and not options.nobackups: - parser.error("Can't use --add-suffix without -n.") - - if not options.write and options.no_diffs: - warn("not writing files and not printing diffs; that's not very useful") - if not options.write and options.nobackups: - parser.error("Can't use -n without -w") - if options.list_fixes: - print("Available transformations for the -f/--fix option:") - for fixname in refactor.get_all_fix_names(fixer_pkg): - print(fixname) - if not args: - return 0 - if not args: - print("At least one file or directory argument required.", file=sys.stderr) - print("Use --help to show usage.", file=sys.stderr) - return 2 - if "-" in args: - refactor_stdin = True - if options.write: - print("Can't write to stdin.", file=sys.stderr) - return 2 - if options.print_function: - flags["print_function"] = True - - if options.exec_function: - flags["exec_function"] = True - - # Set up logging handler - level = logging.DEBUG if options.verbose else logging.INFO - logging.basicConfig(format='%(name)s: %(message)s', level=level) - logger = logging.getLogger('lib2to3.main') - - # Initialize the refactoring tool - avail_fixes = set(refactor.get_fixers_from_package(fixer_pkg)) - unwanted_fixes = set(fixer_pkg + ".fix_" + fix for fix in options.nofix) - explicit = set() - if options.fix: - all_present = False - for fix in options.fix: - if fix == "all": - all_present = True - else: - explicit.add(fixer_pkg + ".fix_" + fix) - requested = avail_fixes.union(explicit) if all_present else explicit - else: - requested = avail_fixes.union(explicit) - fixer_names = requested.difference(unwanted_fixes) - input_base_dir = os.path.commonprefix(args) - if (input_base_dir and not input_base_dir.endswith(os.sep) - and not os.path.isdir(input_base_dir)): - # One or more similar names were passed, their directory is the base. - # os.path.commonprefix() is ignorant of path elements, this corrects - # for that weird API. - input_base_dir = os.path.dirname(input_base_dir) - if options.output_dir: - input_base_dir = input_base_dir.rstrip(os.sep) - logger.info('Output in %r will mirror the input directory %r layout.', - options.output_dir, input_base_dir) - rt = StdoutRefactoringTool( - sorted(fixer_names), flags, sorted(explicit), - options.nobackups, not options.no_diffs, - input_base_dir=input_base_dir, - output_dir=options.output_dir, - append_suffix=options.add_suffix) - - # Refactor all files and directories passed as arguments - if not rt.errors: - if refactor_stdin: - rt.refactor_stdin() - else: - try: - rt.refactor(args, options.write, options.doctests_only, - options.processes) - except refactor.MultiprocessingUnsupported: - assert options.processes > 1 - print("Sorry, -j isn't supported on this platform.", - file=sys.stderr) - return 1 - rt.summarize() - - # Return error status (0 if rt.errors is zero) - return int(bool(rt.errors)) diff --git a/Lib/lib2to3/patcomp.py b/Lib/lib2to3/patcomp.py deleted file mode 100644 index f57f4954b26ce..0000000000000 --- a/Lib/lib2to3/patcomp.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Pattern compiler. - -The grammar is taken from PatternGrammar.txt. - -The compiler compiles a pattern to a pytree.*Pattern instance. -""" - -__author__ = "Guido van Rossum <guido at python.org>" - -# Python imports -import io - -# Fairly local imports -from .pgen2 import driver, literals, token, tokenize, parse, grammar - -# Really local imports -from . import pytree -from . import pygram - - -class PatternSyntaxError(Exception): - pass - - -def tokenize_wrapper(input): - """Tokenizes a string suppressing significant whitespace.""" - skip = {token.NEWLINE, token.INDENT, token.DEDENT} - tokens = tokenize.generate_tokens(io.StringIO(input).readline) - for quintuple in tokens: - type, value, start, end, line_text = quintuple - if type not in skip: - yield quintuple - - -class PatternCompiler(object): - - def __init__(self, grammar_file=None): - """Initializer. - - Takes an optional alternative filename for the pattern grammar. - """ - if grammar_file is None: - self.grammar = pygram.pattern_grammar - self.syms = pygram.pattern_symbols - else: - self.grammar = driver.load_grammar(grammar_file) - self.syms = pygram.Symbols(self.grammar) - self.pygrammar = pygram.python_grammar - self.pysyms = pygram.python_symbols - self.driver = driver.Driver(self.grammar, convert=pattern_convert) - - def compile_pattern(self, input, debug=False, with_tree=False): - """Compiles a pattern string to a nested pytree.*Pattern object.""" - tokens = tokenize_wrapper(input) - try: - root = self.driver.parse_tokens(tokens, debug=debug) - except parse.ParseError as e: - raise PatternSyntaxError(str(e)) from None - if with_tree: - return self.compile_node(root), root - else: - return self.compile_node(root) - - def compile_node(self, node): - """Compiles a node, recursively. - - This is one big switch on the node type. - """ - # XXX Optimize certain Wildcard-containing-Wildcard patterns - # that can be merged - if node.type == self.syms.Matcher: - node = node.children[0] # Avoid unneeded recursion - - if node.type == self.syms.Alternatives: - # Skip the odd children since they are just '|' tokens - alts = [self.compile_node(ch) for ch in node.children[::2]] - if len(alts) == 1: - return alts[0] - p = pytree.WildcardPattern([[a] for a in alts], min=1, max=1) - return p.optimize() - - if node.type == self.syms.Alternative: - units = [self.compile_node(ch) for ch in node.children] - if len(units) == 1: - return units[0] - p = pytree.WildcardPattern([units], min=1, max=1) - return p.optimize() - - if node.type == self.syms.NegatedUnit: - pattern = self.compile_basic(node.children[1:]) - p = pytree.NegatedPattern(pattern) - return p.optimize() - - assert node.type == self.syms.Unit - - name = None - nodes = node.children - if len(nodes) >= 3 and nodes[1].type == token.EQUAL: - name = nodes[0].value - nodes = nodes[2:] - repeat = None - if len(nodes) >= 2 and nodes[-1].type == self.syms.Repeater: - repeat = nodes[-1] - nodes = nodes[:-1] - - # Now we've reduced it to: STRING | NAME [Details] | (...) | [...] - pattern = self.compile_basic(nodes, repeat) - - if repeat is not None: - assert repeat.type == self.syms.Repeater - children = repeat.children - child = children[0] - if child.type == token.STAR: - min = 0 - max = pytree.HUGE - elif child.type == token.PLUS: - min = 1 - max = pytree.HUGE - elif child.type == token.LBRACE: - assert children[-1].type == token.RBRACE - assert len(children) in (3, 5) - min = max = self.get_int(children[1]) - if len(children) == 5: - max = self.get_int(children[3]) - else: - assert False - if min != 1 or max != 1: - pattern = pattern.optimize() - pattern = pytree.WildcardPattern([[pattern]], min=min, max=max) - - if name is not None: - pattern.name = name - return pattern.optimize() - - def compile_basic(self, nodes, repeat=None): - # Compile STRING | NAME [Details] | (...) | [...] - assert len(nodes) >= 1 - node = nodes[0] - if node.type == token.STRING: - value = str(literals.evalString(node.value)) - return pytree.LeafPattern(_type_of_literal(value), value) - elif node.type == token.NAME: - value = node.value - if value.isupper(): - if value not in TOKEN_MAP: - raise PatternSyntaxError("Invalid token: %r" % value) - if nodes[1:]: - raise PatternSyntaxError("Can't have details for token") - return pytree.LeafPattern(TOKEN_MAP[value]) - else: - if value == "any": - type = None - elif not value.startswith("_"): - type = getattr(self.pysyms, value, None) - if type is None: - raise PatternSyntaxError("Invalid symbol: %r" % value) - if nodes[1:]: # Details present - content = [self.compile_node(nodes[1].children[1])] - else: - content = None - return pytree.NodePattern(type, content) - elif node.value == "(": - return self.compile_node(nodes[1]) - elif node.value == "[": - assert repeat is None - subpattern = self.compile_node(nodes[1]) - return pytree.WildcardPattern([[subpattern]], min=0, max=1) - assert False, node - - def get_int(self, node): - assert node.type == token.NUMBER - return int(node.value) - - -# Map named tokens to the type value for a LeafPattern -TOKEN_MAP = {"NAME": token.NAME, - "STRING": token.STRING, - "NUMBER": token.NUMBER, - "TOKEN": None} - - -def _type_of_literal(value): - if value[0].isalpha(): - return token.NAME - elif value in grammar.opmap: - return grammar.opmap[value] - else: - return None - - -def pattern_convert(grammar, raw_node_info): - """Converts raw node information to a Node or Leaf instance.""" - type, value, context, children = raw_node_info - if children or type in grammar.number2symbol: - return pytree.Node(type, children, context=context) - else: - return pytree.Leaf(type, value, context=context) - - -def compile_pattern(pattern): - return PatternCompiler().compile_pattern(pattern) diff --git a/Lib/lib2to3/pgen2/__init__.py b/Lib/lib2to3/pgen2/__init__.py deleted file mode 100644 index af390484528d8..0000000000000 --- a/Lib/lib2to3/pgen2/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""The pgen2 package.""" diff --git a/Lib/lib2to3/pgen2/conv.py b/Lib/lib2to3/pgen2/conv.py deleted file mode 100644 index ed0cac532e424..0000000000000 --- a/Lib/lib2to3/pgen2/conv.py +++ /dev/null @@ -1,257 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Convert graminit.[ch] spit out by pgen to Python code. - -Pgen is the Python parser generator. It is useful to quickly create a -parser from a grammar file in Python's grammar notation. But I don't -want my parsers to be written in C (yet), so I'm translating the -parsing tables to Python data structures and writing a Python parse -engine. - -Note that the token numbers are constants determined by the standard -Python tokenizer. The standard token module defines these numbers and -their names (the names are not used much). The token numbers are -hardcoded into the Python tokenizer and into pgen. A Python -implementation of the Python tokenizer is also available, in the -standard tokenize module. - -On the other hand, symbol numbers (representing the grammar's -non-terminals) are assigned by pgen based on the actual grammar -input. - -Note: this module is pretty much obsolete; the pgen module generates -equivalent grammar tables directly from the Grammar.txt input file -without having to invoke the Python pgen C program. - -""" - -# Python imports -import re - -# Local imports -from pgen2 import grammar, token - - -class Converter(grammar.Grammar): - """Grammar subclass that reads classic pgen output files. - - The run() method reads the tables as produced by the pgen parser - generator, typically contained in two C files, graminit.h and - graminit.c. The other methods are for internal use only. - - See the base class for more documentation. - - """ - - def run(self, graminit_h, graminit_c): - """Load the grammar tables from the text files written by pgen.""" - self.parse_graminit_h(graminit_h) - self.parse_graminit_c(graminit_c) - self.finish_off() - - def parse_graminit_h(self, filename): - """Parse the .h file written by pgen. (Internal) - - This file is a sequence of #define statements defining the - nonterminals of the grammar as numbers. We build two tables - mapping the numbers to names and back. - - """ - try: - f = open(filename) - except OSError as err: - print("Can't open %s: %s" % (filename, err)) - return False - self.symbol2number = {} - self.number2symbol = {} - lineno = 0 - for line in f: - lineno += 1 - mo = re.match(r"^#define\s+(\w+)\s+(\d+)$", line) - if not mo and line.strip(): - print("%s(%s): can't parse %s" % (filename, lineno, - line.strip())) - else: - symbol, number = mo.groups() - number = int(number) - assert symbol not in self.symbol2number - assert number not in self.number2symbol - self.symbol2number[symbol] = number - self.number2symbol[number] = symbol - return True - - def parse_graminit_c(self, filename): - """Parse the .c file written by pgen. (Internal) - - The file looks as follows. The first two lines are always this: - - #include "pgenheaders.h" - #include "grammar.h" - - After that come four blocks: - - 1) one or more state definitions - 2) a table defining dfas - 3) a table defining labels - 4) a struct defining the grammar - - A state definition has the following form: - - one or more arc arrays, each of the form: - static arc arcs_<n>_<m>[<k>] = { - {<i>, <j>}, - ... - }; - - followed by a state array, of the form: - static state states_<s>[<t>] = { - {<k>, arcs_<n>_<m>}, - ... - }; - - """ - try: - f = open(filename) - except OSError as err: - print("Can't open %s: %s" % (filename, err)) - return False - # The code below essentially uses f's iterator-ness! - lineno = 0 - - # Expect the two #include lines - lineno, line = lineno+1, next(f) - assert line == '#include "pgenheaders.h"\n', (lineno, line) - lineno, line = lineno+1, next(f) - assert line == '#include "grammar.h"\n', (lineno, line) - - # Parse the state definitions - lineno, line = lineno+1, next(f) - allarcs = {} - states = [] - while line.startswith("static arc "): - while line.startswith("static arc "): - mo = re.match(r"static arc arcs_(\d+)_(\d+)\[(\d+)\] = {$", - line) - assert mo, (lineno, line) - n, m, k = list(map(int, mo.groups())) - arcs = [] - for _ in range(k): - lineno, line = lineno+1, next(f) - mo = re.match(r"\s+{(\d+), (\d+)},$", line) - assert mo, (lineno, line) - i, j = list(map(int, mo.groups())) - arcs.append((i, j)) - lineno, line = lineno+1, next(f) - assert line == "};\n", (lineno, line) - allarcs[(n, m)] = arcs - lineno, line = lineno+1, next(f) - mo = re.match(r"static state states_(\d+)\[(\d+)\] = {$", line) - assert mo, (lineno, line) - s, t = list(map(int, mo.groups())) - assert s == len(states), (lineno, line) - state = [] - for _ in range(t): - lineno, line = lineno+1, next(f) - mo = re.match(r"\s+{(\d+), arcs_(\d+)_(\d+)},$", line) - assert mo, (lineno, line) - k, n, m = list(map(int, mo.groups())) - arcs = allarcs[n, m] - assert k == len(arcs), (lineno, line) - state.append(arcs) - states.append(state) - lineno, line = lineno+1, next(f) - assert line == "};\n", (lineno, line) - lineno, line = lineno+1, next(f) - self.states = states - - # Parse the dfas - dfas = {} - mo = re.match(r"static dfa dfas\[(\d+)\] = {$", line) - assert mo, (lineno, line) - ndfas = int(mo.group(1)) - for i in range(ndfas): - lineno, line = lineno+1, next(f) - mo = re.match(r'\s+{(\d+), "(\w+)", (\d+), (\d+), states_(\d+),$', - line) - assert mo, (lineno, line) - symbol = mo.group(2) - number, x, y, z = list(map(int, mo.group(1, 3, 4, 5))) - assert self.symbol2number[symbol] == number, (lineno, line) - assert self.number2symbol[number] == symbol, (lineno, line) - assert x == 0, (lineno, line) - state = states[z] - assert y == len(state), (lineno, line) - lineno, line = lineno+1, next(f) - mo = re.match(r'\s+("(?:\\\d\d\d)*")},$', line) - assert mo, (lineno, line) - first = {} - rawbitset = eval(mo.group(1)) - for i, c in enumerate(rawbitset): - byte = ord(c) - for j in range(8): - if byte & (1<<j): - first[i*8 + j] = 1 - dfas[number] = (state, first) - lineno, line = lineno+1, next(f) - assert line == "};\n", (lineno, line) - self.dfas = dfas - - # Parse the labels - labels = [] - lineno, line = lineno+1, next(f) - mo = re.match(r"static label labels\[(\d+)\] = {$", line) - assert mo, (lineno, line) - nlabels = int(mo.group(1)) - for i in range(nlabels): - lineno, line = lineno+1, next(f) - mo = re.match(r'\s+{(\d+), (0|"\w+")},$', line) - assert mo, (lineno, line) - x, y = mo.groups() - x = int(x) - if y == "0": - y = None - else: - y = eval(y) - labels.append((x, y)) - lineno, line = lineno+1, next(f) - assert line == "};\n", (lineno, line) - self.labels = labels - - # Parse the grammar struct - lineno, line = lineno+1, next(f) - assert line == "grammar _PyParser_Grammar = {\n", (lineno, line) - lineno, line = lineno+1, next(f) - mo = re.match(r"\s+(\d+),$", line) - assert mo, (lineno, line) - ndfas = int(mo.group(1)) - assert ndfas == len(self.dfas) - lineno, line = lineno+1, next(f) - assert line == "\tdfas,\n", (lineno, line) - lineno, line = lineno+1, next(f) - mo = re.match(r"\s+{(\d+), labels},$", line) - assert mo, (lineno, line) - nlabels = int(mo.group(1)) - assert nlabels == len(self.labels), (lineno, line) - lineno, line = lineno+1, next(f) - mo = re.match(r"\s+(\d+)$", line) - assert mo, (lineno, line) - start = int(mo.group(1)) - assert start in self.number2symbol, (lineno, line) - self.start = start - lineno, line = lineno+1, next(f) - assert line == "};\n", (lineno, line) - try: - lineno, line = lineno+1, next(f) - except StopIteration: - pass - else: - assert 0, (lineno, line) - - def finish_off(self): - """Create additional useful structures. (Internal).""" - self.keywords = {} # map from keyword strings to arc labels - self.tokens = {} # map from numeric token values to arc labels - for ilabel, (type, value) in enumerate(self.labels): - if type == token.NAME and value is not None: - self.keywords[value] = ilabel - elif value is None: - self.tokens[type] = ilabel diff --git a/Lib/lib2to3/pgen2/driver.py b/Lib/lib2to3/pgen2/driver.py deleted file mode 100644 index 6471635a3192d..0000000000000 --- a/Lib/lib2to3/pgen2/driver.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -# Modifications: -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Parser driver. - -This provides a high-level interface to parse a file into a syntax tree. - -""" - -__author__ = "Guido van Rossum <guido at python.org>" - -__all__ = ["Driver", "load_grammar"] - -# Python imports -import io -import os -import logging -import pkgutil -import sys - -# Pgen imports -from . import grammar, parse, token, tokenize, pgen - - -class Driver(object): - - def __init__(self, grammar, convert=None, logger=None): - self.grammar = grammar - if logger is None: - logger = logging.getLogger() - self.logger = logger - self.convert = convert - - def parse_tokens(self, tokens, debug=False): - """Parse a series of tokens and return the syntax tree.""" - # XXX Move the prefix computation into a wrapper around tokenize. - p = parse.Parser(self.grammar, self.convert) - p.setup() - lineno = 1 - column = 0 - type = value = start = end = line_text = None - prefix = "" - for quintuple in tokens: - type, value, start, end, line_text = quintuple - if start != (lineno, column): - assert (lineno, column) <= start, ((lineno, column), start) - s_lineno, s_column = start - if lineno < s_lineno: - prefix += "\n" * (s_lineno - lineno) - lineno = s_lineno - column = 0 - if column < s_column: - prefix += line_text[column:s_column] - column = s_column - if type in (tokenize.COMMENT, tokenize.NL): - prefix += value - lineno, column = end - if value.endswith("\n"): - lineno += 1 - column = 0 - continue - if type == token.OP: - type = grammar.opmap[value] - if debug: - self.logger.debug("%s %r (prefix=%r)", - token.tok_name[type], value, prefix) - if p.addtoken(type, value, (prefix, start)): - if debug: - self.logger.debug("Stop.") - break - prefix = "" - lineno, column = end - if value.endswith("\n"): - lineno += 1 - column = 0 - else: - # We never broke out -- EOF is too soon (how can this happen???) - raise parse.ParseError("incomplete input", - type, value, (prefix, start)) - return p.rootnode - - def parse_stream_raw(self, stream, debug=False): - """Parse a stream and return the syntax tree.""" - tokens = tokenize.generate_tokens(stream.readline) - return self.parse_tokens(tokens, debug) - - def parse_stream(self, stream, debug=False): - """Parse a stream and return the syntax tree.""" - return self.parse_stream_raw(stream, debug) - - def parse_file(self, filename, encoding=None, debug=False): - """Parse a file and return the syntax tree.""" - with io.open(filename, "r", encoding=encoding) as stream: - return self.parse_stream(stream, debug) - - def parse_string(self, text, debug=False): - """Parse a string and return the syntax tree.""" - tokens = tokenize.generate_tokens(io.StringIO(text).readline) - return self.parse_tokens(tokens, debug) - - -def _generate_pickle_name(gt): - head, tail = os.path.splitext(gt) - if tail == ".txt": - tail = "" - return head + tail + ".".join(map(str, sys.version_info)) + ".pickle" - - -def load_grammar(gt="Grammar.txt", gp=None, - save=True, force=False, logger=None): - """Load the grammar (maybe from a pickle).""" - if logger is None: - logger = logging.getLogger() - gp = _generate_pickle_name(gt) if gp is None else gp - if force or not _newer(gp, gt): - logger.info("Generating grammar tables from %s", gt) - g = pgen.generate_grammar(gt) - if save: - logger.info("Writing grammar tables to %s", gp) - try: - g.dump(gp) - except OSError as e: - logger.info("Writing failed: %s", e) - else: - g = grammar.Grammar() - g.load(gp) - return g - - -def _newer(a, b): - """Inquire whether file a was written since file b.""" - if not os.path.exists(a): - return False - if not os.path.exists(b): - return True - return os.path.getmtime(a) >= os.path.getmtime(b) - - -def load_packaged_grammar(package, grammar_source): - """Normally, loads a pickled grammar by doing - pkgutil.get_data(package, pickled_grammar) - where *pickled_grammar* is computed from *grammar_source* by adding the - Python version and using a ``.pickle`` extension. - - However, if *grammar_source* is an extant file, load_grammar(grammar_source) - is called instead. This facilitates using a packaged grammar file when needed - but preserves load_grammar's automatic regeneration behavior when possible. - - """ - if os.path.isfile(grammar_source): - return load_grammar(grammar_source) - pickled_name = _generate_pickle_name(os.path.basename(grammar_source)) - data = pkgutil.get_data(package, pickled_name) - g = grammar.Grammar() - g.loads(data) - return g - - -def main(*args): - """Main program, when run as a script: produce grammar pickle files. - - Calls load_grammar for each argument, a path to a grammar text file. - """ - if not args: - args = sys.argv[1:] - logging.basicConfig(level=logging.INFO, stream=sys.stdout, - format='%(message)s') - for gt in args: - load_grammar(gt, save=True, force=True) - return True - -if __name__ == "__main__": - sys.exit(int(not main())) diff --git a/Lib/lib2to3/pgen2/grammar.py b/Lib/lib2to3/pgen2/grammar.py deleted file mode 100644 index 5d550aeb65e8d..0000000000000 --- a/Lib/lib2to3/pgen2/grammar.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""This module defines the data structures used to represent a grammar. - -These are a bit arcane because they are derived from the data -structures used by Python's 'pgen' parser generator. - -There's also a table here mapping operators to their names in the -token module; the Python tokenize module reports all operators as the -fallback token code OP, but the parser needs the actual token code. - -""" - -# Python imports -import pickle - -# Local imports -from . import token - - -class Grammar(object): - """Pgen parsing tables conversion class. - - Once initialized, this class supplies the grammar tables for the - parsing engine implemented by parse.py. The parsing engine - accesses the instance variables directly. The class here does not - provide initialization of the tables; several subclasses exist to - do this (see the conv and pgen modules). - - The load() method reads the tables from a pickle file, which is - much faster than the other ways offered by subclasses. The pickle - file is written by calling dump() (after loading the grammar - tables using a subclass). The report() method prints a readable - representation of the tables to stdout, for debugging. - - The instance variables are as follows: - - symbol2number -- a dict mapping symbol names to numbers. Symbol - numbers are always 256 or higher, to distinguish - them from token numbers, which are between 0 and - 255 (inclusive). - - number2symbol -- a dict mapping numbers to symbol names; - these two are each other's inverse. - - states -- a list of DFAs, where each DFA is a list of - states, each state is a list of arcs, and each - arc is a (i, j) pair where i is a label and j is - a state number. The DFA number is the index into - this list. (This name is slightly confusing.) - Final states are represented by a special arc of - the form (0, j) where j is its own state number. - - dfas -- a dict mapping symbol numbers to (DFA, first) - pairs, where DFA is an item from the states list - above, and first is a set of tokens that can - begin this grammar rule (represented by a dict - whose values are always 1). - - labels -- a list of (x, y) pairs where x is either a token - number or a symbol number, and y is either None - or a string; the strings are keywords. The label - number is the index in this list; label numbers - are used to mark state transitions (arcs) in the - DFAs. - - start -- the number of the grammar's start symbol. - - keywords -- a dict mapping keyword strings to arc labels. - - tokens -- a dict mapping token numbers to arc labels. - - """ - - def __init__(self): - self.symbol2number = {} - self.number2symbol = {} - self.states = [] - self.dfas = {} - self.labels = [(0, "EMPTY")] - self.keywords = {} - self.tokens = {} - self.symbol2label = {} - self.start = 256 - - def dump(self, filename): - """Dump the grammar tables to a pickle file.""" - with open(filename, "wb") as f: - pickle.dump(self.__dict__, f, pickle.HIGHEST_PROTOCOL) - - def load(self, filename): - """Load the grammar tables from a pickle file.""" - with open(filename, "rb") as f: - d = pickle.load(f) - self.__dict__.update(d) - - def loads(self, pkl): - """Load the grammar tables from a pickle bytes object.""" - self.__dict__.update(pickle.loads(pkl)) - - def copy(self): - """ - Copy the grammar. - """ - new = self.__class__() - for dict_attr in ("symbol2number", "number2symbol", "dfas", "keywords", - "tokens", "symbol2label"): - setattr(new, dict_attr, getattr(self, dict_attr).copy()) - new.labels = self.labels[:] - new.states = self.states[:] - new.start = self.start - return new - - def report(self): - """Dump the grammar tables to standard output, for debugging.""" - from pprint import pprint - print("s2n") - pprint(self.symbol2number) - print("n2s") - pprint(self.number2symbol) - print("states") - pprint(self.states) - print("dfas") - pprint(self.dfas) - print("labels") - pprint(self.labels) - print("start", self.start) - - -# Map from operator to number (since tokenize doesn't do this) - -opmap_raw = """ -( LPAR -) RPAR -[ LSQB -] RSQB -: COLON -, COMMA -; SEMI -+ PLUS -- MINUS -* STAR -/ SLASH -| VBAR -& AMPER -< LESS -> GREATER -= EQUAL -. DOT -% PERCENT -` BACKQUOTE -{ LBRACE -} RBRACE -@ AT -@= ATEQUAL -== EQEQUAL -!= NOTEQUAL -<> NOTEQUAL -<= LESSEQUAL ->= GREATEREQUAL -~ TILDE -^ CIRCUMFLEX -<< LEFTSHIFT ->> RIGHTSHIFT -** DOUBLESTAR -+= PLUSEQUAL --= MINEQUAL -*= STAREQUAL -/= SLASHEQUAL -%= PERCENTEQUAL -&= AMPEREQUAL -|= VBAREQUAL -^= CIRCUMFLEXEQUAL -<<= LEFTSHIFTEQUAL ->>= RIGHTSHIFTEQUAL -**= DOUBLESTAREQUAL -// DOUBLESLASH -//= DOUBLESLASHEQUAL --> RARROW -:= COLONEQUAL -""" - -opmap = {} -for line in opmap_raw.splitlines(): - if line: - op, name = line.split() - opmap[op] = getattr(token, name) -del line, op, name diff --git a/Lib/lib2to3/pgen2/literals.py b/Lib/lib2to3/pgen2/literals.py deleted file mode 100644 index b9b63e6e5572c..0000000000000 --- a/Lib/lib2to3/pgen2/literals.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Safely evaluate Python string literals without using eval().""" - -import re - -simple_escapes = {"a": "\a", - "b": "\b", - "f": "\f", - "n": "\n", - "r": "\r", - "t": "\t", - "v": "\v", - "'": "'", - '"': '"', - "\\": "\\"} - -def escape(m): - all, tail = m.group(0, 1) - assert all.startswith("\\") - esc = simple_escapes.get(tail) - if esc is not None: - return esc - if tail.startswith("x"): - hexes = tail[1:] - if len(hexes) < 2: - raise ValueError("invalid hex string escape ('\\%s')" % tail) - try: - i = int(hexes, 16) - except ValueError: - raise ValueError("invalid hex string escape ('\\%s')" % tail) from None - else: - try: - i = int(tail, 8) - except ValueError: - raise ValueError("invalid octal string escape ('\\%s')" % tail) from None - return chr(i) - -def evalString(s): - assert s.startswith("'") or s.startswith('"'), repr(s[:1]) - q = s[0] - if s[:3] == q*3: - q = q*3 - assert s.endswith(q), repr(s[-len(q):]) - assert len(s) >= 2*len(q) - s = s[len(q):-len(q)] - return re.sub(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})", escape, s) - -def test(): - for i in range(256): - c = chr(i) - s = repr(c) - e = evalString(s) - if e != c: - print(i, c, s, e) - - -if __name__ == "__main__": - test() diff --git a/Lib/lib2to3/pgen2/parse.py b/Lib/lib2to3/pgen2/parse.py deleted file mode 100644 index cf3fcf7e99fd1..0000000000000 --- a/Lib/lib2to3/pgen2/parse.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Parser engine for the grammar tables generated by pgen. - -The grammar table must be loaded first. - -See Parser/parser.c in the Python distribution for additional info on -how this parsing engine works. - -""" - -# Local imports -from . import token - -class ParseError(Exception): - """Exception to signal the parser is stuck.""" - - def __init__(self, msg, type, value, context): - Exception.__init__(self, "%s: type=%r, value=%r, context=%r" % - (msg, type, value, context)) - self.msg = msg - self.type = type - self.value = value - self.context = context - - def __reduce__(self): - return type(self), (self.msg, self.type, self.value, self.context) - -class Parser(object): - """Parser engine. - - The proper usage sequence is: - - p = Parser(grammar, [converter]) # create instance - p.setup([start]) # prepare for parsing - <for each input token>: - if p.addtoken(...): # parse a token; may raise ParseError - break - root = p.rootnode # root of abstract syntax tree - - A Parser instance may be reused by calling setup() repeatedly. - - A Parser instance contains state pertaining to the current token - sequence, and should not be used concurrently by different threads - to parse separate token sequences. - - See driver.py for how to get input tokens by tokenizing a file or - string. - - Parsing is complete when addtoken() returns True; the root of the - abstract syntax tree can then be retrieved from the rootnode - instance variable. When a syntax error occurs, addtoken() raises - the ParseError exception. There is no error recovery; the parser - cannot be used after a syntax error was reported (but it can be - reinitialized by calling setup()). - - """ - - def __init__(self, grammar, convert=None): - """Constructor. - - The grammar argument is a grammar.Grammar instance; see the - grammar module for more information. - - The parser is not ready yet for parsing; you must call the - setup() method to get it started. - - The optional convert argument is a function mapping concrete - syntax tree nodes to abstract syntax tree nodes. If not - given, no conversion is done and the syntax tree produced is - the concrete syntax tree. If given, it must be a function of - two arguments, the first being the grammar (a grammar.Grammar - instance), and the second being the concrete syntax tree node - to be converted. The syntax tree is converted from the bottom - up. - - A concrete syntax tree node is a (type, value, context, nodes) - tuple, where type is the node type (a token or symbol number), - value is None for symbols and a string for tokens, context is - None or an opaque value used for error reporting (typically a - (lineno, offset) pair), and nodes is a list of children for - symbols, and None for tokens. - - An abstract syntax tree node may be anything; this is entirely - up to the converter function. - - """ - self.grammar = grammar - self.convert = convert or (lambda grammar, node: node) - - def setup(self, start=None): - """Prepare for parsing. - - This *must* be called before starting to parse. - - The optional argument is an alternative start symbol; it - defaults to the grammar's start symbol. - - You can use a Parser instance to parse any number of programs; - each time you call setup() the parser is reset to an initial - state determined by the (implicit or explicit) start symbol. - - """ - if start is None: - start = self.grammar.start - # Each stack entry is a tuple: (dfa, state, node). - # A node is a tuple: (type, value, context, children), - # where children is a list of nodes or None, and context may be None. - newnode = (start, None, None, []) - stackentry = (self.grammar.dfas[start], 0, newnode) - self.stack = [stackentry] - self.rootnode = None - self.used_names = set() # Aliased to self.rootnode.used_names in pop() - - def addtoken(self, type, value, context): - """Add a token; return True iff this is the end of the program.""" - # Map from token to label - ilabel = self.classify(type, value, context) - # Loop until the token is shifted; may raise exceptions - while True: - dfa, state, node = self.stack[-1] - states, first = dfa - arcs = states[state] - # Look for a state with this label - for i, newstate in arcs: - t, v = self.grammar.labels[i] - if ilabel == i: - # Look it up in the list of labels - assert t < 256 - # Shift a token; we're done with it - self.shift(type, value, newstate, context) - # Pop while we are in an accept-only state - state = newstate - while states[state] == [(0, state)]: - self.pop() - if not self.stack: - # Done parsing! - return True - dfa, state, node = self.stack[-1] - states, first = dfa - # Done with this token - return False - elif t >= 256: - # See if it's a symbol and if we're in its first set - itsdfa = self.grammar.dfas[t] - itsstates, itsfirst = itsdfa - if ilabel in itsfirst: - # Push a symbol - self.push(t, self.grammar.dfas[t], newstate, context) - break # To continue the outer while loop - else: - if (0, state) in arcs: - # An accepting state, pop it and try something else - self.pop() - if not self.stack: - # Done parsing, but another token is input - raise ParseError("too much input", - type, value, context) - else: - # No success finding a transition - raise ParseError("bad input", type, value, context) - - def classify(self, type, value, context): - """Turn a token into a label. (Internal)""" - if type == token.NAME: - # Keep a listing of all used names - self.used_names.add(value) - # Check for reserved words - ilabel = self.grammar.keywords.get(value) - if ilabel is not None: - return ilabel - ilabel = self.grammar.tokens.get(type) - if ilabel is None: - raise ParseError("bad token", type, value, context) - return ilabel - - def shift(self, type, value, newstate, context): - """Shift a token. (Internal)""" - dfa, state, node = self.stack[-1] - newnode = (type, value, context, None) - newnode = self.convert(self.grammar, newnode) - if newnode is not None: - node[-1].append(newnode) - self.stack[-1] = (dfa, newstate, node) - - def push(self, type, newdfa, newstate, context): - """Push a nonterminal. (Internal)""" - dfa, state, node = self.stack[-1] - newnode = (type, None, context, []) - self.stack[-1] = (dfa, newstate, node) - self.stack.append((newdfa, 0, newnode)) - - def pop(self): - """Pop a nonterminal. (Internal)""" - popdfa, popstate, popnode = self.stack.pop() - newnode = self.convert(self.grammar, popnode) - if newnode is not None: - if self.stack: - dfa, state, node = self.stack[-1] - node[-1].append(newnode) - else: - self.rootnode = newnode - self.rootnode.used_names = self.used_names diff --git a/Lib/lib2to3/pgen2/pgen.py b/Lib/lib2to3/pgen2/pgen.py deleted file mode 100644 index 7abd5cef1c36b..0000000000000 --- a/Lib/lib2to3/pgen2/pgen.py +++ /dev/null @@ -1,386 +0,0 @@ -# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -# Pgen imports -from . import grammar, token, tokenize - -class PgenGrammar(grammar.Grammar): - pass - -class ParserGenerator(object): - - def __init__(self, filename, stream=None): - close_stream = None - if stream is None: - stream = open(filename, encoding="utf-8") - close_stream = stream.close - self.filename = filename - self.stream = stream - self.generator = tokenize.generate_tokens(stream.readline) - self.gettoken() # Initialize lookahead - self.dfas, self.startsymbol = self.parse() - if close_stream is not None: - close_stream() - self.first = {} # map from symbol name to set of tokens - self.addfirstsets() - - def make_grammar(self): - c = PgenGrammar() - names = list(self.dfas.keys()) - names.sort() - names.remove(self.startsymbol) - names.insert(0, self.startsymbol) - for name in names: - i = 256 + len(c.symbol2number) - c.symbol2number[name] = i - c.number2symbol[i] = name - for name in names: - dfa = self.dfas[name] - states = [] - for state in dfa: - arcs = [] - for label, next in sorted(state.arcs.items()): - arcs.append((self.make_label(c, label), dfa.index(next))) - if state.isfinal: - arcs.append((0, dfa.index(state))) - states.append(arcs) - c.states.append(states) - c.dfas[c.symbol2number[name]] = (states, self.make_first(c, name)) - c.start = c.symbol2number[self.startsymbol] - return c - - def make_first(self, c, name): - rawfirst = self.first[name] - first = {} - for label in sorted(rawfirst): - ilabel = self.make_label(c, label) - ##assert ilabel not in first # XXX failed on <> ... != - first[ilabel] = 1 - return first - - def make_label(self, c, label): - # XXX Maybe this should be a method on a subclass of converter? - ilabel = len(c.labels) - if label[0].isalpha(): - # Either a symbol name or a named token - if label in c.symbol2number: - # A symbol name (a non-terminal) - if label in c.symbol2label: - return c.symbol2label[label] - else: - c.labels.append((c.symbol2number[label], None)) - c.symbol2label[label] = ilabel - return ilabel - else: - # A named token (NAME, NUMBER, STRING) - itoken = getattr(token, label, None) - assert isinstance(itoken, int), label - assert itoken in token.tok_name, label - if itoken in c.tokens: - return c.tokens[itoken] - else: - c.labels.append((itoken, None)) - c.tokens[itoken] = ilabel - return ilabel - else: - # Either a keyword or an operator - assert label[0] in ('"', "'"), label - value = eval(label) - if value[0].isalpha(): - # A keyword - if value in c.keywords: - return c.keywords[value] - else: - c.labels.append((token.NAME, value)) - c.keywords[value] = ilabel - return ilabel - else: - # An operator (any non-numeric token) - itoken = grammar.opmap[value] # Fails if unknown token - if itoken in c.tokens: - return c.tokens[itoken] - else: - c.labels.append((itoken, None)) - c.tokens[itoken] = ilabel - return ilabel - - def addfirstsets(self): - names = list(self.dfas.keys()) - names.sort() - for name in names: - if name not in self.first: - self.calcfirst(name) - #print name, self.first[name].keys() - - def calcfirst(self, name): - dfa = self.dfas[name] - self.first[name] = None # dummy to detect left recursion - state = dfa[0] - totalset = {} - overlapcheck = {} - for label, next in state.arcs.items(): - if label in self.dfas: - if label in self.first: - fset = self.first[label] - if fset is None: - raise ValueError("recursion for rule %r" % name) - else: - self.calcfirst(label) - fset = self.first[label] - totalset.update(fset) - overlapcheck[label] = fset - else: - totalset[label] = 1 - overlapcheck[label] = {label: 1} - inverse = {} - for label, itsfirst in overlapcheck.items(): - for symbol in itsfirst: - if symbol in inverse: - raise ValueError("rule %s is ambiguous; %s is in the" - " first sets of %s as well as %s" % - (name, symbol, label, inverse[symbol])) - inverse[symbol] = label - self.first[name] = totalset - - def parse(self): - dfas = {} - startsymbol = None - # MSTART: (NEWLINE | RULE)* ENDMARKER - while self.type != token.ENDMARKER: - while self.type == token.NEWLINE: - self.gettoken() - # RULE: NAME ':' RHS NEWLINE - name = self.expect(token.NAME) - self.expect(token.OP, ":") - a, z = self.parse_rhs() - self.expect(token.NEWLINE) - #self.dump_nfa(name, a, z) - dfa = self.make_dfa(a, z) - #self.dump_dfa(name, dfa) - oldlen = len(dfa) - self.simplify_dfa(dfa) - newlen = len(dfa) - dfas[name] = dfa - #print name, oldlen, newlen - if startsymbol is None: - startsymbol = name - return dfas, startsymbol - - def make_dfa(self, start, finish): - # To turn an NFA into a DFA, we define the states of the DFA - # to correspond to *sets* of states of the NFA. Then do some - # state reduction. Let's represent sets as dicts with 1 for - # values. - assert isinstance(start, NFAState) - assert isinstance(finish, NFAState) - def closure(state): - base = {} - addclosure(state, base) - return base - def addclosure(state, base): - assert isinstance(state, NFAState) - if state in base: - return - base[state] = 1 - for label, next in state.arcs: - if label is None: - addclosure(next, base) - states = [DFAState(closure(start), finish)] - for state in states: # NB states grows while we're iterating - arcs = {} - for nfastate in state.nfaset: - for label, next in nfastate.arcs: - if label is not None: - addclosure(next, arcs.setdefault(label, {})) - for label, nfaset in sorted(arcs.items()): - for st in states: - if st.nfaset == nfaset: - break - else: - st = DFAState(nfaset, finish) - states.append(st) - state.addarc(st, label) - return states # List of DFAState instances; first one is start - - def dump_nfa(self, name, start, finish): - print("Dump of NFA for", name) - todo = [start] - for i, state in enumerate(todo): - print(" State", i, state is finish and "(final)" or "") - for label, next in state.arcs: - if next in todo: - j = todo.index(next) - else: - j = len(todo) - todo.append(next) - if label is None: - print(" -> %d" % j) - else: - print(" %s -> %d" % (label, j)) - - def dump_dfa(self, name, dfa): - print("Dump of DFA for", name) - for i, state in enumerate(dfa): - print(" State", i, state.isfinal and "(final)" or "") - for label, next in sorted(state.arcs.items()): - print(" %s -> %d" % (label, dfa.index(next))) - - def simplify_dfa(self, dfa): - # This is not theoretically optimal, but works well enough. - # Algorithm: repeatedly look for two states that have the same - # set of arcs (same labels pointing to the same nodes) and - # unify them, until things stop changing. - - # dfa is a list of DFAState instances - changes = True - while changes: - changes = False - for i, state_i in enumerate(dfa): - for j in range(i+1, len(dfa)): - state_j = dfa[j] - if state_i == state_j: - #print " unify", i, j - del dfa[j] - for state in dfa: - state.unifystate(state_j, state_i) - changes = True - break - - def parse_rhs(self): - # RHS: ALT ('|' ALT)* - a, z = self.parse_alt() - if self.value != "|": - return a, z - else: - aa = NFAState() - zz = NFAState() - aa.addarc(a) - z.addarc(zz) - while self.value == "|": - self.gettoken() - a, z = self.parse_alt() - aa.addarc(a) - z.addarc(zz) - return aa, zz - - def parse_alt(self): - # ALT: ITEM+ - a, b = self.parse_item() - while (self.value in ("(", "[") or - self.type in (token.NAME, token.STRING)): - c, d = self.parse_item() - b.addarc(c) - b = d - return a, b - - def parse_item(self): - # ITEM: '[' RHS ']' | ATOM ['+' | '*'] - if self.value == "[": - self.gettoken() - a, z = self.parse_rhs() - self.expect(token.OP, "]") - a.addarc(z) - return a, z - else: - a, z = self.parse_atom() - value = self.value - if value not in ("+", "*"): - return a, z - self.gettoken() - z.addarc(a) - if value == "+": - return a, z - else: - return a, a - - def parse_atom(self): - # ATOM: '(' RHS ')' | NAME | STRING - if self.value == "(": - self.gettoken() - a, z = self.parse_rhs() - self.expect(token.OP, ")") - return a, z - elif self.type in (token.NAME, token.STRING): - a = NFAState() - z = NFAState() - a.addarc(z, self.value) - self.gettoken() - return a, z - else: - self.raise_error("expected (...) or NAME or STRING, got %s/%s", - self.type, self.value) - - def expect(self, type, value=None): - if self.type != type or (value is not None and self.value != value): - self.raise_error("expected %s/%s, got %s/%s", - type, value, self.type, self.value) - value = self.value - self.gettoken() - return value - - def gettoken(self): - tup = next(self.generator) - while tup[0] in (tokenize.COMMENT, tokenize.NL): - tup = next(self.generator) - self.type, self.value, self.begin, self.end, self.line = tup - #print token.tok_name[self.type], repr(self.value) - - def raise_error(self, msg, *args): - if args: - try: - msg = msg % args - except: - msg = " ".join([msg] + list(map(str, args))) - raise SyntaxError(msg, (self.filename, self.end[0], - self.end[1], self.line)) - -class NFAState(object): - - def __init__(self): - self.arcs = [] # list of (label, NFAState) pairs - - def addarc(self, next, label=None): - assert label is None or isinstance(label, str) - assert isinstance(next, NFAState) - self.arcs.append((label, next)) - -class DFAState(object): - - def __init__(self, nfaset, final): - assert isinstance(nfaset, dict) - assert isinstance(next(iter(nfaset)), NFAState) - assert isinstance(final, NFAState) - self.nfaset = nfaset - self.isfinal = final in nfaset - self.arcs = {} # map from label to DFAState - - def addarc(self, next, label): - assert isinstance(label, str) - assert label not in self.arcs - assert isinstance(next, DFAState) - self.arcs[label] = next - - def unifystate(self, old, new): - for label, next in self.arcs.items(): - if next is old: - self.arcs[label] = new - - def __eq__(self, other): - # Equality test -- ignore the nfaset instance variable - assert isinstance(other, DFAState) - if self.isfinal != other.isfinal: - return False - # Can't just return self.arcs == other.arcs, because that - # would invoke this method recursively, with cycles... - if len(self.arcs) != len(other.arcs): - return False - for label, next in self.arcs.items(): - if next is not other.arcs.get(label): - return False - return True - - __hash__ = None # For Py3 compatibility. - -def generate_grammar(filename="Grammar.txt"): - p = ParserGenerator(filename) - return p.make_grammar() diff --git a/Lib/lib2to3/pgen2/token.py b/Lib/lib2to3/pgen2/token.py deleted file mode 100755 index 2a55138e48237..0000000000000 --- a/Lib/lib2to3/pgen2/token.py +++ /dev/null @@ -1,86 +0,0 @@ -#! /usr/bin/env python3 - -"""Token constants (from "token.h").""" - -# Taken from Python (r53757) and modified to include some tokens -# originally monkeypatched in by pgen2.tokenize - -#--start constants-- -ENDMARKER = 0 -NAME = 1 -NUMBER = 2 -STRING = 3 -NEWLINE = 4 -INDENT = 5 -DEDENT = 6 -LPAR = 7 -RPAR = 8 -LSQB = 9 -RSQB = 10 -COLON = 11 -COMMA = 12 -SEMI = 13 -PLUS = 14 -MINUS = 15 -STAR = 16 -SLASH = 17 -VBAR = 18 -AMPER = 19 -LESS = 20 -GREATER = 21 -EQUAL = 22 -DOT = 23 -PERCENT = 24 -BACKQUOTE = 25 -LBRACE = 26 -RBRACE = 27 -EQEQUAL = 28 -NOTEQUAL = 29 -LESSEQUAL = 30 -GREATEREQUAL = 31 -TILDE = 32 -CIRCUMFLEX = 33 -LEFTSHIFT = 34 -RIGHTSHIFT = 35 -DOUBLESTAR = 36 -PLUSEQUAL = 37 -MINEQUAL = 38 -STAREQUAL = 39 -SLASHEQUAL = 40 -PERCENTEQUAL = 41 -AMPEREQUAL = 42 -VBAREQUAL = 43 -CIRCUMFLEXEQUAL = 44 -LEFTSHIFTEQUAL = 45 -RIGHTSHIFTEQUAL = 46 -DOUBLESTAREQUAL = 47 -DOUBLESLASH = 48 -DOUBLESLASHEQUAL = 49 -AT = 50 -ATEQUAL = 51 -OP = 52 -COMMENT = 53 -NL = 54 -RARROW = 55 -AWAIT = 56 -ASYNC = 57 -ERRORTOKEN = 58 -COLONEQUAL = 59 -N_TOKENS = 60 -NT_OFFSET = 256 -#--end constants-- - -tok_name = {} -for _name, _value in list(globals().items()): - if isinstance(_value, int): - tok_name[_value] = _name - - -def ISTERMINAL(x): - return x < NT_OFFSET - -def ISNONTERMINAL(x): - return x >= NT_OFFSET - -def ISEOF(x): - return x == ENDMARKER diff --git a/Lib/lib2to3/pgen2/tokenize.py b/Lib/lib2to3/pgen2/tokenize.py deleted file mode 100644 index 099dfa7798afd..0000000000000 --- a/Lib/lib2to3/pgen2/tokenize.py +++ /dev/null @@ -1,564 +0,0 @@ -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation. -# All rights reserved. - -"""Tokenization help for Python programs. - -generate_tokens(readline) is a generator that breaks a stream of -text into Python tokens. It accepts a readline-like method which is called -repeatedly to get the next line of input (or "" for EOF). It generates -5-tuples with these members: - - the token type (see token.py) - the token (a string) - the starting (row, column) indices of the token (a 2-tuple of ints) - the ending (row, column) indices of the token (a 2-tuple of ints) - the original line (string) - -It is designed to match the working of the Python tokenizer exactly, except -that it produces COMMENT tokens for comments and gives type OP for all -operators - -Older entry points - tokenize_loop(readline, tokeneater) - tokenize(readline, tokeneater=printtoken) -are the same, except instead of generating tokens, tokeneater is a callback -function to which the 5 fields described above are passed as 5 arguments, -each time a new token is found.""" - -__author__ = 'Ka-Ping Yee <ping at lfw.org>' -__credits__ = \ - 'GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, Skip Montanaro' - -import string, re -from codecs import BOM_UTF8, lookup -from lib2to3.pgen2.token import * - -from . import token -__all__ = [x for x in dir(token) if x[0] != '_'] + ["tokenize", - "generate_tokens", "untokenize"] -del token - -try: - bytes -except NameError: - # Support bytes type in Python <= 2.5, so 2to3 turns itself into - # valid Python 3 code. - bytes = str - -def group(*choices): return '(' + '|'.join(choices) + ')' -def any(*choices): return group(*choices) + '*' -def maybe(*choices): return group(*choices) + '?' -def _combinations(*l): - return set( - x + y for x in l for y in l + ("",) if x.casefold() != y.casefold() - ) - -Whitespace = r'[ \f\t]*' -Comment = r'#[^\r\n]*' -Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) -Name = r'\w+' - -Binnumber = r'0[bB]_?[01]+(?:_[01]+)*' -Hexnumber = r'0[xX]_?[\da-fA-F]+(?:_[\da-fA-F]+)*[lL]?' -Octnumber = r'0[oO]?_?[0-7]+(?:_[0-7]+)*[lL]?' -Decnumber = group(r'[1-9]\d*(?:_\d+)*[lL]?', '0[lL]?') -Intnumber = group(Binnumber, Hexnumber, Octnumber, Decnumber) -Exponent = r'[eE][-+]?\d+(?:_\d+)*' -Pointfloat = group(r'\d+(?:_\d+)*\.(?:\d+(?:_\d+)*)?', r'\.\d+(?:_\d+)*') + maybe(Exponent) -Expfloat = r'\d+(?:_\d+)*' + Exponent -Floatnumber = group(Pointfloat, Expfloat) -Imagnumber = group(r'\d+(?:_\d+)*[jJ]', Floatnumber + r'[jJ]') -Number = group(Imagnumber, Floatnumber, Intnumber) - -# Tail end of ' string. -Single = r"[^'\\]*(?:\\.[^'\\]*)*'" -# Tail end of " string. -Double = r'[^"\\]*(?:\\.[^"\\]*)*"' -# Tail end of ''' string. -Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" -# Tail end of """ string. -Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' -_litprefix = r"(?:[uUrRbBfF]|[rR][fFbB]|[fFbBuU][rR])?" -Triple = group(_litprefix + "'''", _litprefix + '"""') -# Single-line ' or " string. -String = group(_litprefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", - _litprefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') - -# Because of leftmost-then-longest match semantics, be sure to put the -# longest operators first (e.g., if = came before ==, == would get -# recognized as two instances of =). -Operator = group(r"\*\*=?", r">>=?", r"<<=?", r"<>", r"!=", - r"//=?", r"->", - r"[+\-*/%&@|^=<>]=?", - r"~") - -Bracket = '[][(){}]' -Special = group(r'\r?\n', r':=', r'[:;.,`@]') -Funny = group(Operator, Bracket, Special) - -PlainToken = group(Number, Funny, String, Name) -Token = Ignore + PlainToken - -# First (or only) line of ' or " string. -ContStr = group(_litprefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + - group("'", r'\\\r?\n'), - _litprefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + - group('"', r'\\\r?\n')) -PseudoExtras = group(r'\\\r?\n', Comment, Triple) -PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) - -tokenprog, pseudoprog, single3prog, double3prog = map( - re.compile, (Token, PseudoToken, Single3, Double3)) - -_strprefixes = ( - _combinations('r', 'R', 'f', 'F') | - _combinations('r', 'R', 'b', 'B') | - {'u', 'U', 'ur', 'uR', 'Ur', 'UR'} -) - -endprogs = {"'": re.compile(Single), '"': re.compile(Double), - "'''": single3prog, '"""': double3prog, - **{f"{prefix}'''": single3prog for prefix in _strprefixes}, - **{f'{prefix}"""': double3prog for prefix in _strprefixes}, - **{prefix: None for prefix in _strprefixes}} - -triple_quoted = ( - {"'''", '"""'} | - {f"{prefix}'''" for prefix in _strprefixes} | - {f'{prefix}"""' for prefix in _strprefixes} -) -single_quoted = ( - {"'", '"'} | - {f"{prefix}'" for prefix in _strprefixes} | - {f'{prefix}"' for prefix in _strprefixes} -) - -tabsize = 8 - -class TokenError(Exception): pass - -class StopTokenizing(Exception): pass - -def printtoken(type, token, xxx_todo_changeme, xxx_todo_changeme1, line): # for testing - (srow, scol) = xxx_todo_changeme - (erow, ecol) = xxx_todo_changeme1 - print("%d,%d-%d,%d:\t%s\t%s" % \ - (srow, scol, erow, ecol, tok_name[type], repr(token))) - -def tokenize(readline, tokeneater=printtoken): - """ - The tokenize() function accepts two parameters: one representing the - input stream, and one providing an output mechanism for tokenize(). - - The first parameter, readline, must be a callable object which provides - the same interface as the readline() method of built-in file objects. - Each call to the function should return one line of input as a string. - - The second parameter, tokeneater, must also be a callable object. It is - called once for each token, with five arguments, corresponding to the - tuples generated by generate_tokens(). - """ - try: - tokenize_loop(readline, tokeneater) - except StopTokenizing: - pass - -# backwards compatible interface -def tokenize_loop(readline, tokeneater): - for token_info in generate_tokens(readline): - tokeneater(*token_info) - -class Untokenizer: - - def __init__(self): - self.tokens = [] - self.prev_row = 1 - self.prev_col = 0 - - def add_whitespace(self, start): - row, col = start - assert row <= self.prev_row - col_offset = col - self.prev_col - if col_offset: - self.tokens.append(" " * col_offset) - - def untokenize(self, iterable): - for t in iterable: - if len(t) == 2: - self.compat(t, iterable) - break - tok_type, token, start, end, line = t - self.add_whitespace(start) - self.tokens.append(token) - self.prev_row, self.prev_col = end - if tok_type in (NEWLINE, NL): - self.prev_row += 1 - self.prev_col = 0 - return "".join(self.tokens) - - def compat(self, token, iterable): - startline = False - indents = [] - toks_append = self.tokens.append - toknum, tokval = token - if toknum in (NAME, NUMBER): - tokval += ' ' - if toknum in (NEWLINE, NL): - startline = True - for tok in iterable: - toknum, tokval = tok[:2] - - if toknum in (NAME, NUMBER, ASYNC, AWAIT): - tokval += ' ' - - if toknum == INDENT: - indents.append(tokval) - continue - elif toknum == DEDENT: - indents.pop() - continue - elif toknum in (NEWLINE, NL): - startline = True - elif startline and indents: - toks_append(indents[-1]) - startline = False - toks_append(tokval) - -cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII) -blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)', re.ASCII) - -def _get_normal_name(orig_enc): - """Imitates get_normal_name in tokenizer.c.""" - # Only care about the first 12 characters. - enc = orig_enc[:12].lower().replace("_", "-") - if enc == "utf-8" or enc.startswith("utf-8-"): - return "utf-8" - if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ - enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): - return "iso-8859-1" - return orig_enc - -def detect_encoding(readline): - """ - The detect_encoding() function is used to detect the encoding that should - be used to decode a Python source file. It requires one argument, readline, - in the same way as the tokenize() generator. - - It will call readline a maximum of twice, and return the encoding used - (as a string) and a list of any lines (left as bytes) it has read - in. - - It detects the encoding from the presence of a utf-8 bom or an encoding - cookie as specified in pep-0263. If both a bom and a cookie are present, but - disagree, a SyntaxError will be raised. If the encoding cookie is an invalid - charset, raise a SyntaxError. Note that if a utf-8 bom is found, - 'utf-8-sig' is returned. - - If no encoding is specified, then the default of 'utf-8' will be returned. - """ - bom_found = False - encoding = None - default = 'utf-8' - def read_or_stop(): - try: - return readline() - except StopIteration: - return bytes() - - def find_cookie(line): - try: - line_string = line.decode('ascii') - except UnicodeDecodeError: - return None - match = cookie_re.match(line_string) - if not match: - return None - encoding = _get_normal_name(match.group(1)) - try: - codec = lookup(encoding) - except LookupError: - # This behaviour mimics the Python interpreter - raise SyntaxError("unknown encoding: " + encoding) - - if bom_found: - if codec.name != 'utf-8': - # This behaviour mimics the Python interpreter - raise SyntaxError('encoding problem: utf-8') - encoding += '-sig' - return encoding - - first = read_or_stop() - if first.startswith(BOM_UTF8): - bom_found = True - first = first[3:] - default = 'utf-8-sig' - if not first: - return default, [] - - encoding = find_cookie(first) - if encoding: - return encoding, [first] - if not blank_re.match(first): - return default, [first] - - second = read_or_stop() - if not second: - return default, [first] - - encoding = find_cookie(second) - if encoding: - return encoding, [first, second] - - return default, [first, second] - -def untokenize(iterable): - """Transform tokens back into Python source code. - - Each element returned by the iterable must be a token sequence - with at least two elements, a token number and token value. If - only two tokens are passed, the resulting output is poor. - - Round-trip invariant for full input: - Untokenized source will match input source exactly - - Round-trip invariant for limited input: - # Output text will tokenize the back to the input - t1 = [tok[:2] for tok in generate_tokens(f.readline)] - newcode = untokenize(t1) - readline = iter(newcode.splitlines(1)).next - t2 = [tok[:2] for tokin generate_tokens(readline)] - assert t1 == t2 - """ - ut = Untokenizer() - return ut.untokenize(iterable) - -def generate_tokens(readline): - """ - The generate_tokens() generator requires one argument, readline, which - must be a callable object which provides the same interface as the - readline() method of built-in file objects. Each call to the function - should return one line of input as a string. Alternately, readline - can be a callable function terminating with StopIteration: - readline = open(myfile).next # Example of alternate readline - - The generator produces 5-tuples with these members: the token type; the - token string; a 2-tuple (srow, scol) of ints specifying the row and - column where the token begins in the source; a 2-tuple (erow, ecol) of - ints specifying the row and column where the token ends in the source; - and the line on which the token was found. The line passed is the - physical line. - """ - lnum = parenlev = continued = 0 - contstr, needcont = '', 0 - contline = None - indents = [0] - - # 'stashed' and 'async_*' are used for async/await parsing - stashed = None - async_def = False - async_def_indent = 0 - async_def_nl = False - - while 1: # loop over lines in stream - try: - line = readline() - except StopIteration: - line = '' - lnum = lnum + 1 - pos, max = 0, len(line) - - if contstr: # continued string - if not line: - raise TokenError("EOF in multi-line string", strstart) - endmatch = endprog.match(line) - if endmatch: - pos = end = endmatch.end(0) - yield (STRING, contstr + line[:end], - strstart, (lnum, end), contline + line) - contstr, needcont = '', 0 - contline = None - elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': - yield (ERRORTOKEN, contstr + line, - strstart, (lnum, len(line)), contline) - contstr = '' - contline = None - continue - else: - contstr = contstr + line - contline = contline + line - continue - - elif parenlev == 0 and not continued: # new statement - if not line: break - column = 0 - while pos < max: # measure leading whitespace - if line[pos] == ' ': column = column + 1 - elif line[pos] == '\t': column = (column//tabsize + 1)*tabsize - elif line[pos] == '\f': column = 0 - else: break - pos = pos + 1 - if pos == max: break - - if stashed: - yield stashed - stashed = None - - if line[pos] in '#\r\n': # skip comments or blank lines - if line[pos] == '#': - comment_token = line[pos:].rstrip('\r\n') - nl_pos = pos + len(comment_token) - yield (COMMENT, comment_token, - (lnum, pos), (lnum, pos + len(comment_token)), line) - yield (NL, line[nl_pos:], - (lnum, nl_pos), (lnum, len(line)), line) - else: - yield ((NL, COMMENT)[line[pos] == '#'], line[pos:], - (lnum, pos), (lnum, len(line)), line) - continue - - if column > indents[-1]: # count indents or dedents - indents.append(column) - yield (INDENT, line[:pos], (lnum, 0), (lnum, pos), line) - while column < indents[-1]: - if column not in indents: - raise IndentationError( - "unindent does not match any outer indentation level", - ("<tokenize>", lnum, pos, line)) - indents = indents[:-1] - - if async_def and async_def_indent >= indents[-1]: - async_def = False - async_def_nl = False - async_def_indent = 0 - - yield (DEDENT, '', (lnum, pos), (lnum, pos), line) - - if async_def and async_def_nl and async_def_indent >= indents[-1]: - async_def = False - async_def_nl = False - async_def_indent = 0 - - else: # continued statement - if not line: - raise TokenError("EOF in multi-line statement", (lnum, 0)) - continued = 0 - - while pos < max: - pseudomatch = pseudoprog.match(line, pos) - if pseudomatch: # scan for tokens - start, end = pseudomatch.span(1) - spos, epos, pos = (lnum, start), (lnum, end), end - token, initial = line[start:end], line[start] - - if initial in string.digits or \ - (initial == '.' and token != '.'): # ordinary number - yield (NUMBER, token, spos, epos, line) - elif initial in '\r\n': - newline = NEWLINE - if parenlev > 0: - newline = NL - elif async_def: - async_def_nl = True - if stashed: - yield stashed - stashed = None - yield (newline, token, spos, epos, line) - - elif initial == '#': - assert not token.endswith("\n") - if stashed: - yield stashed - stashed = None - yield (COMMENT, token, spos, epos, line) - elif token in triple_quoted: - endprog = endprogs[token] - endmatch = endprog.match(line, pos) - if endmatch: # all on one line - pos = endmatch.end(0) - token = line[start:pos] - if stashed: - yield stashed - stashed = None - yield (STRING, token, spos, (lnum, pos), line) - else: - strstart = (lnum, start) # multiple lines - contstr = line[start:] - contline = line - break - elif initial in single_quoted or \ - token[:2] in single_quoted or \ - token[:3] in single_quoted: - if token[-1] == '\n': # continued string - strstart = (lnum, start) - endprog = (endprogs[initial] or endprogs[token[1]] or - endprogs[token[2]]) - contstr, needcont = line[start:], 1 - contline = line - break - else: # ordinary string - if stashed: - yield stashed - stashed = None - yield (STRING, token, spos, epos, line) - elif initial.isidentifier(): # ordinary name - if token in ('async', 'await'): - if async_def: - yield (ASYNC if token == 'async' else AWAIT, - token, spos, epos, line) - continue - - tok = (NAME, token, spos, epos, line) - if token == 'async' and not stashed: - stashed = tok - continue - - if token in ('def', 'for'): - if (stashed - and stashed[0] == NAME - and stashed[1] == 'async'): - - if token == 'def': - async_def = True - async_def_indent = indents[-1] - - yield (ASYNC, stashed[1], - stashed[2], stashed[3], - stashed[4]) - stashed = None - - if stashed: - yield stashed - stashed = None - - yield tok - elif initial == '\\': # continued stmt - # This yield is new; needed for better idempotency: - if stashed: - yield stashed - stashed = None - yield (NL, token, spos, (lnum, pos), line) - continued = 1 - else: - if initial in '([{': parenlev = parenlev + 1 - elif initial in ')]}': parenlev = parenlev - 1 - if stashed: - yield stashed - stashed = None - yield (OP, token, spos, epos, line) - else: - yield (ERRORTOKEN, line[pos], - (lnum, pos), (lnum, pos+1), line) - pos = pos + 1 - - if stashed: - yield stashed - stashed = None - - for indent in indents[1:]: # pop remaining indent levels - yield (DEDENT, '', (lnum, 0), (lnum, 0), '') - yield (ENDMARKER, '', (lnum, 0), (lnum, 0), '') - -if __name__ == '__main__': # testing - import sys - if len(sys.argv) > 1: tokenize(open(sys.argv[1]).readline) - else: tokenize(sys.stdin.readline) diff --git a/Lib/lib2to3/pygram.py b/Lib/lib2to3/pygram.py deleted file mode 100644 index 24d9db9217f13..0000000000000 --- a/Lib/lib2to3/pygram.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Export the Python grammar and symbols.""" - -# Python imports -import os - -# Local imports -from .pgen2 import token -from .pgen2 import driver -from . import pytree - -# The grammar file -_GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), "Grammar.txt") -_PATTERN_GRAMMAR_FILE = os.path.join(os.path.dirname(__file__), - "PatternGrammar.txt") - - -class Symbols(object): - - def __init__(self, grammar): - """Initializer. - - Creates an attribute for each grammar symbol (nonterminal), - whose value is the symbol's type (an int >= 256). - """ - for name, symbol in grammar.symbol2number.items(): - setattr(self, name, symbol) - - -python_grammar = driver.load_packaged_grammar("lib2to3", _GRAMMAR_FILE) - -python_symbols = Symbols(python_grammar) - -python_grammar_no_print_statement = python_grammar.copy() -del python_grammar_no_print_statement.keywords["print"] - -python_grammar_no_print_and_exec_statement = python_grammar_no_print_statement.copy() -del python_grammar_no_print_and_exec_statement.keywords["exec"] - -pattern_grammar = driver.load_packaged_grammar("lib2to3", _PATTERN_GRAMMAR_FILE) -pattern_symbols = Symbols(pattern_grammar) diff --git a/Lib/lib2to3/pytree.py b/Lib/lib2to3/pytree.py deleted file mode 100644 index 729023df0284e..0000000000000 --- a/Lib/lib2to3/pytree.py +++ /dev/null @@ -1,853 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -""" -Python parse tree definitions. - -This is a very concrete parse tree; we need to keep every token and -even the comments and whitespace between tokens. - -There's also a pattern matching implementation here. -""" - -__author__ = "Guido van Rossum <guido at python.org>" - -import sys -from io import StringIO - -HUGE = 0x7FFFFFFF # maximum repeat count, default max - -_type_reprs = {} -def type_repr(type_num): - global _type_reprs - if not _type_reprs: - from .pygram import python_symbols - # printing tokens is possible but not as useful - # from .pgen2 import token // token.__dict__.items(): - for name, val in python_symbols.__dict__.items(): - if type(val) == int: _type_reprs[val] = name - return _type_reprs.setdefault(type_num, type_num) - -class Base(object): - - """ - Abstract base class for Node and Leaf. - - This provides some default functionality and boilerplate using the - template pattern. - - A node may be a subnode of at most one parent. - """ - - # Default values for instance variables - type = None # int: token number (< 256) or symbol number (>= 256) - parent = None # Parent node pointer, or None - children = () # Tuple of subnodes - was_changed = False - was_checked = False - - def __new__(cls, *args, **kwds): - """Constructor that prevents Base from being instantiated.""" - assert cls is not Base, "Cannot instantiate Base" - return object.__new__(cls) - - def __eq__(self, other): - """ - Compare two nodes for equality. - - This calls the method _eq(). - """ - if self.__class__ is not other.__class__: - return NotImplemented - return self._eq(other) - - __hash__ = None # For Py3 compatibility. - - def _eq(self, other): - """ - Compare two nodes for equality. - - This is called by __eq__ and __ne__. It is only called if the two nodes - have the same type. This must be implemented by the concrete subclass. - Nodes should be considered equal if they have the same structure, - ignoring the prefix string and other context information. - """ - raise NotImplementedError - - def clone(self): - """ - Return a cloned (deep) copy of self. - - This must be implemented by the concrete subclass. - """ - raise NotImplementedError - - def post_order(self): - """ - Return a post-order iterator for the tree. - - This must be implemented by the concrete subclass. - """ - raise NotImplementedError - - def pre_order(self): - """ - Return a pre-order iterator for the tree. - - This must be implemented by the concrete subclass. - """ - raise NotImplementedError - - def replace(self, new): - """Replace this node with a new one in the parent.""" - assert self.parent is not None, str(self) - assert new is not None - if not isinstance(new, list): - new = [new] - l_children = [] - found = False - for ch in self.parent.children: - if ch is self: - assert not found, (self.parent.children, self, new) - if new is not None: - l_children.extend(new) - found = True - else: - l_children.append(ch) - assert found, (self.children, self, new) - self.parent.changed() - self.parent.children = l_children - for x in new: - x.parent = self.parent - self.parent = None - - def get_lineno(self): - """Return the line number which generated the invocant node.""" - node = self - while not isinstance(node, Leaf): - if not node.children: - return - node = node.children[0] - return node.lineno - - def changed(self): - if self.parent: - self.parent.changed() - self.was_changed = True - - def remove(self): - """ - Remove the node from the tree. Returns the position of the node in its - parent's children before it was removed. - """ - if self.parent: - for i, node in enumerate(self.parent.children): - if node is self: - self.parent.changed() - del self.parent.children[i] - self.parent = None - return i - - @property - def next_sibling(self): - """ - The node immediately following the invocant in their parent's children - list. If the invocant does not have a next sibling, it is None - """ - if self.parent is None: - return None - - # Can't use index(); we need to test by identity - for i, child in enumerate(self.parent.children): - if child is self: - try: - return self.parent.children[i+1] - except IndexError: - return None - - @property - def prev_sibling(self): - """ - The node immediately preceding the invocant in their parent's children - list. If the invocant does not have a previous sibling, it is None. - """ - if self.parent is None: - return None - - # Can't use index(); we need to test by identity - for i, child in enumerate(self.parent.children): - if child is self: - if i == 0: - return None - return self.parent.children[i-1] - - def leaves(self): - for child in self.children: - yield from child.leaves() - - def depth(self): - if self.parent is None: - return 0 - return 1 + self.parent.depth() - - def get_suffix(self): - """ - Return the string immediately following the invocant node. This is - effectively equivalent to node.next_sibling.prefix - """ - next_sib = self.next_sibling - if next_sib is None: - return "" - return next_sib.prefix - - if sys.version_info < (3, 0): - def __str__(self): - return str(self).encode("ascii") - -class Node(Base): - - """Concrete implementation for interior nodes.""" - - def __init__(self,type, children, - context=None, - prefix=None, - fixers_applied=None): - """ - Initializer. - - Takes a type constant (a symbol number >= 256), a sequence of - child nodes, and an optional context keyword argument. - - As a side effect, the parent pointers of the children are updated. - """ - assert type >= 256, type - self.type = type - self.children = list(children) - for ch in self.children: - assert ch.parent is None, repr(ch) - ch.parent = self - if prefix is not None: - self.prefix = prefix - if fixers_applied: - self.fixers_applied = fixers_applied[:] - else: - self.fixers_applied = None - - def __repr__(self): - """Return a canonical string representation.""" - return "%s(%s, %r)" % (self.__class__.__name__, - type_repr(self.type), - self.children) - - def __unicode__(self): - """ - Return a pretty string representation. - - This reproduces the input source exactly. - """ - return "".join(map(str, self.children)) - - if sys.version_info > (3, 0): - __str__ = __unicode__ - - def _eq(self, other): - """Compare two nodes for equality.""" - return (self.type, self.children) == (other.type, other.children) - - def clone(self): - """Return a cloned (deep) copy of self.""" - return Node(self.type, [ch.clone() for ch in self.children], - fixers_applied=self.fixers_applied) - - def post_order(self): - """Return a post-order iterator for the tree.""" - for child in self.children: - yield from child.post_order() - yield self - - def pre_order(self): - """Return a pre-order iterator for the tree.""" - yield self - for child in self.children: - yield from child.pre_order() - - @property - def prefix(self): - """ - The whitespace and comments preceding this node in the input. - """ - if not self.children: - return "" - return self.children[0].prefix - - @prefix.setter - def prefix(self, prefix): - if self.children: - self.children[0].prefix = prefix - - def set_child(self, i, child): - """ - Equivalent to 'node.children[i] = child'. This method also sets the - child's parent attribute appropriately. - """ - child.parent = self - self.children[i].parent = None - self.children[i] = child - self.changed() - - def insert_child(self, i, child): - """ - Equivalent to 'node.children.insert(i, child)'. This method also sets - the child's parent attribute appropriately. - """ - child.parent = self - self.children.insert(i, child) - self.changed() - - def append_child(self, child): - """ - Equivalent to 'node.children.append(child)'. This method also sets the - child's parent attribute appropriately. - """ - child.parent = self - self.children.append(child) - self.changed() - - -class Leaf(Base): - - """Concrete implementation for leaf nodes.""" - - # Default values for instance variables - _prefix = "" # Whitespace and comments preceding this token in the input - lineno = 0 # Line where this token starts in the input - column = 0 # Column where this token tarts in the input - - def __init__(self, type, value, - context=None, - prefix=None, - fixers_applied=[]): - """ - Initializer. - - Takes a type constant (a token number < 256), a string value, and an - optional context keyword argument. - """ - assert 0 <= type < 256, type - if context is not None: - self._prefix, (self.lineno, self.column) = context - self.type = type - self.value = value - if prefix is not None: - self._prefix = prefix - self.fixers_applied = fixers_applied[:] - - def __repr__(self): - """Return a canonical string representation.""" - return "%s(%r, %r)" % (self.__class__.__name__, - self.type, - self.value) - - def __unicode__(self): - """ - Return a pretty string representation. - - This reproduces the input source exactly. - """ - return self.prefix + str(self.value) - - if sys.version_info > (3, 0): - __str__ = __unicode__ - - def _eq(self, other): - """Compare two nodes for equality.""" - return (self.type, self.value) == (other.type, other.value) - - def clone(self): - """Return a cloned (deep) copy of self.""" - return Leaf(self.type, self.value, - (self.prefix, (self.lineno, self.column)), - fixers_applied=self.fixers_applied) - - def leaves(self): - yield self - - def post_order(self): - """Return a post-order iterator for the tree.""" - yield self - - def pre_order(self): - """Return a pre-order iterator for the tree.""" - yield self - - @property - def prefix(self): - """ - The whitespace and comments preceding this token in the input. - """ - return self._prefix - - @prefix.setter - def prefix(self, prefix): - self.changed() - self._prefix = prefix - -def convert(gr, raw_node): - """ - Convert raw node information to a Node or Leaf instance. - - This is passed to the parser driver which calls it whenever a reduction of a - grammar rule produces a new complete node, so that the tree is build - strictly bottom-up. - """ - type, value, context, children = raw_node - if children or type in gr.number2symbol: - # If there's exactly one child, return that child instead of - # creating a new node. - if len(children) == 1: - return children[0] - return Node(type, children, context=context) - else: - return Leaf(type, value, context=context) - - -class BasePattern(object): - - """ - A pattern is a tree matching pattern. - - It looks for a specific node type (token or symbol), and - optionally for a specific content. - - This is an abstract base class. There are three concrete - subclasses: - - - LeafPattern matches a single leaf node; - - NodePattern matches a single node (usually non-leaf); - - WildcardPattern matches a sequence of nodes of variable length. - """ - - # Defaults for instance variables - type = None # Node type (token if < 256, symbol if >= 256) - content = None # Optional content matching pattern - name = None # Optional name used to store match in results dict - - def __new__(cls, *args, **kwds): - """Constructor that prevents BasePattern from being instantiated.""" - assert cls is not BasePattern, "Cannot instantiate BasePattern" - return object.__new__(cls) - - def __repr__(self): - args = [type_repr(self.type), self.content, self.name] - while args and args[-1] is None: - del args[-1] - return "%s(%s)" % (self.__class__.__name__, ", ".join(map(repr, args))) - - def optimize(self): - """ - A subclass can define this as a hook for optimizations. - - Returns either self or another node with the same effect. - """ - return self - - def match(self, node, results=None): - """ - Does this pattern exactly match a node? - - Returns True if it matches, False if not. - - If results is not None, it must be a dict which will be - updated with the nodes matching named subpatterns. - - Default implementation for non-wildcard patterns. - """ - if self.type is not None and node.type != self.type: - return False - if self.content is not None: - r = None - if results is not None: - r = {} - if not self._submatch(node, r): - return False - if r: - results.update(r) - if results is not None and self.name: - results[self.name] = node - return True - - def match_seq(self, nodes, results=None): - """ - Does this pattern exactly match a sequence of nodes? - - Default implementation for non-wildcard patterns. - """ - if len(nodes) != 1: - return False - return self.match(nodes[0], results) - - def generate_matches(self, nodes): - """ - Generator yielding all matches for this pattern. - - Default implementation for non-wildcard patterns. - """ - r = {} - if nodes and self.match(nodes[0], r): - yield 1, r - - -class LeafPattern(BasePattern): - - def __init__(self, type=None, content=None, name=None): - """ - Initializer. Takes optional type, content, and name. - - The type, if given must be a token type (< 256). If not given, - this matches any *leaf* node; the content may still be required. - - The content, if given, must be a string. - - If a name is given, the matching node is stored in the results - dict under that key. - """ - if type is not None: - assert 0 <= type < 256, type - if content is not None: - assert isinstance(content, str), repr(content) - self.type = type - self.content = content - self.name = name - - def match(self, node, results=None): - """Override match() to insist on a leaf node.""" - if not isinstance(node, Leaf): - return False - return BasePattern.match(self, node, results) - - def _submatch(self, node, results=None): - """ - Match the pattern's content to the node's children. - - This assumes the node type matches and self.content is not None. - - Returns True if it matches, False if not. - - If results is not None, it must be a dict which will be - updated with the nodes matching named subpatterns. - - When returning False, the results dict may still be updated. - """ - return self.content == node.value - - -class NodePattern(BasePattern): - - wildcards = False - - def __init__(self, type=None, content=None, name=None): - """ - Initializer. Takes optional type, content, and name. - - The type, if given, must be a symbol type (>= 256). If the - type is None this matches *any* single node (leaf or not), - except if content is not None, in which it only matches - non-leaf nodes that also match the content pattern. - - The content, if not None, must be a sequence of Patterns that - must match the node's children exactly. If the content is - given, the type must not be None. - - If a name is given, the matching node is stored in the results - dict under that key. - """ - if type is not None: - assert type >= 256, type - if content is not None: - assert not isinstance(content, str), repr(content) - content = list(content) - for i, item in enumerate(content): - assert isinstance(item, BasePattern), (i, item) - if isinstance(item, WildcardPattern): - self.wildcards = True - self.type = type - self.content = content - self.name = name - - def _submatch(self, node, results=None): - """ - Match the pattern's content to the node's children. - - This assumes the node type matches and self.content is not None. - - Returns True if it matches, False if not. - - If results is not None, it must be a dict which will be - updated with the nodes matching named subpatterns. - - When returning False, the results dict may still be updated. - """ - if self.wildcards: - for c, r in generate_matches(self.content, node.children): - if c == len(node.children): - if results is not None: - results.update(r) - return True - return False - if len(self.content) != len(node.children): - return False - for subpattern, child in zip(self.content, node.children): - if not subpattern.match(child, results): - return False - return True - - -class WildcardPattern(BasePattern): - - """ - A wildcard pattern can match zero or more nodes. - - This has all the flexibility needed to implement patterns like: - - .* .+ .? .{m,n} - (a b c | d e | f) - (...)* (...)+ (...)? (...){m,n} - - except it always uses non-greedy matching. - """ - - def __init__(self, content=None, min=0, max=HUGE, name=None): - """ - Initializer. - - Args: - content: optional sequence of subsequences of patterns; - if absent, matches one node; - if present, each subsequence is an alternative [*] - min: optional minimum number of times to match, default 0 - max: optional maximum number of times to match, default HUGE - name: optional name assigned to this match - - [*] Thus, if content is [[a, b, c], [d, e], [f, g, h]] this is - equivalent to (a b c | d e | f g h); if content is None, - this is equivalent to '.' in regular expression terms. - The min and max parameters work as follows: - min=0, max=maxint: .* - min=1, max=maxint: .+ - min=0, max=1: .? - min=1, max=1: . - If content is not None, replace the dot with the parenthesized - list of alternatives, e.g. (a b c | d e | f g h)* - """ - assert 0 <= min <= max <= HUGE, (min, max) - if content is not None: - content = tuple(map(tuple, content)) # Protect against alterations - # Check sanity of alternatives - assert len(content), repr(content) # Can't have zero alternatives - for alt in content: - assert len(alt), repr(alt) # Can have empty alternatives - self.content = content - self.min = min - self.max = max - self.name = name - - def optimize(self): - """Optimize certain stacked wildcard patterns.""" - subpattern = None - if (self.content is not None and - len(self.content) == 1 and len(self.content[0]) == 1): - subpattern = self.content[0][0] - if self.min == 1 and self.max == 1: - if self.content is None: - return NodePattern(name=self.name) - if subpattern is not None and self.name == subpattern.name: - return subpattern.optimize() - if (self.min <= 1 and isinstance(subpattern, WildcardPattern) and - subpattern.min <= 1 and self.name == subpattern.name): - return WildcardPattern(subpattern.content, - self.min*subpattern.min, - self.max*subpattern.max, - subpattern.name) - return self - - def match(self, node, results=None): - """Does this pattern exactly match a node?""" - return self.match_seq([node], results) - - def match_seq(self, nodes, results=None): - """Does this pattern exactly match a sequence of nodes?""" - for c, r in self.generate_matches(nodes): - if c == len(nodes): - if results is not None: - results.update(r) - if self.name: - results[self.name] = list(nodes) - return True - return False - - def generate_matches(self, nodes): - """ - Generator yielding matches for a sequence of nodes. - - Args: - nodes: sequence of nodes - - Yields: - (count, results) tuples where: - count: the match comprises nodes[:count]; - results: dict containing named submatches. - """ - if self.content is None: - # Shortcut for special case (see __init__.__doc__) - for count in range(self.min, 1 + min(len(nodes), self.max)): - r = {} - if self.name: - r[self.name] = nodes[:count] - yield count, r - elif self.name == "bare_name": - yield self._bare_name_matches(nodes) - else: - # The reason for this is that hitting the recursion limit usually - # results in some ugly messages about how RuntimeErrors are being - # ignored. We only have to do this on CPython, though, because other - # implementations don't have this nasty bug in the first place. - if hasattr(sys, "getrefcount"): - save_stderr = sys.stderr - sys.stderr = StringIO() - try: - for count, r in self._recursive_matches(nodes, 0): - if self.name: - r[self.name] = nodes[:count] - yield count, r - except RuntimeError: - # Fall back to the iterative pattern matching scheme if the - # recursive scheme hits the recursion limit (RecursionError). - for count, r in self._iterative_matches(nodes): - if self.name: - r[self.name] = nodes[:count] - yield count, r - finally: - if hasattr(sys, "getrefcount"): - sys.stderr = save_stderr - - def _iterative_matches(self, nodes): - """Helper to iteratively yield the matches.""" - nodelen = len(nodes) - if 0 >= self.min: - yield 0, {} - - results = [] - # generate matches that use just one alt from self.content - for alt in self.content: - for c, r in generate_matches(alt, nodes): - yield c, r - results.append((c, r)) - - # for each match, iterate down the nodes - while results: - new_results = [] - for c0, r0 in results: - # stop if the entire set of nodes has been matched - if c0 < nodelen and c0 <= self.max: - for alt in self.content: - for c1, r1 in generate_matches(alt, nodes[c0:]): - if c1 > 0: - r = {} - r.update(r0) - r.update(r1) - yield c0 + c1, r - new_results.append((c0 + c1, r)) - results = new_results - - def _bare_name_matches(self, nodes): - """Special optimized matcher for bare_name.""" - count = 0 - r = {} - done = False - max = len(nodes) - while not done and count < max: - done = True - for leaf in self.content: - if leaf[0].match(nodes[count], r): - count += 1 - done = False - break - r[self.name] = nodes[:count] - return count, r - - def _recursive_matches(self, nodes, count): - """Helper to recursively yield the matches.""" - assert self.content is not None - if count >= self.min: - yield 0, {} - if count < self.max: - for alt in self.content: - for c0, r0 in generate_matches(alt, nodes): - for c1, r1 in self._recursive_matches(nodes[c0:], count+1): - r = {} - r.update(r0) - r.update(r1) - yield c0 + c1, r - - -class NegatedPattern(BasePattern): - - def __init__(self, content=None): - """ - Initializer. - - The argument is either a pattern or None. If it is None, this - only matches an empty sequence (effectively '$' in regex - lingo). If it is not None, this matches whenever the argument - pattern doesn't have any matches. - """ - if content is not None: - assert isinstance(content, BasePattern), repr(content) - self.content = content - - def match(self, node): - # We never match a node in its entirety - return False - - def match_seq(self, nodes): - # We only match an empty sequence of nodes in its entirety - return len(nodes) == 0 - - def generate_matches(self, nodes): - if self.content is None: - # Return a match if there is an empty sequence - if len(nodes) == 0: - yield 0, {} - else: - # Return a match if the argument pattern has no matches - for c, r in self.content.generate_matches(nodes): - return - yield 0, {} - - -def generate_matches(patterns, nodes): - """ - Generator yielding matches for a sequence of patterns and nodes. - - Args: - patterns: a sequence of patterns - nodes: a sequence of nodes - - Yields: - (count, results) tuples where: - count: the entire sequence of patterns matches nodes[:count]; - results: dict containing named submatches. - """ - if not patterns: - yield 0, {} - else: - p, rest = patterns[0], patterns[1:] - for c0, r0 in p.generate_matches(nodes): - if not rest: - yield c0, r0 - else: - for c1, r1 in generate_matches(rest, nodes[c0:]): - r = {} - r.update(r0) - r.update(r1) - yield c0 + c1, r diff --git a/Lib/lib2to3/refactor.py b/Lib/lib2to3/refactor.py deleted file mode 100644 index 3a5aafffc6df0..0000000000000 --- a/Lib/lib2to3/refactor.py +++ /dev/null @@ -1,732 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Refactoring framework. - -Used as a main program, this can refactor any number of files and/or -recursively descend down directories. Imported as a module, this -provides infrastructure to write your own refactoring tool. -""" - -__author__ = "Guido van Rossum <guido at python.org>" - - -# Python imports -import io -import os -import pkgutil -import sys -import logging -import operator -import collections -from itertools import chain - -# Local imports -from .pgen2 import driver, tokenize, token -from .fixer_util import find_root -from . import pytree, pygram -from . import btm_matcher as bm - - -def get_all_fix_names(fixer_pkg, remove_prefix=True): - """Return a sorted list of all available fix names in the given package.""" - pkg = __import__(fixer_pkg, [], [], ["*"]) - fix_names = [] - for finder, name, ispkg in pkgutil.iter_modules(pkg.__path__): - if name.startswith("fix_"): - if remove_prefix: - name = name[4:] - fix_names.append(name) - return fix_names - - -class _EveryNode(Exception): - pass - - -def _get_head_types(pat): - """ Accepts a pytree Pattern Node and returns a set - of the pattern types which will match first. """ - - if isinstance(pat, (pytree.NodePattern, pytree.LeafPattern)): - # NodePatters must either have no type and no content - # or a type and content -- so they don't get any farther - # Always return leafs - if pat.type is None: - raise _EveryNode - return {pat.type} - - if isinstance(pat, pytree.NegatedPattern): - if pat.content: - return _get_head_types(pat.content) - raise _EveryNode # Negated Patterns don't have a type - - if isinstance(pat, pytree.WildcardPattern): - # Recurse on each node in content - r = set() - for p in pat.content: - for x in p: - r.update(_get_head_types(x)) - return r - - raise Exception("Oh no! I don't understand pattern %s" %(pat)) - - -def _get_headnode_dict(fixer_list): - """ Accepts a list of fixers and returns a dictionary - of head node type --> fixer list. """ - head_nodes = collections.defaultdict(list) - every = [] - for fixer in fixer_list: - if fixer.pattern: - try: - heads = _get_head_types(fixer.pattern) - except _EveryNode: - every.append(fixer) - else: - for node_type in heads: - head_nodes[node_type].append(fixer) - else: - if fixer._accept_type is not None: - head_nodes[fixer._accept_type].append(fixer) - else: - every.append(fixer) - for node_type in chain(pygram.python_grammar.symbol2number.values(), - pygram.python_grammar.tokens): - head_nodes[node_type].extend(every) - return dict(head_nodes) - - -def get_fixers_from_package(pkg_name): - """ - Return the fully qualified names for fixers in the package pkg_name. - """ - return [pkg_name + "." + fix_name - for fix_name in get_all_fix_names(pkg_name, False)] - -def _identity(obj): - return obj - - -def _detect_future_features(source): - have_docstring = False - gen = tokenize.generate_tokens(io.StringIO(source).readline) - def advance(): - tok = next(gen) - return tok[0], tok[1] - ignore = frozenset({token.NEWLINE, tokenize.NL, token.COMMENT}) - features = set() - try: - while True: - tp, value = advance() - if tp in ignore: - continue - elif tp == token.STRING: - if have_docstring: - break - have_docstring = True - elif tp == token.NAME and value == "from": - tp, value = advance() - if tp != token.NAME or value != "__future__": - break - tp, value = advance() - if tp != token.NAME or value != "import": - break - tp, value = advance() - if tp == token.OP and value == "(": - tp, value = advance() - while tp == token.NAME: - features.add(value) - tp, value = advance() - if tp != token.OP or value != ",": - break - tp, value = advance() - else: - break - except StopIteration: - pass - return frozenset(features) - - -class FixerError(Exception): - """A fixer could not be loaded.""" - - -class RefactoringTool(object): - - _default_options = {"print_function" : False, - "exec_function": False, - "write_unchanged_files" : False} - - CLASS_PREFIX = "Fix" # The prefix for fixer classes - FILE_PREFIX = "fix_" # The prefix for modules with a fixer within - - def __init__(self, fixer_names, options=None, explicit=None): - """Initializer. - - Args: - fixer_names: a list of fixers to import - options: a dict with configuration. - explicit: a list of fixers to run even if they are explicit. - """ - self.fixers = fixer_names - self.explicit = explicit or [] - self.options = self._default_options.copy() - if options is not None: - self.options.update(options) - self.grammar = pygram.python_grammar.copy() - - if self.options['print_function']: - del self.grammar.keywords["print"] - elif self.options['exec_function']: - del self.grammar.keywords["exec"] - - # When this is True, the refactor*() methods will call write_file() for - # files processed even if they were not changed during refactoring. If - # and only if the refactor method's write parameter was True. - self.write_unchanged_files = self.options.get("write_unchanged_files") - self.errors = [] - self.logger = logging.getLogger("RefactoringTool") - self.fixer_log = [] - self.wrote = False - self.driver = driver.Driver(self.grammar, - convert=pytree.convert, - logger=self.logger) - self.pre_order, self.post_order = self.get_fixers() - - - self.files = [] # List of files that were or should be modified - - self.BM = bm.BottomMatcher() - self.bmi_pre_order = [] # Bottom Matcher incompatible fixers - self.bmi_post_order = [] - - for fixer in chain(self.post_order, self.pre_order): - if fixer.BM_compatible: - self.BM.add_fixer(fixer) - # remove fixers that will be handled by the bottom-up - # matcher - elif fixer in self.pre_order: - self.bmi_pre_order.append(fixer) - elif fixer in self.post_order: - self.bmi_post_order.append(fixer) - - self.bmi_pre_order_heads = _get_headnode_dict(self.bmi_pre_order) - self.bmi_post_order_heads = _get_headnode_dict(self.bmi_post_order) - - - - def get_fixers(self): - """Inspects the options to load the requested patterns and handlers. - - Returns: - (pre_order, post_order), where pre_order is the list of fixers that - want a pre-order AST traversal, and post_order is the list that want - post-order traversal. - """ - pre_order_fixers = [] - post_order_fixers = [] - for fix_mod_path in self.fixers: - mod = __import__(fix_mod_path, {}, {}, ["*"]) - fix_name = fix_mod_path.rsplit(".", 1)[-1] - if fix_name.startswith(self.FILE_PREFIX): - fix_name = fix_name[len(self.FILE_PREFIX):] - parts = fix_name.split("_") - class_name = self.CLASS_PREFIX + "".join([p.title() for p in parts]) - try: - fix_class = getattr(mod, class_name) - except AttributeError: - raise FixerError("Can't find %s.%s" % (fix_name, class_name)) from None - fixer = fix_class(self.options, self.fixer_log) - if fixer.explicit and self.explicit is not True and \ - fix_mod_path not in self.explicit: - self.log_message("Skipping optional fixer: %s", fix_name) - continue - - self.log_debug("Adding transformation: %s", fix_name) - if fixer.order == "pre": - pre_order_fixers.append(fixer) - elif fixer.order == "post": - post_order_fixers.append(fixer) - else: - raise FixerError("Illegal fixer order: %r" % fixer.order) - - key_func = operator.attrgetter("run_order") - pre_order_fixers.sort(key=key_func) - post_order_fixers.sort(key=key_func) - return (pre_order_fixers, post_order_fixers) - - def log_error(self, msg, *args, **kwds): - """Called when an error occurs.""" - raise - - def log_message(self, msg, *args): - """Hook to log a message.""" - if args: - msg = msg % args - self.logger.info(msg) - - def log_debug(self, msg, *args): - if args: - msg = msg % args - self.logger.debug(msg) - - def print_output(self, old_text, new_text, filename, equal): - """Called with the old version, new version, and filename of a - refactored file.""" - pass - - def refactor(self, items, write=False, doctests_only=False): - """Refactor a list of files and directories.""" - - for dir_or_file in items: - if os.path.isdir(dir_or_file): - self.refactor_dir(dir_or_file, write, doctests_only) - else: - self.refactor_file(dir_or_file, write, doctests_only) - - def refactor_dir(self, dir_name, write=False, doctests_only=False): - """Descends down a directory and refactor every Python file found. - - Python files are assumed to have a .py extension. - - Files and subdirectories starting with '.' are skipped. - """ - py_ext = os.extsep + "py" - for dirpath, dirnames, filenames in os.walk(dir_name): - self.log_debug("Descending into %s", dirpath) - dirnames.sort() - filenames.sort() - for name in filenames: - if (not name.startswith(".") and - os.path.splitext(name)[1] == py_ext): - fullname = os.path.join(dirpath, name) - self.refactor_file(fullname, write, doctests_only) - # Modify dirnames in-place to remove subdirs with leading dots - dirnames[:] = [dn for dn in dirnames if not dn.startswith(".")] - - def _read_python_source(self, filename): - """ - Do our best to decode a Python source file correctly. - """ - try: - f = open(filename, "rb") - except OSError as err: - self.log_error("Can't open %s: %s", filename, err) - return None, None - try: - encoding = tokenize.detect_encoding(f.readline)[0] - finally: - f.close() - with io.open(filename, "r", encoding=encoding, newline='') as f: - return f.read(), encoding - - def refactor_file(self, filename, write=False, doctests_only=False): - """Refactors a file.""" - input, encoding = self._read_python_source(filename) - if input is None: - # Reading the file failed. - return - input += "\n" # Silence certain parse errors - if doctests_only: - self.log_debug("Refactoring doctests in %s", filename) - output = self.refactor_docstring(input, filename) - if self.write_unchanged_files or output != input: - self.processed_file(output, filename, input, write, encoding) - else: - self.log_debug("No doctest changes in %s", filename) - else: - tree = self.refactor_string(input, filename) - if self.write_unchanged_files or (tree and tree.was_changed): - # The [:-1] is to take off the \n we added earlier - self.processed_file(str(tree)[:-1], filename, - write=write, encoding=encoding) - else: - self.log_debug("No changes in %s", filename) - - def refactor_string(self, data, name): - """Refactor a given input string. - - Args: - data: a string holding the code to be refactored. - name: a human-readable name for use in error/log messages. - - Returns: - An AST corresponding to the refactored input stream; None if - there were errors during the parse. - """ - features = _detect_future_features(data) - if "print_function" in features: - self.driver.grammar = pygram.python_grammar_no_print_statement - try: - tree = self.driver.parse_string(data) - except Exception as err: - self.log_error("Can't parse %s: %s: %s", - name, err.__class__.__name__, err) - return - finally: - self.driver.grammar = self.grammar - tree.future_features = features - self.log_debug("Refactoring %s", name) - self.refactor_tree(tree, name) - return tree - - def refactor_stdin(self, doctests_only=False): - input = sys.stdin.read() - if doctests_only: - self.log_debug("Refactoring doctests in stdin") - output = self.refactor_docstring(input, "<stdin>") - if self.write_unchanged_files or output != input: - self.processed_file(output, "<stdin>", input) - else: - self.log_debug("No doctest changes in stdin") - else: - tree = self.refactor_string(input, "<stdin>") - if self.write_unchanged_files or (tree and tree.was_changed): - self.processed_file(str(tree), "<stdin>", input) - else: - self.log_debug("No changes in stdin") - - def refactor_tree(self, tree, name): - """Refactors a parse tree (modifying the tree in place). - - For compatible patterns the bottom matcher module is - used. Otherwise the tree is traversed node-to-node for - matches. - - Args: - tree: a pytree.Node instance representing the root of the tree - to be refactored. - name: a human-readable name for this tree. - - Returns: - True if the tree was modified, False otherwise. - """ - - for fixer in chain(self.pre_order, self.post_order): - fixer.start_tree(tree, name) - - #use traditional matching for the incompatible fixers - self.traverse_by(self.bmi_pre_order_heads, tree.pre_order()) - self.traverse_by(self.bmi_post_order_heads, tree.post_order()) - - # obtain a set of candidate nodes - match_set = self.BM.run(tree.leaves()) - - while any(match_set.values()): - for fixer in self.BM.fixers: - if fixer in match_set and match_set[fixer]: - #sort by depth; apply fixers from bottom(of the AST) to top - match_set[fixer].sort(key=pytree.Base.depth, reverse=True) - - if fixer.keep_line_order: - #some fixers(eg fix_imports) must be applied - #with the original file's line order - match_set[fixer].sort(key=pytree.Base.get_lineno) - - for node in list(match_set[fixer]): - if node in match_set[fixer]: - match_set[fixer].remove(node) - - try: - find_root(node) - except ValueError: - # this node has been cut off from a - # previous transformation ; skip - continue - - if node.fixers_applied and fixer in node.fixers_applied: - # do not apply the same fixer again - continue - - results = fixer.match(node) - - if results: - new = fixer.transform(node, results) - if new is not None: - node.replace(new) - #new.fixers_applied.append(fixer) - for node in new.post_order(): - # do not apply the fixer again to - # this or any subnode - if not node.fixers_applied: - node.fixers_applied = [] - node.fixers_applied.append(fixer) - - # update the original match set for - # the added code - new_matches = self.BM.run(new.leaves()) - for fxr in new_matches: - if not fxr in match_set: - match_set[fxr]=[] - - match_set[fxr].extend(new_matches[fxr]) - - for fixer in chain(self.pre_order, self.post_order): - fixer.finish_tree(tree, name) - return tree.was_changed - - def traverse_by(self, fixers, traversal): - """Traverse an AST, applying a set of fixers to each node. - - This is a helper method for refactor_tree(). - - Args: - fixers: a list of fixer instances. - traversal: a generator that yields AST nodes. - - Returns: - None - """ - if not fixers: - return - for node in traversal: - for fixer in fixers[node.type]: - results = fixer.match(node) - if results: - new = fixer.transform(node, results) - if new is not None: - node.replace(new) - node = new - - def processed_file(self, new_text, filename, old_text=None, write=False, - encoding=None): - """ - Called when a file has been refactored and there may be changes. - """ - self.files.append(filename) - if old_text is None: - old_text = self._read_python_source(filename)[0] - if old_text is None: - return - equal = old_text == new_text - self.print_output(old_text, new_text, filename, equal) - if equal: - self.log_debug("No changes to %s", filename) - if not self.write_unchanged_files: - return - if write: - self.write_file(new_text, filename, old_text, encoding) - else: - self.log_debug("Not writing changes to %s", filename) - - def write_file(self, new_text, filename, old_text, encoding=None): - """Writes a string to a file. - - It first shows a unified diff between the old text and the new text, and - then rewrites the file; the latter is only done if the write option is - set. - """ - try: - fp = io.open(filename, "w", encoding=encoding, newline='') - except OSError as err: - self.log_error("Can't create %s: %s", filename, err) - return - - with fp: - try: - fp.write(new_text) - except OSError as err: - self.log_error("Can't write %s: %s", filename, err) - self.log_debug("Wrote changes to %s", filename) - self.wrote = True - - PS1 = ">>> " - PS2 = "... " - - def refactor_docstring(self, input, filename): - """Refactors a docstring, looking for doctests. - - This returns a modified version of the input string. It looks - for doctests, which start with a ">>>" prompt, and may be - continued with "..." prompts, as long as the "..." is indented - the same as the ">>>". - - (Unfortunately we can't use the doctest module's parser, - since, like most parsers, it is not geared towards preserving - the original source.) - """ - result = [] - block = None - block_lineno = None - indent = None - lineno = 0 - for line in input.splitlines(keepends=True): - lineno += 1 - if line.lstrip().startswith(self.PS1): - if block is not None: - result.extend(self.refactor_doctest(block, block_lineno, - indent, filename)) - block_lineno = lineno - block = [line] - i = line.find(self.PS1) - indent = line[:i] - elif (indent is not None and - (line.startswith(indent + self.PS2) or - line == indent + self.PS2.rstrip() + "\n")): - block.append(line) - else: - if block is not None: - result.extend(self.refactor_doctest(block, block_lineno, - indent, filename)) - block = None - indent = None - result.append(line) - if block is not None: - result.extend(self.refactor_doctest(block, block_lineno, - indent, filename)) - return "".join(result) - - def refactor_doctest(self, block, lineno, indent, filename): - """Refactors one doctest. - - A doctest is given as a block of lines, the first of which starts - with ">>>" (possibly indented), while the remaining lines start - with "..." (identically indented). - - """ - try: - tree = self.parse_block(block, lineno, indent) - except Exception as err: - if self.logger.isEnabledFor(logging.DEBUG): - for line in block: - self.log_debug("Source: %s", line.rstrip("\n")) - self.log_error("Can't parse docstring in %s line %s: %s: %s", - filename, lineno, err.__class__.__name__, err) - return block - if self.refactor_tree(tree, filename): - new = str(tree).splitlines(keepends=True) - # Undo the adjustment of the line numbers in wrap_toks() below. - clipped, new = new[:lineno-1], new[lineno-1:] - assert clipped == ["\n"] * (lineno-1), clipped - if not new[-1].endswith("\n"): - new[-1] += "\n" - block = [indent + self.PS1 + new.pop(0)] - if new: - block += [indent + self.PS2 + line for line in new] - return block - - def summarize(self): - if self.wrote: - were = "were" - else: - were = "need to be" - if not self.files: - self.log_message("No files %s modified.", were) - else: - self.log_message("Files that %s modified:", were) - for file in self.files: - self.log_message(file) - if self.fixer_log: - self.log_message("Warnings/messages while refactoring:") - for message in self.fixer_log: - self.log_message(message) - if self.errors: - if len(self.errors) == 1: - self.log_message("There was 1 error:") - else: - self.log_message("There were %d errors:", len(self.errors)) - for msg, args, kwds in self.errors: - self.log_message(msg, *args, **kwds) - - def parse_block(self, block, lineno, indent): - """Parses a block into a tree. - - This is necessary to get correct line number / offset information - in the parser diagnostics and embedded into the parse tree. - """ - tree = self.driver.parse_tokens(self.wrap_toks(block, lineno, indent)) - tree.future_features = frozenset() - return tree - - def wrap_toks(self, block, lineno, indent): - """Wraps a tokenize stream to systematically modify start/end.""" - tokens = tokenize.generate_tokens(self.gen_lines(block, indent).__next__) - for type, value, (line0, col0), (line1, col1), line_text in tokens: - line0 += lineno - 1 - line1 += lineno - 1 - # Don't bother updating the columns; this is too complicated - # since line_text would also have to be updated and it would - # still break for tokens spanning lines. Let the user guess - # that the column numbers for doctests are relative to the - # end of the prompt string (PS1 or PS2). - yield type, value, (line0, col0), (line1, col1), line_text - - - def gen_lines(self, block, indent): - """Generates lines as expected by tokenize from a list of lines. - - This strips the first len(indent + self.PS1) characters off each line. - """ - prefix1 = indent + self.PS1 - prefix2 = indent + self.PS2 - prefix = prefix1 - for line in block: - if line.startswith(prefix): - yield line[len(prefix):] - elif line == prefix.rstrip() + "\n": - yield "\n" - else: - raise AssertionError("line=%r, prefix=%r" % (line, prefix)) - prefix = prefix2 - while True: - yield "" - - -class MultiprocessingUnsupported(Exception): - pass - - -class MultiprocessRefactoringTool(RefactoringTool): - - def __init__(self, *args, **kwargs): - super(MultiprocessRefactoringTool, self).__init__(*args, **kwargs) - self.queue = None - self.output_lock = None - - def refactor(self, items, write=False, doctests_only=False, - num_processes=1): - if num_processes == 1: - return super(MultiprocessRefactoringTool, self).refactor( - items, write, doctests_only) - try: - import multiprocessing - except ImportError: - raise MultiprocessingUnsupported - if self.queue is not None: - raise RuntimeError("already doing multiple processes") - self.queue = multiprocessing.JoinableQueue() - self.output_lock = multiprocessing.Lock() - processes = [multiprocessing.Process(target=self._child) - for i in range(num_processes)] - try: - for p in processes: - p.start() - super(MultiprocessRefactoringTool, self).refactor(items, write, - doctests_only) - finally: - self.queue.join() - for i in range(num_processes): - self.queue.put(None) - for p in processes: - if p.is_alive(): - p.join() - self.queue = None - - def _child(self): - task = self.queue.get() - while task is not None: - args, kwargs = task - try: - super(MultiprocessRefactoringTool, self).refactor_file( - *args, **kwargs) - finally: - self.queue.task_done() - task = self.queue.get() - - def refactor_file(self, *args, **kwargs): - if self.queue is not None: - self.queue.put((args, kwargs)) - else: - return super(MultiprocessRefactoringTool, self).refactor_file( - *args, **kwargs) diff --git a/Lib/test/test_lib2to3/__init__.py b/Lib/test/test_lib2to3/__init__.py deleted file mode 100644 index f323c2355b228..0000000000000 --- a/Lib/test/test_lib2to3/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Author: Collin Winter - -import os -import warnings - -from test.support import load_package_tests - -def load_tests(*args): - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', category=DeprecationWarning, message='lib2to3') - return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_lib2to3/__main__.py b/Lib/test/test_lib2to3/__main__.py deleted file mode 100644 index 40a23a297ec2b..0000000000000 --- a/Lib/test/test_lib2to3/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from . import load_tests -import unittest - -unittest.main() diff --git a/Lib/test/test_lib2to3/data/README b/Lib/test/test_lib2to3/data/README deleted file mode 100644 index 7aa47e40aa97f..0000000000000 --- a/Lib/test/test_lib2to3/data/README +++ /dev/null @@ -1,6 +0,0 @@ -In this directory: -- py2_test_grammar.py -- test file that exercises most/all of Python 2.x's grammar. -- py3_test_grammar.py -- test file that exercises most/all of Python 3.x's grammar. -- infinite_recursion.py -- test file that causes lib2to3's faster recursive pattern matching - scheme to fail, but passes when lib2to3 falls back to iterative pattern matching. -- fixes/ -- for use by test_refactor.py diff --git a/Lib/test/test_lib2to3/data/bom.py b/Lib/test/test_lib2to3/data/bom.py deleted file mode 100644 index 9bc3975a42f60..0000000000000 --- a/Lib/test/test_lib2to3/data/bom.py +++ /dev/null @@ -1,2 +0,0 @@ -?# coding: utf-8 -print "BOM BOOM!" diff --git a/Lib/test/test_lib2to3/data/crlf.py b/Lib/test/test_lib2to3/data/crlf.py deleted file mode 100644 index a83ca8f0a2068..0000000000000 --- a/Lib/test/test_lib2to3/data/crlf.py +++ /dev/null @@ -1,3 +0,0 @@ -print "hi" - -print "Like bad Windows newlines?" diff --git a/Lib/test/test_lib2to3/data/different_encoding.py b/Lib/test/test_lib2to3/data/different_encoding.py deleted file mode 100755 index 9f32bd04dc28d..0000000000000 --- a/Lib/test/test_lib2to3/data/different_encoding.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -print u'??????????????????????????????????????????????????????????????' - -def f(x): - print '%s\t-> ?(%2i):%s ?(%s)' diff --git a/Lib/test/test_lib2to3/data/false_encoding.py b/Lib/test/test_lib2to3/data/false_encoding.py deleted file mode 100755 index f4e59e787da1e..0000000000000 --- a/Lib/test/test_lib2to3/data/false_encoding.py +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env python -print '#coding=0' diff --git a/Lib/test/test_lib2to3/data/fixers/bad_order.py b/Lib/test/test_lib2to3/data/fixers/bad_order.py deleted file mode 100644 index 061bbf209a0de..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/bad_order.py +++ /dev/null @@ -1,5 +0,0 @@ -from lib2to3.fixer_base import BaseFix - -class FixBadOrder(BaseFix): - - order = "crazy" diff --git a/Lib/test/test_lib2to3/data/fixers/myfixes/__init__.py b/Lib/test/test_lib2to3/data/fixers/myfixes/__init__.py deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_explicit.py b/Lib/test/test_lib2to3/data/fixers/myfixes/fix_explicit.py deleted file mode 100644 index cbe16f6f1f0df..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_explicit.py +++ /dev/null @@ -1,6 +0,0 @@ -from lib2to3.fixer_base import BaseFix - -class FixExplicit(BaseFix): - explicit = True - - def match(self): return False diff --git a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_first.py b/Lib/test/test_lib2to3/data/fixers/myfixes/fix_first.py deleted file mode 100644 index a88821f06b2d1..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_first.py +++ /dev/null @@ -1,6 +0,0 @@ -from lib2to3.fixer_base import BaseFix - -class FixFirst(BaseFix): - run_order = 1 - - def match(self, node): return False diff --git a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_last.py b/Lib/test/test_lib2to3/data/fixers/myfixes/fix_last.py deleted file mode 100644 index 9a077d41594da..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_last.py +++ /dev/null @@ -1,7 +0,0 @@ -from lib2to3.fixer_base import BaseFix - -class FixLast(BaseFix): - - run_order = 10 - - def match(self, node): return False diff --git a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_parrot.py b/Lib/test/test_lib2to3/data/fixers/myfixes/fix_parrot.py deleted file mode 100644 index 6db79adf8d80c..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_parrot.py +++ /dev/null @@ -1,13 +0,0 @@ -from lib2to3.fixer_base import BaseFix -from lib2to3.fixer_util import Name - -class FixParrot(BaseFix): - """ - Change functions named 'parrot' to 'cheese'. - """ - - PATTERN = """funcdef < 'def' name='parrot' any* >""" - - def transform(self, node, results): - name = results["name"] - name.replace(Name("cheese", name.prefix)) diff --git a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_preorder.py b/Lib/test/test_lib2to3/data/fixers/myfixes/fix_preorder.py deleted file mode 100644 index b9bfbba9d5e90..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/myfixes/fix_preorder.py +++ /dev/null @@ -1,6 +0,0 @@ -from lib2to3.fixer_base import BaseFix - -class FixPreorder(BaseFix): - order = "pre" - - def match(self, node): return False diff --git a/Lib/test/test_lib2to3/data/fixers/no_fixer_cls.py b/Lib/test/test_lib2to3/data/fixers/no_fixer_cls.py deleted file mode 100644 index 506f794951705..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/no_fixer_cls.py +++ /dev/null @@ -1 +0,0 @@ -# This is empty so trying to fetch the fixer class gives an AttributeError diff --git a/Lib/test/test_lib2to3/data/fixers/parrot_example.py b/Lib/test/test_lib2to3/data/fixers/parrot_example.py deleted file mode 100644 index 08529280cdb4a..0000000000000 --- a/Lib/test/test_lib2to3/data/fixers/parrot_example.py +++ /dev/null @@ -1,2 +0,0 @@ -def parrot(): - pass diff --git a/Lib/test/test_lib2to3/data/infinite_recursion.py b/Lib/test/test_lib2to3/data/infinite_recursion.py deleted file mode 100644 index acc62ed4f1a44..0000000000000 --- a/Lib/test/test_lib2to3/data/infinite_recursion.py +++ /dev/null @@ -1,2669 +0,0 @@ -# Verify that 2to3 falls back from the recursive pattern matching scheme to a -# slower, iterative scheme in the event of a RecursionError. -from ctypes import * -STRING = c_char_p - - -OSUnknownByteOrder = 0 -UIT_PROMPT = 1 -P_PGID = 2 -P_PID = 1 -UIT_ERROR = 5 -UIT_INFO = 4 -UIT_NONE = 0 -P_ALL = 0 -UIT_VERIFY = 2 -OSBigEndian = 2 -UIT_BOOLEAN = 3 -OSLittleEndian = 1 -__darwin_nl_item = c_int -__darwin_wctrans_t = c_int -__darwin_wctype_t = c_ulong -__int8_t = c_byte -__uint8_t = c_ubyte -__int16_t = c_short -__uint16_t = c_ushort -__int32_t = c_int -__uint32_t = c_uint -__int64_t = c_longlong -__uint64_t = c_ulonglong -__darwin_intptr_t = c_long -__darwin_natural_t = c_uint -__darwin_ct_rune_t = c_int -class __mbstate_t(Union): - pass -__mbstate_t._pack_ = 4 -__mbstate_t._fields_ = [ - ('__mbstate8', c_char * 128), - ('_mbstateL', c_longlong), -] -assert sizeof(__mbstate_t) == 128, sizeof(__mbstate_t) -assert alignment(__mbstate_t) == 4, alignment(__mbstate_t) -__darwin_mbstate_t = __mbstate_t -__darwin_ptrdiff_t = c_int -__darwin_size_t = c_ulong -__darwin_va_list = STRING -__darwin_wchar_t = c_int -__darwin_rune_t = __darwin_wchar_t -__darwin_wint_t = c_int -__darwin_clock_t = c_ulong -__darwin_socklen_t = __uint32_t -__darwin_ssize_t = c_long -__darwin_time_t = c_long -sig_atomic_t = c_int -class sigcontext(Structure): - pass -sigcontext._fields_ = [ - ('sc_onstack', c_int), - ('sc_mask', c_int), - ('sc_eax', c_uint), - ('sc_ebx', c_uint), - ('sc_ecx', c_uint), - ('sc_edx', c_uint), - ('sc_edi', c_uint), - ('sc_esi', c_uint), - ('sc_ebp', c_uint), - ('sc_esp', c_uint), - ('sc_ss', c_uint), - ('sc_eflags', c_uint), - ('sc_eip', c_uint), - ('sc_cs', c_uint), - ('sc_ds', c_uint), - ('sc_es', c_uint), - ('sc_fs', c_uint), - ('sc_gs', c_uint), -] -assert sizeof(sigcontext) == 72, sizeof(sigcontext) -assert alignment(sigcontext) == 4, alignment(sigcontext) -u_int8_t = c_ubyte -u_int16_t = c_ushort -u_int32_t = c_uint -u_int64_t = c_ulonglong -int32_t = c_int -register_t = int32_t -user_addr_t = u_int64_t -user_size_t = u_int64_t -int64_t = c_longlong -user_ssize_t = int64_t -user_long_t = int64_t -user_ulong_t = u_int64_t -user_time_t = int64_t -syscall_arg_t = u_int64_t - -# values for unnamed enumeration -class aes_key_st(Structure): - pass -aes_key_st._fields_ = [ - ('rd_key', c_ulong * 60), - ('rounds', c_int), -] -assert sizeof(aes_key_st) == 244, sizeof(aes_key_st) -assert alignment(aes_key_st) == 4, alignment(aes_key_st) -AES_KEY = aes_key_st -class asn1_ctx_st(Structure): - pass -asn1_ctx_st._fields_ = [ - ('p', POINTER(c_ubyte)), - ('eos', c_int), - ('error', c_int), - ('inf', c_int), - ('tag', c_int), - ('xclass', c_int), - ('slen', c_long), - ('max', POINTER(c_ubyte)), - ('q', POINTER(c_ubyte)), - ('pp', POINTER(POINTER(c_ubyte))), - ('line', c_int), -] -assert sizeof(asn1_ctx_st) == 44, sizeof(asn1_ctx_st) -assert alignment(asn1_ctx_st) == 4, alignment(asn1_ctx_st) -ASN1_CTX = asn1_ctx_st -class asn1_object_st(Structure): - pass -asn1_object_st._fields_ = [ - ('sn', STRING), - ('ln', STRING), - ('nid', c_int), - ('length', c_int), - ('data', POINTER(c_ubyte)), - ('flags', c_int), -] -assert sizeof(asn1_object_st) == 24, sizeof(asn1_object_st) -assert alignment(asn1_object_st) == 4, alignment(asn1_object_st) -ASN1_OBJECT = asn1_object_st -class asn1_string_st(Structure): - pass -asn1_string_st._fields_ = [ - ('length', c_int), - ('type', c_int), - ('data', POINTER(c_ubyte)), - ('flags', c_long), -] -assert sizeof(asn1_string_st) == 16, sizeof(asn1_string_st) -assert alignment(asn1_string_st) == 4, alignment(asn1_string_st) -ASN1_STRING = asn1_string_st -class ASN1_ENCODING_st(Structure): - pass -ASN1_ENCODING_st._fields_ = [ - ('enc', POINTER(c_ubyte)), - ('len', c_long), - ('modified', c_int), -] -assert sizeof(ASN1_ENCODING_st) == 12, sizeof(ASN1_ENCODING_st) -assert alignment(ASN1_ENCODING_st) == 4, alignment(ASN1_ENCODING_st) -ASN1_ENCODING = ASN1_ENCODING_st -class asn1_string_table_st(Structure): - pass -asn1_string_table_st._fields_ = [ - ('nid', c_int), - ('minsize', c_long), - ('maxsize', c_long), - ('mask', c_ulong), - ('flags', c_ulong), -] -assert sizeof(asn1_string_table_st) == 20, sizeof(asn1_string_table_st) -assert alignment(asn1_string_table_st) == 4, alignment(asn1_string_table_st) -ASN1_STRING_TABLE = asn1_string_table_st -class ASN1_TEMPLATE_st(Structure): - pass -ASN1_TEMPLATE_st._fields_ = [ -] -ASN1_TEMPLATE = ASN1_TEMPLATE_st -class ASN1_ITEM_st(Structure): - pass -ASN1_ITEM = ASN1_ITEM_st -ASN1_ITEM_st._fields_ = [ -] -class ASN1_TLC_st(Structure): - pass -ASN1_TLC = ASN1_TLC_st -ASN1_TLC_st._fields_ = [ -] -class ASN1_VALUE_st(Structure): - pass -ASN1_VALUE_st._fields_ = [ -] -ASN1_VALUE = ASN1_VALUE_st -ASN1_ITEM_EXP = ASN1_ITEM -class asn1_type_st(Structure): - pass -class N12asn1_type_st4DOLLAR_11E(Union): - pass -ASN1_BOOLEAN = c_int -ASN1_INTEGER = asn1_string_st -ASN1_ENUMERATED = asn1_string_st -ASN1_BIT_STRING = asn1_string_st -ASN1_OCTET_STRING = asn1_string_st -ASN1_PRINTABLESTRING = asn1_string_st -ASN1_T61STRING = asn1_string_st -ASN1_IA5STRING = asn1_string_st -ASN1_GENERALSTRING = asn1_string_st -ASN1_BMPSTRING = asn1_string_st -ASN1_UNIVERSALSTRING = asn1_string_st -ASN1_UTCTIME = asn1_string_st -ASN1_GENERALIZEDTIME = asn1_string_st -ASN1_VISIBLESTRING = asn1_string_st -ASN1_UTF8STRING = asn1_string_st -N12asn1_type_st4DOLLAR_11E._fields_ = [ - ('ptr', STRING), - ('boolean', ASN1_BOOLEAN), - ('asn1_string', POINTER(ASN1_STRING)), - ('object', POINTER(ASN1_OBJECT)), - ('integer', POINTER(ASN1_INTEGER)), - ('enumerated', POINTER(ASN1_ENUMERATED)), - ('bit_string', POINTER(ASN1_BIT_STRING)), - ('octet_string', POINTER(ASN1_OCTET_STRING)), - ('printablestring', POINTER(ASN1_PRINTABLESTRING)), - ('t61string', POINTER(ASN1_T61STRING)), - ('ia5string', POINTER(ASN1_IA5STRING)), - ('generalstring', POINTER(ASN1_GENERALSTRING)), - ('bmpstring', POINTER(ASN1_BMPSTRING)), - ('universalstring', POINTER(ASN1_UNIVERSALSTRING)), - ('utctime', POINTER(ASN1_UTCTIME)), - ('generalizedtime', POINTER(ASN1_GENERALIZEDTIME)), - ('visiblestring', POINTER(ASN1_VISIBLESTRING)), - ('utf8string', POINTER(ASN1_UTF8STRING)), - ('set', POINTER(ASN1_STRING)), - ('sequence', POINTER(ASN1_STRING)), -] -assert sizeof(N12asn1_type_st4DOLLAR_11E) == 4, sizeof(N12asn1_type_st4DOLLAR_11E) -assert alignment(N12asn1_type_st4DOLLAR_11E) == 4, alignment(N12asn1_type_st4DOLLAR_11E) -asn1_type_st._fields_ = [ - ('type', c_int), - ('value', N12asn1_type_st4DOLLAR_11E), -] -assert sizeof(asn1_type_st) == 8, sizeof(asn1_type_st) -assert alignment(asn1_type_st) == 4, alignment(asn1_type_st) -ASN1_TYPE = asn1_type_st -class asn1_method_st(Structure): - pass -asn1_method_st._fields_ = [ - ('i2d', CFUNCTYPE(c_int)), - ('d2i', CFUNCTYPE(STRING)), - ('create', CFUNCTYPE(STRING)), - ('destroy', CFUNCTYPE(None)), -] -assert sizeof(asn1_method_st) == 16, sizeof(asn1_method_st) -assert alignment(asn1_method_st) == 4, alignment(asn1_method_st) -ASN1_METHOD = asn1_method_st -class asn1_header_st(Structure): - pass -asn1_header_st._fields_ = [ - ('header', POINTER(ASN1_OCTET_STRING)), - ('data', STRING), - ('meth', POINTER(ASN1_METHOD)), -] -assert sizeof(asn1_header_st) == 12, sizeof(asn1_header_st) -assert alignment(asn1_header_st) == 4, alignment(asn1_header_st) -ASN1_HEADER = asn1_header_st -class BIT_STRING_BITNAME_st(Structure): - pass -BIT_STRING_BITNAME_st._fields_ = [ - ('bitnum', c_int), - ('lname', STRING), - ('sname', STRING), -] -assert sizeof(BIT_STRING_BITNAME_st) == 12, sizeof(BIT_STRING_BITNAME_st) -assert alignment(BIT_STRING_BITNAME_st) == 4, alignment(BIT_STRING_BITNAME_st) -BIT_STRING_BITNAME = BIT_STRING_BITNAME_st -class bio_st(Structure): - pass -BIO = bio_st -bio_info_cb = CFUNCTYPE(None, POINTER(bio_st), c_int, STRING, c_int, c_long, c_long) -class bio_method_st(Structure): - pass -bio_method_st._fields_ = [ - ('type', c_int), - ('name', STRING), - ('bwrite', CFUNCTYPE(c_int, POINTER(BIO), STRING, c_int)), - ('bread', CFUNCTYPE(c_int, POINTER(BIO), STRING, c_int)), - ('bputs', CFUNCTYPE(c_int, POINTER(BIO), STRING)), - ('bgets', CFUNCTYPE(c_int, POINTER(BIO), STRING, c_int)), - ('ctrl', CFUNCTYPE(c_long, POINTER(BIO), c_int, c_long, c_void_p)), - ('create', CFUNCTYPE(c_int, POINTER(BIO))), - ('destroy', CFUNCTYPE(c_int, POINTER(BIO))), - ('callback_ctrl', CFUNCTYPE(c_long, POINTER(BIO), c_int, POINTER(bio_info_cb))), -] -assert sizeof(bio_method_st) == 40, sizeof(bio_method_st) -assert alignment(bio_method_st) == 4, alignment(bio_method_st) -BIO_METHOD = bio_method_st -class crypto_ex_data_st(Structure): - pass -class stack_st(Structure): - pass -STACK = stack_st -crypto_ex_data_st._fields_ = [ - ('sk', POINTER(STACK)), - ('dummy', c_int), -] -assert sizeof(crypto_ex_data_st) == 8, sizeof(crypto_ex_data_st) -assert alignment(crypto_ex_data_st) == 4, alignment(crypto_ex_data_st) -CRYPTO_EX_DATA = crypto_ex_data_st -bio_st._fields_ = [ - ('method', POINTER(BIO_METHOD)), - ('callback', CFUNCTYPE(c_long, POINTER(bio_st), c_int, STRING, c_int, c_long, c_long)), - ('cb_arg', STRING), - ('init', c_int), - ('shutdown', c_int), - ('flags', c_int), - ('retry_reason', c_int), - ('num', c_int), - ('ptr', c_void_p), - ('next_bio', POINTER(bio_st)), - ('prev_bio', POINTER(bio_st)), - ('references', c_int), - ('num_read', c_ulong), - ('num_write', c_ulong), - ('ex_data', CRYPTO_EX_DATA), -] -assert sizeof(bio_st) == 64, sizeof(bio_st) -assert alignment(bio_st) == 4, alignment(bio_st) -class bio_f_buffer_ctx_struct(Structure): - pass -bio_f_buffer_ctx_struct._fields_ = [ - ('ibuf_size', c_int), - ('obuf_size', c_int), - ('ibuf', STRING), - ('ibuf_len', c_int), - ('ibuf_off', c_int), - ('obuf', STRING), - ('obuf_len', c_int), - ('obuf_off', c_int), -] -assert sizeof(bio_f_buffer_ctx_struct) == 32, sizeof(bio_f_buffer_ctx_struct) -assert alignment(bio_f_buffer_ctx_struct) == 4, alignment(bio_f_buffer_ctx_struct) -BIO_F_BUFFER_CTX = bio_f_buffer_ctx_struct -class hostent(Structure): - pass -hostent._fields_ = [ -] -class bf_key_st(Structure): - pass -bf_key_st._fields_ = [ - ('P', c_uint * 18), - ('S', c_uint * 1024), -] -assert sizeof(bf_key_st) == 4168, sizeof(bf_key_st) -assert alignment(bf_key_st) == 4, alignment(bf_key_st) -BF_KEY = bf_key_st -class bignum_st(Structure): - pass -bignum_st._fields_ = [ - ('d', POINTER(c_ulong)), - ('top', c_int), - ('dmax', c_int), - ('neg', c_int), - ('flags', c_int), -] -assert sizeof(bignum_st) == 20, sizeof(bignum_st) -assert alignment(bignum_st) == 4, alignment(bignum_st) -BIGNUM = bignum_st -class bignum_ctx(Structure): - pass -bignum_ctx._fields_ = [ -] -BN_CTX = bignum_ctx -class bn_blinding_st(Structure): - pass -bn_blinding_st._fields_ = [ - ('init', c_int), - ('A', POINTER(BIGNUM)), - ('Ai', POINTER(BIGNUM)), - ('mod', POINTER(BIGNUM)), - ('thread_id', c_ulong), -] -assert sizeof(bn_blinding_st) == 20, sizeof(bn_blinding_st) -assert alignment(bn_blinding_st) == 4, alignment(bn_blinding_st) -BN_BLINDING = bn_blinding_st -class bn_mont_ctx_st(Structure): - pass -bn_mont_ctx_st._fields_ = [ - ('ri', c_int), - ('RR', BIGNUM), - ('N', BIGNUM), - ('Ni', BIGNUM), - ('n0', c_ulong), - ('flags', c_int), -] -assert sizeof(bn_mont_ctx_st) == 72, sizeof(bn_mont_ctx_st) -assert alignment(bn_mont_ctx_st) == 4, alignment(bn_mont_ctx_st) -BN_MONT_CTX = bn_mont_ctx_st -class bn_recp_ctx_st(Structure): - pass -bn_recp_ctx_st._fields_ = [ - ('N', BIGNUM), - ('Nr', BIGNUM), - ('num_bits', c_int), - ('shift', c_int), - ('flags', c_int), -] -assert sizeof(bn_recp_ctx_st) == 52, sizeof(bn_recp_ctx_st) -assert alignment(bn_recp_ctx_st) == 4, alignment(bn_recp_ctx_st) -BN_RECP_CTX = bn_recp_ctx_st -class buf_mem_st(Structure): - pass -buf_mem_st._fields_ = [ - ('length', c_int), - ('data', STRING), - ('max', c_int), -] -assert sizeof(buf_mem_st) == 12, sizeof(buf_mem_st) -assert alignment(buf_mem_st) == 4, alignment(buf_mem_st) -BUF_MEM = buf_mem_st -class cast_key_st(Structure): - pass -cast_key_st._fields_ = [ - ('data', c_ulong * 32), - ('short_key', c_int), -] -assert sizeof(cast_key_st) == 132, sizeof(cast_key_st) -assert alignment(cast_key_st) == 4, alignment(cast_key_st) -CAST_KEY = cast_key_st -class comp_method_st(Structure): - pass -comp_method_st._fields_ = [ - ('type', c_int), - ('name', STRING), - ('init', CFUNCTYPE(c_int)), - ('finish', CFUNCTYPE(None)), - ('compress', CFUNCTYPE(c_int)), - ('expand', CFUNCTYPE(c_int)), - ('ctrl', CFUNCTYPE(c_long)), - ('callback_ctrl', CFUNCTYPE(c_long)), -] -assert sizeof(comp_method_st) == 32, sizeof(comp_method_st) -assert alignment(comp_method_st) == 4, alignment(comp_method_st) -COMP_METHOD = comp_method_st -class comp_ctx_st(Structure): - pass -comp_ctx_st._fields_ = [ - ('meth', POINTER(COMP_METHOD)), - ('compress_in', c_ulong), - ('compress_out', c_ulong), - ('expand_in', c_ulong), - ('expand_out', c_ulong), - ('ex_data', CRYPTO_EX_DATA), -] -assert sizeof(comp_ctx_st) == 28, sizeof(comp_ctx_st) -assert alignment(comp_ctx_st) == 4, alignment(comp_ctx_st) -COMP_CTX = comp_ctx_st -class CRYPTO_dynlock_value(Structure): - pass -CRYPTO_dynlock_value._fields_ = [ -] -class CRYPTO_dynlock(Structure): - pass -CRYPTO_dynlock._fields_ = [ - ('references', c_int), - ('data', POINTER(CRYPTO_dynlock_value)), -] -assert sizeof(CRYPTO_dynlock) == 8, sizeof(CRYPTO_dynlock) -assert alignment(CRYPTO_dynlock) == 4, alignment(CRYPTO_dynlock) -BIO_dummy = bio_st -CRYPTO_EX_new = CFUNCTYPE(c_int, c_void_p, c_void_p, POINTER(CRYPTO_EX_DATA), c_int, c_long, c_void_p) -CRYPTO_EX_free = CFUNCTYPE(None, c_void_p, c_void_p, POINTER(CRYPTO_EX_DATA), c_int, c_long, c_void_p) -CRYPTO_EX_dup = CFUNCTYPE(c_int, POINTER(CRYPTO_EX_DATA), POINTER(CRYPTO_EX_DATA), c_void_p, c_int, c_long, c_void_p) -class crypto_ex_data_func_st(Structure): - pass -crypto_ex_data_func_st._fields_ = [ - ('argl', c_long), - ('argp', c_void_p), - ('new_func', POINTER(CRYPTO_EX_new)), - ('free_func', POINTER(CRYPTO_EX_free)), - ('dup_func', POINTER(CRYPTO_EX_dup)), -] -assert sizeof(crypto_ex_data_func_st) == 20, sizeof(crypto_ex_data_func_st) -assert alignment(crypto_ex_data_func_st) == 4, alignment(crypto_ex_data_func_st) -CRYPTO_EX_DATA_FUNCS = crypto_ex_data_func_st -class st_CRYPTO_EX_DATA_IMPL(Structure): - pass -CRYPTO_EX_DATA_IMPL = st_CRYPTO_EX_DATA_IMPL -st_CRYPTO_EX_DATA_IMPL._fields_ = [ -] -CRYPTO_MEM_LEAK_CB = CFUNCTYPE(c_void_p, c_ulong, STRING, c_int, c_int, c_void_p) -DES_cblock = c_ubyte * 8 -const_DES_cblock = c_ubyte * 8 -class DES_ks(Structure): - pass -class N6DES_ks3DOLLAR_9E(Union): - pass -N6DES_ks3DOLLAR_9E._fields_ = [ - ('cblock', DES_cblock), - ('deslong', c_ulong * 2), -] -assert sizeof(N6DES_ks3DOLLAR_9E) == 8, sizeof(N6DES_ks3DOLLAR_9E) -assert alignment(N6DES_ks3DOLLAR_9E) == 4, alignment(N6DES_ks3DOLLAR_9E) -DES_ks._fields_ = [ - ('ks', N6DES_ks3DOLLAR_9E * 16), -] -assert sizeof(DES_ks) == 128, sizeof(DES_ks) -assert alignment(DES_ks) == 4, alignment(DES_ks) -DES_key_schedule = DES_ks -_ossl_old_des_cblock = c_ubyte * 8 -class _ossl_old_des_ks_struct(Structure): - pass -class N23_ossl_old_des_ks_struct4DOLLAR_10E(Union): - pass -N23_ossl_old_des_ks_struct4DOLLAR_10E._fields_ = [ - ('_', _ossl_old_des_cblock), - ('pad', c_ulong * 2), -] -assert sizeof(N23_ossl_old_des_ks_struct4DOLLAR_10E) == 8, sizeof(N23_ossl_old_des_ks_struct4DOLLAR_10E) -assert alignment(N23_ossl_old_des_ks_struct4DOLLAR_10E) == 4, alignment(N23_ossl_old_des_ks_struct4DOLLAR_10E) -_ossl_old_des_ks_struct._fields_ = [ - ('ks', N23_ossl_old_des_ks_struct4DOLLAR_10E), -] -assert sizeof(_ossl_old_des_ks_struct) == 8, sizeof(_ossl_old_des_ks_struct) -assert alignment(_ossl_old_des_ks_struct) == 4, alignment(_ossl_old_des_ks_struct) -_ossl_old_des_key_schedule = _ossl_old_des_ks_struct * 16 -class dh_st(Structure): - pass -DH = dh_st -class dh_method(Structure): - pass -dh_method._fields_ = [ - ('name', STRING), - ('generate_key', CFUNCTYPE(c_int, POINTER(DH))), - ('compute_key', CFUNCTYPE(c_int, POINTER(c_ubyte), POINTER(BIGNUM), POINTER(DH))), - ('bn_mod_exp', CFUNCTYPE(c_int, POINTER(DH), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BN_CTX), POINTER(BN_MONT_CTX))), - ('init', CFUNCTYPE(c_int, POINTER(DH))), - ('finish', CFUNCTYPE(c_int, POINTER(DH))), - ('flags', c_int), - ('app_data', STRING), -] -assert sizeof(dh_method) == 32, sizeof(dh_method) -assert alignment(dh_method) == 4, alignment(dh_method) -DH_METHOD = dh_method -class engine_st(Structure): - pass -ENGINE = engine_st -dh_st._fields_ = [ - ('pad', c_int), - ('version', c_int), - ('p', POINTER(BIGNUM)), - ('g', POINTER(BIGNUM)), - ('length', c_long), - ('pub_key', POINTER(BIGNUM)), - ('priv_key', POINTER(BIGNUM)), - ('flags', c_int), - ('method_mont_p', STRING), - ('q', POINTER(BIGNUM)), - ('j', POINTER(BIGNUM)), - ('seed', POINTER(c_ubyte)), - ('seedlen', c_int), - ('counter', POINTER(BIGNUM)), - ('references', c_int), - ('ex_data', CRYPTO_EX_DATA), - ('meth', POINTER(DH_METHOD)), - ('engine', POINTER(ENGINE)), -] -assert sizeof(dh_st) == 76, sizeof(dh_st) -assert alignment(dh_st) == 4, alignment(dh_st) -class dsa_st(Structure): - pass -DSA = dsa_st -class DSA_SIG_st(Structure): - pass -DSA_SIG_st._fields_ = [ - ('r', POINTER(BIGNUM)), - ('s', POINTER(BIGNUM)), -] -assert sizeof(DSA_SIG_st) == 8, sizeof(DSA_SIG_st) -assert alignment(DSA_SIG_st) == 4, alignment(DSA_SIG_st) -DSA_SIG = DSA_SIG_st -class dsa_method(Structure): - pass -dsa_method._fields_ = [ - ('name', STRING), - ('dsa_do_sign', CFUNCTYPE(POINTER(DSA_SIG), POINTER(c_ubyte), c_int, POINTER(DSA))), - ('dsa_sign_setup', CFUNCTYPE(c_int, POINTER(DSA), POINTER(BN_CTX), POINTER(POINTER(BIGNUM)), POINTER(POINTER(BIGNUM)))), - ('dsa_do_verify', CFUNCTYPE(c_int, POINTER(c_ubyte), c_int, POINTER(DSA_SIG), POINTER(DSA))), - ('dsa_mod_exp', CFUNCTYPE(c_int, POINTER(DSA), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BN_CTX), POINTER(BN_MONT_CTX))), - ('bn_mod_exp', CFUNCTYPE(c_int, POINTER(DSA), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BN_CTX), POINTER(BN_MONT_CTX))), - ('init', CFUNCTYPE(c_int, POINTER(DSA))), - ('finish', CFUNCTYPE(c_int, POINTER(DSA))), - ('flags', c_int), - ('app_data', STRING), -] -assert sizeof(dsa_method) == 40, sizeof(dsa_method) -assert alignment(dsa_method) == 4, alignment(dsa_method) -DSA_METHOD = dsa_method -dsa_st._fields_ = [ - ('pad', c_int), - ('version', c_long), - ('write_params', c_int), - ('p', POINTER(BIGNUM)), - ('q', POINTER(BIGNUM)), - ('g', POINTER(BIGNUM)), - ('pub_key', POINTER(BIGNUM)), - ('priv_key', POINTER(BIGNUM)), - ('kinv', POINTER(BIGNUM)), - ('r', POINTER(BIGNUM)), - ('flags', c_int), - ('method_mont_p', STRING), - ('references', c_int), - ('ex_data', CRYPTO_EX_DATA), - ('meth', POINTER(DSA_METHOD)), - ('engine', POINTER(ENGINE)), -] -assert sizeof(dsa_st) == 68, sizeof(dsa_st) -assert alignment(dsa_st) == 4, alignment(dsa_st) -class evp_pkey_st(Structure): - pass -class N11evp_pkey_st4DOLLAR_12E(Union): - pass -class rsa_st(Structure): - pass -N11evp_pkey_st4DOLLAR_12E._fields_ = [ - ('ptr', STRING), - ('rsa', POINTER(rsa_st)), - ('dsa', POINTER(dsa_st)), - ('dh', POINTER(dh_st)), -] -assert sizeof(N11evp_pkey_st4DOLLAR_12E) == 4, sizeof(N11evp_pkey_st4DOLLAR_12E) -assert alignment(N11evp_pkey_st4DOLLAR_12E) == 4, alignment(N11evp_pkey_st4DOLLAR_12E) -evp_pkey_st._fields_ = [ - ('type', c_int), - ('save_type', c_int), - ('references', c_int), - ('pkey', N11evp_pkey_st4DOLLAR_12E), - ('save_parameters', c_int), - ('attributes', POINTER(STACK)), -] -assert sizeof(evp_pkey_st) == 24, sizeof(evp_pkey_st) -assert alignment(evp_pkey_st) == 4, alignment(evp_pkey_st) -class env_md_st(Structure): - pass -class env_md_ctx_st(Structure): - pass -EVP_MD_CTX = env_md_ctx_st -env_md_st._fields_ = [ - ('type', c_int), - ('pkey_type', c_int), - ('md_size', c_int), - ('flags', c_ulong), - ('init', CFUNCTYPE(c_int, POINTER(EVP_MD_CTX))), - ('update', CFUNCTYPE(c_int, POINTER(EVP_MD_CTX), c_void_p, c_ulong)), - ('final', CFUNCTYPE(c_int, POINTER(EVP_MD_CTX), POINTER(c_ubyte))), - ('copy', CFUNCTYPE(c_int, POINTER(EVP_MD_CTX), POINTER(EVP_MD_CTX))), - ('cleanup', CFUNCTYPE(c_int, POINTER(EVP_MD_CTX))), - ('sign', CFUNCTYPE(c_int)), - ('verify', CFUNCTYPE(c_int)), - ('required_pkey_type', c_int * 5), - ('block_size', c_int), - ('ctx_size', c_int), -] -assert sizeof(env_md_st) == 72, sizeof(env_md_st) -assert alignment(env_md_st) == 4, alignment(env_md_st) -EVP_MD = env_md_st -env_md_ctx_st._fields_ = [ - ('digest', POINTER(EVP_MD)), - ('engine', POINTER(ENGINE)), - ('flags', c_ulong), - ('md_data', c_void_p), -] -assert sizeof(env_md_ctx_st) == 16, sizeof(env_md_ctx_st) -assert alignment(env_md_ctx_st) == 4, alignment(env_md_ctx_st) -class evp_cipher_st(Structure): - pass -class evp_cipher_ctx_st(Structure): - pass -EVP_CIPHER_CTX = evp_cipher_ctx_st -evp_cipher_st._fields_ = [ - ('nid', c_int), - ('block_size', c_int), - ('key_len', c_int), - ('iv_len', c_int), - ('flags', c_ulong), - ('init', CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX), POINTER(c_ubyte), POINTER(c_ubyte), c_int)), - ('do_cipher', CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX), POINTER(c_ubyte), POINTER(c_ubyte), c_uint)), - ('cleanup', CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX))), - ('ctx_size', c_int), - ('set_asn1_parameters', CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX), POINTER(ASN1_TYPE))), - ('get_asn1_parameters', CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX), POINTER(ASN1_TYPE))), - ('ctrl', CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX), c_int, c_int, c_void_p)), - ('app_data', c_void_p), -] -assert sizeof(evp_cipher_st) == 52, sizeof(evp_cipher_st) -assert alignment(evp_cipher_st) == 4, alignment(evp_cipher_st) -class evp_cipher_info_st(Structure): - pass -EVP_CIPHER = evp_cipher_st -evp_cipher_info_st._fields_ = [ - ('cipher', POINTER(EVP_CIPHER)), - ('iv', c_ubyte * 16), -] -assert sizeof(evp_cipher_info_st) == 20, sizeof(evp_cipher_info_st) -assert alignment(evp_cipher_info_st) == 4, alignment(evp_cipher_info_st) -EVP_CIPHER_INFO = evp_cipher_info_st -evp_cipher_ctx_st._fields_ = [ - ('cipher', POINTER(EVP_CIPHER)), - ('engine', POINTER(ENGINE)), - ('encrypt', c_int), - ('buf_len', c_int), - ('oiv', c_ubyte * 16), - ('iv', c_ubyte * 16), - ('buf', c_ubyte * 32), - ('num', c_int), - ('app_data', c_void_p), - ('key_len', c_int), - ('flags', c_ulong), - ('cipher_data', c_void_p), - ('final_used', c_int), - ('block_mask', c_int), - ('final', c_ubyte * 32), -] -assert sizeof(evp_cipher_ctx_st) == 140, sizeof(evp_cipher_ctx_st) -assert alignment(evp_cipher_ctx_st) == 4, alignment(evp_cipher_ctx_st) -class evp_Encode_Ctx_st(Structure): - pass -evp_Encode_Ctx_st._fields_ = [ - ('num', c_int), - ('length', c_int), - ('enc_data', c_ubyte * 80), - ('line_num', c_int), - ('expect_nl', c_int), -] -assert sizeof(evp_Encode_Ctx_st) == 96, sizeof(evp_Encode_Ctx_st) -assert alignment(evp_Encode_Ctx_st) == 4, alignment(evp_Encode_Ctx_st) -EVP_ENCODE_CTX = evp_Encode_Ctx_st -EVP_PBE_KEYGEN = CFUNCTYPE(c_int, POINTER(EVP_CIPHER_CTX), STRING, c_int, POINTER(ASN1_TYPE), POINTER(EVP_CIPHER), POINTER(EVP_MD), c_int) -class lhash_node_st(Structure): - pass -lhash_node_st._fields_ = [ - ('data', c_void_p), - ('next', POINTER(lhash_node_st)), - ('hash', c_ulong), -] -assert sizeof(lhash_node_st) == 12, sizeof(lhash_node_st) -assert alignment(lhash_node_st) == 4, alignment(lhash_node_st) -LHASH_NODE = lhash_node_st -LHASH_COMP_FN_TYPE = CFUNCTYPE(c_int, c_void_p, c_void_p) -LHASH_HASH_FN_TYPE = CFUNCTYPE(c_ulong, c_void_p) -LHASH_DOALL_FN_TYPE = CFUNCTYPE(None, c_void_p) -LHASH_DOALL_ARG_FN_TYPE = CFUNCTYPE(None, c_void_p, c_void_p) -class lhash_st(Structure): - pass -lhash_st._fields_ = [ - ('b', POINTER(POINTER(LHASH_NODE))), - ('comp', LHASH_COMP_FN_TYPE), - ('hash', LHASH_HASH_FN_TYPE), - ('num_nodes', c_uint), - ('num_alloc_nodes', c_uint), - ('p', c_uint), - ('pmax', c_uint), - ('up_load', c_ulong), - ('down_load', c_ulong), - ('num_items', c_ulong), - ('num_expands', c_ulong), - ('num_expand_reallocs', c_ulong), - ('num_contracts', c_ulong), - ('num_contract_reallocs', c_ulong), - ('num_hash_calls', c_ulong), - ('num_comp_calls', c_ulong), - ('num_insert', c_ulong), - ('num_replace', c_ulong), - ('num_delete', c_ulong), - ('num_no_delete', c_ulong), - ('num_retrieve', c_ulong), - ('num_retrieve_miss', c_ulong), - ('num_hash_comps', c_ulong), - ('error', c_int), -] -assert sizeof(lhash_st) == 96, sizeof(lhash_st) -assert alignment(lhash_st) == 4, alignment(lhash_st) -LHASH = lhash_st -class MD2state_st(Structure): - pass -MD2state_st._fields_ = [ - ('num', c_int), - ('data', c_ubyte * 16), - ('cksm', c_uint * 16), - ('state', c_uint * 16), -] -assert sizeof(MD2state_st) == 148, sizeof(MD2state_st) -assert alignment(MD2state_st) == 4, alignment(MD2state_st) -MD2_CTX = MD2state_st -class MD4state_st(Structure): - pass -MD4state_st._fields_ = [ - ('A', c_uint), - ('B', c_uint), - ('C', c_uint), - ('D', c_uint), - ('Nl', c_uint), - ('Nh', c_uint), - ('data', c_uint * 16), - ('num', c_int), -] -assert sizeof(MD4state_st) == 92, sizeof(MD4state_st) -assert alignment(MD4state_st) == 4, alignment(MD4state_st) -MD4_CTX = MD4state_st -class MD5state_st(Structure): - pass -MD5state_st._fields_ = [ - ('A', c_uint), - ('B', c_uint), - ('C', c_uint), - ('D', c_uint), - ('Nl', c_uint), - ('Nh', c_uint), - ('data', c_uint * 16), - ('num', c_int), -] -assert sizeof(MD5state_st) == 92, sizeof(MD5state_st) -assert alignment(MD5state_st) == 4, alignment(MD5state_st) -MD5_CTX = MD5state_st -class mdc2_ctx_st(Structure): - pass -mdc2_ctx_st._fields_ = [ - ('num', c_int), - ('data', c_ubyte * 8), - ('h', DES_cblock), - ('hh', DES_cblock), - ('pad_type', c_int), -] -assert sizeof(mdc2_ctx_st) == 32, sizeof(mdc2_ctx_st) -assert alignment(mdc2_ctx_st) == 4, alignment(mdc2_ctx_st) -MDC2_CTX = mdc2_ctx_st -class obj_name_st(Structure): - pass -obj_name_st._fields_ = [ - ('type', c_int), - ('alias', c_int), - ('name', STRING), - ('data', STRING), -] -assert sizeof(obj_name_st) == 16, sizeof(obj_name_st) -assert alignment(obj_name_st) == 4, alignment(obj_name_st) -OBJ_NAME = obj_name_st -ASN1_TIME = asn1_string_st -ASN1_NULL = c_int -EVP_PKEY = evp_pkey_st -class x509_st(Structure): - pass -X509 = x509_st -class X509_algor_st(Structure): - pass -X509_ALGOR = X509_algor_st -class X509_crl_st(Structure): - pass -X509_CRL = X509_crl_st -class X509_name_st(Structure): - pass -X509_NAME = X509_name_st -class x509_store_st(Structure): - pass -X509_STORE = x509_store_st -class x509_store_ctx_st(Structure): - pass -X509_STORE_CTX = x509_store_ctx_st -engine_st._fields_ = [ -] -class PEM_Encode_Seal_st(Structure): - pass -PEM_Encode_Seal_st._fields_ = [ - ('encode', EVP_ENCODE_CTX), - ('md', EVP_MD_CTX), - ('cipher', EVP_CIPHER_CTX), -] -assert sizeof(PEM_Encode_Seal_st) == 252, sizeof(PEM_Encode_Seal_st) -assert alignment(PEM_Encode_Seal_st) == 4, alignment(PEM_Encode_Seal_st) -PEM_ENCODE_SEAL_CTX = PEM_Encode_Seal_st -class pem_recip_st(Structure): - pass -pem_recip_st._fields_ = [ - ('name', STRING), - ('dn', POINTER(X509_NAME)), - ('cipher', c_int), - ('key_enc', c_int), -] -assert sizeof(pem_recip_st) == 16, sizeof(pem_recip_st) -assert alignment(pem_recip_st) == 4, alignment(pem_recip_st) -PEM_USER = pem_recip_st -class pem_ctx_st(Structure): - pass -class N10pem_ctx_st4DOLLAR_16E(Structure): - pass -N10pem_ctx_st4DOLLAR_16E._fields_ = [ - ('version', c_int), - ('mode', c_int), -] -assert sizeof(N10pem_ctx_st4DOLLAR_16E) == 8, sizeof(N10pem_ctx_st4DOLLAR_16E) -assert alignment(N10pem_ctx_st4DOLLAR_16E) == 4, alignment(N10pem_ctx_st4DOLLAR_16E) -class N10pem_ctx_st4DOLLAR_17E(Structure): - pass -N10pem_ctx_st4DOLLAR_17E._fields_ = [ - ('cipher', c_int), -] -assert sizeof(N10pem_ctx_st4DOLLAR_17E) == 4, sizeof(N10pem_ctx_st4DOLLAR_17E) -assert alignment(N10pem_ctx_st4DOLLAR_17E) == 4, alignment(N10pem_ctx_st4DOLLAR_17E) -pem_ctx_st._fields_ = [ - ('type', c_int), - ('proc_type', N10pem_ctx_st4DOLLAR_16E), - ('domain', STRING), - ('DEK_info', N10pem_ctx_st4DOLLAR_17E), - ('originator', POINTER(PEM_USER)), - ('num_recipient', c_int), - ('recipient', POINTER(POINTER(PEM_USER))), - ('x509_chain', POINTER(STACK)), - ('md', POINTER(EVP_MD)), - ('md_enc', c_int), - ('md_len', c_int), - ('md_data', STRING), - ('dec', POINTER(EVP_CIPHER)), - ('key_len', c_int), - ('key', POINTER(c_ubyte)), - ('data_enc', c_int), - ('data_len', c_int), - ('data', POINTER(c_ubyte)), -] -assert sizeof(pem_ctx_st) == 76, sizeof(pem_ctx_st) -assert alignment(pem_ctx_st) == 4, alignment(pem_ctx_st) -PEM_CTX = pem_ctx_st -pem_password_cb = CFUNCTYPE(c_int, STRING, c_int, c_int, c_void_p) -class pkcs7_issuer_and_serial_st(Structure): - pass -pkcs7_issuer_and_serial_st._fields_ = [ - ('issuer', POINTER(X509_NAME)), - ('serial', POINTER(ASN1_INTEGER)), -] -assert sizeof(pkcs7_issuer_and_serial_st) == 8, sizeof(pkcs7_issuer_and_serial_st) -assert alignment(pkcs7_issuer_and_serial_st) == 4, alignment(pkcs7_issuer_and_serial_st) -PKCS7_ISSUER_AND_SERIAL = pkcs7_issuer_and_serial_st -class pkcs7_signer_info_st(Structure): - pass -pkcs7_signer_info_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('issuer_and_serial', POINTER(PKCS7_ISSUER_AND_SERIAL)), - ('digest_alg', POINTER(X509_ALGOR)), - ('auth_attr', POINTER(STACK)), - ('digest_enc_alg', POINTER(X509_ALGOR)), - ('enc_digest', POINTER(ASN1_OCTET_STRING)), - ('unauth_attr', POINTER(STACK)), - ('pkey', POINTER(EVP_PKEY)), -] -assert sizeof(pkcs7_signer_info_st) == 32, sizeof(pkcs7_signer_info_st) -assert alignment(pkcs7_signer_info_st) == 4, alignment(pkcs7_signer_info_st) -PKCS7_SIGNER_INFO = pkcs7_signer_info_st -class pkcs7_recip_info_st(Structure): - pass -pkcs7_recip_info_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('issuer_and_serial', POINTER(PKCS7_ISSUER_AND_SERIAL)), - ('key_enc_algor', POINTER(X509_ALGOR)), - ('enc_key', POINTER(ASN1_OCTET_STRING)), - ('cert', POINTER(X509)), -] -assert sizeof(pkcs7_recip_info_st) == 20, sizeof(pkcs7_recip_info_st) -assert alignment(pkcs7_recip_info_st) == 4, alignment(pkcs7_recip_info_st) -PKCS7_RECIP_INFO = pkcs7_recip_info_st -class pkcs7_signed_st(Structure): - pass -class pkcs7_st(Structure): - pass -pkcs7_signed_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('md_algs', POINTER(STACK)), - ('cert', POINTER(STACK)), - ('crl', POINTER(STACK)), - ('signer_info', POINTER(STACK)), - ('contents', POINTER(pkcs7_st)), -] -assert sizeof(pkcs7_signed_st) == 24, sizeof(pkcs7_signed_st) -assert alignment(pkcs7_signed_st) == 4, alignment(pkcs7_signed_st) -PKCS7_SIGNED = pkcs7_signed_st -class pkcs7_enc_content_st(Structure): - pass -pkcs7_enc_content_st._fields_ = [ - ('content_type', POINTER(ASN1_OBJECT)), - ('algorithm', POINTER(X509_ALGOR)), - ('enc_data', POINTER(ASN1_OCTET_STRING)), - ('cipher', POINTER(EVP_CIPHER)), -] -assert sizeof(pkcs7_enc_content_st) == 16, sizeof(pkcs7_enc_content_st) -assert alignment(pkcs7_enc_content_st) == 4, alignment(pkcs7_enc_content_st) -PKCS7_ENC_CONTENT = pkcs7_enc_content_st -class pkcs7_enveloped_st(Structure): - pass -pkcs7_enveloped_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('recipientinfo', POINTER(STACK)), - ('enc_data', POINTER(PKCS7_ENC_CONTENT)), -] -assert sizeof(pkcs7_enveloped_st) == 12, sizeof(pkcs7_enveloped_st) -assert alignment(pkcs7_enveloped_st) == 4, alignment(pkcs7_enveloped_st) -PKCS7_ENVELOPE = pkcs7_enveloped_st -class pkcs7_signedandenveloped_st(Structure): - pass -pkcs7_signedandenveloped_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('md_algs', POINTER(STACK)), - ('cert', POINTER(STACK)), - ('crl', POINTER(STACK)), - ('signer_info', POINTER(STACK)), - ('enc_data', POINTER(PKCS7_ENC_CONTENT)), - ('recipientinfo', POINTER(STACK)), -] -assert sizeof(pkcs7_signedandenveloped_st) == 28, sizeof(pkcs7_signedandenveloped_st) -assert alignment(pkcs7_signedandenveloped_st) == 4, alignment(pkcs7_signedandenveloped_st) -PKCS7_SIGN_ENVELOPE = pkcs7_signedandenveloped_st -class pkcs7_digest_st(Structure): - pass -pkcs7_digest_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('md', POINTER(X509_ALGOR)), - ('contents', POINTER(pkcs7_st)), - ('digest', POINTER(ASN1_OCTET_STRING)), -] -assert sizeof(pkcs7_digest_st) == 16, sizeof(pkcs7_digest_st) -assert alignment(pkcs7_digest_st) == 4, alignment(pkcs7_digest_st) -PKCS7_DIGEST = pkcs7_digest_st -class pkcs7_encrypted_st(Structure): - pass -pkcs7_encrypted_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('enc_data', POINTER(PKCS7_ENC_CONTENT)), -] -assert sizeof(pkcs7_encrypted_st) == 8, sizeof(pkcs7_encrypted_st) -assert alignment(pkcs7_encrypted_st) == 4, alignment(pkcs7_encrypted_st) -PKCS7_ENCRYPT = pkcs7_encrypted_st -class N8pkcs7_st4DOLLAR_15E(Union): - pass -N8pkcs7_st4DOLLAR_15E._fields_ = [ - ('ptr', STRING), - ('data', POINTER(ASN1_OCTET_STRING)), - ('sign', POINTER(PKCS7_SIGNED)), - ('enveloped', POINTER(PKCS7_ENVELOPE)), - ('signed_and_enveloped', POINTER(PKCS7_SIGN_ENVELOPE)), - ('digest', POINTER(PKCS7_DIGEST)), - ('encrypted', POINTER(PKCS7_ENCRYPT)), - ('other', POINTER(ASN1_TYPE)), -] -assert sizeof(N8pkcs7_st4DOLLAR_15E) == 4, sizeof(N8pkcs7_st4DOLLAR_15E) -assert alignment(N8pkcs7_st4DOLLAR_15E) == 4, alignment(N8pkcs7_st4DOLLAR_15E) -pkcs7_st._fields_ = [ - ('asn1', POINTER(c_ubyte)), - ('length', c_long), - ('state', c_int), - ('detached', c_int), - ('type', POINTER(ASN1_OBJECT)), - ('d', N8pkcs7_st4DOLLAR_15E), -] -assert sizeof(pkcs7_st) == 24, sizeof(pkcs7_st) -assert alignment(pkcs7_st) == 4, alignment(pkcs7_st) -PKCS7 = pkcs7_st -class rc2_key_st(Structure): - pass -rc2_key_st._fields_ = [ - ('data', c_uint * 64), -] -assert sizeof(rc2_key_st) == 256, sizeof(rc2_key_st) -assert alignment(rc2_key_st) == 4, alignment(rc2_key_st) -RC2_KEY = rc2_key_st -class rc4_key_st(Structure): - pass -rc4_key_st._fields_ = [ - ('x', c_ubyte), - ('y', c_ubyte), - ('data', c_ubyte * 256), -] -assert sizeof(rc4_key_st) == 258, sizeof(rc4_key_st) -assert alignment(rc4_key_st) == 1, alignment(rc4_key_st) -RC4_KEY = rc4_key_st -class rc5_key_st(Structure): - pass -rc5_key_st._fields_ = [ - ('rounds', c_int), - ('data', c_ulong * 34), -] -assert sizeof(rc5_key_st) == 140, sizeof(rc5_key_st) -assert alignment(rc5_key_st) == 4, alignment(rc5_key_st) -RC5_32_KEY = rc5_key_st -class RIPEMD160state_st(Structure): - pass -RIPEMD160state_st._fields_ = [ - ('A', c_uint), - ('B', c_uint), - ('C', c_uint), - ('D', c_uint), - ('E', c_uint), - ('Nl', c_uint), - ('Nh', c_uint), - ('data', c_uint * 16), - ('num', c_int), -] -assert sizeof(RIPEMD160state_st) == 96, sizeof(RIPEMD160state_st) -assert alignment(RIPEMD160state_st) == 4, alignment(RIPEMD160state_st) -RIPEMD160_CTX = RIPEMD160state_st -RSA = rsa_st -class rsa_meth_st(Structure): - pass -rsa_meth_st._fields_ = [ - ('name', STRING), - ('rsa_pub_enc', CFUNCTYPE(c_int, c_int, POINTER(c_ubyte), POINTER(c_ubyte), POINTER(RSA), c_int)), - ('rsa_pub_dec', CFUNCTYPE(c_int, c_int, POINTER(c_ubyte), POINTER(c_ubyte), POINTER(RSA), c_int)), - ('rsa_priv_enc', CFUNCTYPE(c_int, c_int, POINTER(c_ubyte), POINTER(c_ubyte), POINTER(RSA), c_int)), - ('rsa_priv_dec', CFUNCTYPE(c_int, c_int, POINTER(c_ubyte), POINTER(c_ubyte), POINTER(RSA), c_int)), - ('rsa_mod_exp', CFUNCTYPE(c_int, POINTER(BIGNUM), POINTER(BIGNUM), POINTER(RSA))), - ('bn_mod_exp', CFUNCTYPE(c_int, POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BIGNUM), POINTER(BN_CTX), POINTER(BN_MONT_CTX))), - ('init', CFUNCTYPE(c_int, POINTER(RSA))), - ('finish', CFUNCTYPE(c_int, POINTER(RSA))), - ('flags', c_int), - ('app_data', STRING), - ('rsa_sign', CFUNCTYPE(c_int, c_int, POINTER(c_ubyte), c_uint, POINTER(c_ubyte), POINTER(c_uint), POINTER(RSA))), - ('rsa_verify', CFUNCTYPE(c_int, c_int, POINTER(c_ubyte), c_uint, POINTER(c_ubyte), c_uint, POINTER(RSA))), -] -assert sizeof(rsa_meth_st) == 52, sizeof(rsa_meth_st) -assert alignment(rsa_meth_st) == 4, alignment(rsa_meth_st) -RSA_METHOD = rsa_meth_st -rsa_st._fields_ = [ - ('pad', c_int), - ('version', c_long), - ('meth', POINTER(RSA_METHOD)), - ('engine', POINTER(ENGINE)), - ('n', POINTER(BIGNUM)), - ('e', POINTER(BIGNUM)), - ('d', POINTER(BIGNUM)), - ('p', POINTER(BIGNUM)), - ('q', POINTER(BIGNUM)), - ('dmp1', POINTER(BIGNUM)), - ('dmq1', POINTER(BIGNUM)), - ('iqmp', POINTER(BIGNUM)), - ('ex_data', CRYPTO_EX_DATA), - ('references', c_int), - ('flags', c_int), - ('_method_mod_n', POINTER(BN_MONT_CTX)), - ('_method_mod_p', POINTER(BN_MONT_CTX)), - ('_method_mod_q', POINTER(BN_MONT_CTX)), - ('bignum_data', STRING), - ('blinding', POINTER(BN_BLINDING)), -] -assert sizeof(rsa_st) == 84, sizeof(rsa_st) -assert alignment(rsa_st) == 4, alignment(rsa_st) -openssl_fptr = CFUNCTYPE(None) -class SHAstate_st(Structure): - pass -SHAstate_st._fields_ = [ - ('h0', c_uint), - ('h1', c_uint), - ('h2', c_uint), - ('h3', c_uint), - ('h4', c_uint), - ('Nl', c_uint), - ('Nh', c_uint), - ('data', c_uint * 16), - ('num', c_int), -] -assert sizeof(SHAstate_st) == 96, sizeof(SHAstate_st) -assert alignment(SHAstate_st) == 4, alignment(SHAstate_st) -SHA_CTX = SHAstate_st -class ssl_st(Structure): - pass -ssl_crock_st = POINTER(ssl_st) -class ssl_cipher_st(Structure): - pass -ssl_cipher_st._fields_ = [ - ('valid', c_int), - ('name', STRING), - ('id', c_ulong), - ('algorithms', c_ulong), - ('algo_strength', c_ulong), - ('algorithm2', c_ulong), - ('strength_bits', c_int), - ('alg_bits', c_int), - ('mask', c_ulong), - ('mask_strength', c_ulong), -] -assert sizeof(ssl_cipher_st) == 40, sizeof(ssl_cipher_st) -assert alignment(ssl_cipher_st) == 4, alignment(ssl_cipher_st) -SSL_CIPHER = ssl_cipher_st -SSL = ssl_st -class ssl_ctx_st(Structure): - pass -SSL_CTX = ssl_ctx_st -class ssl_method_st(Structure): - pass -class ssl3_enc_method(Structure): - pass -ssl_method_st._fields_ = [ - ('version', c_int), - ('ssl_new', CFUNCTYPE(c_int, POINTER(SSL))), - ('ssl_clear', CFUNCTYPE(None, POINTER(SSL))), - ('ssl_free', CFUNCTYPE(None, POINTER(SSL))), - ('ssl_accept', CFUNCTYPE(c_int, POINTER(SSL))), - ('ssl_connect', CFUNCTYPE(c_int, POINTER(SSL))), - ('ssl_read', CFUNCTYPE(c_int, POINTER(SSL), c_void_p, c_int)), - ('ssl_peek', CFUNCTYPE(c_int, POINTER(SSL), c_void_p, c_int)), - ('ssl_write', CFUNCTYPE(c_int, POINTER(SSL), c_void_p, c_int)), - ('ssl_shutdown', CFUNCTYPE(c_int, POINTER(SSL))), - ('ssl_renegotiate', CFUNCTYPE(c_int, POINTER(SSL))), - ('ssl_renegotiate_check', CFUNCTYPE(c_int, POINTER(SSL))), - ('ssl_ctrl', CFUNCTYPE(c_long, POINTER(SSL), c_int, c_long, c_void_p)), - ('ssl_ctx_ctrl', CFUNCTYPE(c_long, POINTER(SSL_CTX), c_int, c_long, c_void_p)), - ('get_cipher_by_char', CFUNCTYPE(POINTER(SSL_CIPHER), POINTER(c_ubyte))), - ('put_cipher_by_char', CFUNCTYPE(c_int, POINTER(SSL_CIPHER), POINTER(c_ubyte))), - ('ssl_pending', CFUNCTYPE(c_int, POINTER(SSL))), - ('num_ciphers', CFUNCTYPE(c_int)), - ('get_cipher', CFUNCTYPE(POINTER(SSL_CIPHER), c_uint)), - ('get_ssl_method', CFUNCTYPE(POINTER(ssl_method_st), c_int)), - ('get_timeout', CFUNCTYPE(c_long)), - ('ssl3_enc', POINTER(ssl3_enc_method)), - ('ssl_version', CFUNCTYPE(c_int)), - ('ssl_callback_ctrl', CFUNCTYPE(c_long, POINTER(SSL), c_int, CFUNCTYPE(None))), - ('ssl_ctx_callback_ctrl', CFUNCTYPE(c_long, POINTER(SSL_CTX), c_int, CFUNCTYPE(None))), -] -assert sizeof(ssl_method_st) == 100, sizeof(ssl_method_st) -assert alignment(ssl_method_st) == 4, alignment(ssl_method_st) -ssl3_enc_method._fields_ = [ -] -SSL_METHOD = ssl_method_st -class ssl_session_st(Structure): - pass -class sess_cert_st(Structure): - pass -ssl_session_st._fields_ = [ - ('ssl_version', c_int), - ('key_arg_length', c_uint), - ('key_arg', c_ubyte * 8), - ('master_key_length', c_int), - ('master_key', c_ubyte * 48), - ('session_id_length', c_uint), - ('session_id', c_ubyte * 32), - ('sid_ctx_length', c_uint), - ('sid_ctx', c_ubyte * 32), - ('not_resumable', c_int), - ('sess_cert', POINTER(sess_cert_st)), - ('peer', POINTER(X509)), - ('verify_result', c_long), - ('references', c_int), - ('timeout', c_long), - ('time', c_long), - ('compress_meth', c_int), - ('cipher', POINTER(SSL_CIPHER)), - ('cipher_id', c_ulong), - ('ciphers', POINTER(STACK)), - ('ex_data', CRYPTO_EX_DATA), - ('prev', POINTER(ssl_session_st)), - ('next', POINTER(ssl_session_st)), -] -assert sizeof(ssl_session_st) == 200, sizeof(ssl_session_st) -assert alignment(ssl_session_st) == 4, alignment(ssl_session_st) -sess_cert_st._fields_ = [ -] -SSL_SESSION = ssl_session_st -GEN_SESSION_CB = CFUNCTYPE(c_int, POINTER(SSL), POINTER(c_ubyte), POINTER(c_uint)) -class ssl_comp_st(Structure): - pass -ssl_comp_st._fields_ = [ - ('id', c_int), - ('name', STRING), - ('method', POINTER(COMP_METHOD)), -] -assert sizeof(ssl_comp_st) == 12, sizeof(ssl_comp_st) -assert alignment(ssl_comp_st) == 4, alignment(ssl_comp_st) -SSL_COMP = ssl_comp_st -class N10ssl_ctx_st4DOLLAR_18E(Structure): - pass -N10ssl_ctx_st4DOLLAR_18E._fields_ = [ - ('sess_connect', c_int), - ('sess_connect_renegotiate', c_int), - ('sess_connect_good', c_int), - ('sess_accept', c_int), - ('sess_accept_renegotiate', c_int), - ('sess_accept_good', c_int), - ('sess_miss', c_int), - ('sess_timeout', c_int), - ('sess_cache_full', c_int), - ('sess_hit', c_int), - ('sess_cb_hit', c_int), -] -assert sizeof(N10ssl_ctx_st4DOLLAR_18E) == 44, sizeof(N10ssl_ctx_st4DOLLAR_18E) -assert alignment(N10ssl_ctx_st4DOLLAR_18E) == 4, alignment(N10ssl_ctx_st4DOLLAR_18E) -class cert_st(Structure): - pass -ssl_ctx_st._fields_ = [ - ('method', POINTER(SSL_METHOD)), - ('cipher_list', POINTER(STACK)), - ('cipher_list_by_id', POINTER(STACK)), - ('cert_store', POINTER(x509_store_st)), - ('sessions', POINTER(lhash_st)), - ('session_cache_size', c_ulong), - ('session_cache_head', POINTER(ssl_session_st)), - ('session_cache_tail', POINTER(ssl_session_st)), - ('session_cache_mode', c_int), - ('session_timeout', c_long), - ('new_session_cb', CFUNCTYPE(c_int, POINTER(ssl_st), POINTER(SSL_SESSION))), - ('remove_session_cb', CFUNCTYPE(None, POINTER(ssl_ctx_st), POINTER(SSL_SESSION))), - ('get_session_cb', CFUNCTYPE(POINTER(SSL_SESSION), POINTER(ssl_st), POINTER(c_ubyte), c_int, POINTER(c_int))), - ('stats', N10ssl_ctx_st4DOLLAR_18E), - ('references', c_int), - ('app_verify_callback', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), c_void_p)), - ('app_verify_arg', c_void_p), - ('default_passwd_callback', POINTER(pem_password_cb)), - ('default_passwd_callback_userdata', c_void_p), - ('client_cert_cb', CFUNCTYPE(c_int, POINTER(SSL), POINTER(POINTER(X509)), POINTER(POINTER(EVP_PKEY)))), - ('ex_data', CRYPTO_EX_DATA), - ('rsa_md5', POINTER(EVP_MD)), - ('md5', POINTER(EVP_MD)), - ('sha1', POINTER(EVP_MD)), - ('extra_certs', POINTER(STACK)), - ('comp_methods', POINTER(STACK)), - ('info_callback', CFUNCTYPE(None, POINTER(SSL), c_int, c_int)), - ('client_CA', POINTER(STACK)), - ('options', c_ulong), - ('mode', c_ulong), - ('max_cert_list', c_long), - ('cert', POINTER(cert_st)), - ('read_ahead', c_int), - ('msg_callback', CFUNCTYPE(None, c_int, c_int, c_int, c_void_p, c_ulong, POINTER(SSL), c_void_p)), - ('msg_callback_arg', c_void_p), - ('verify_mode', c_int), - ('verify_depth', c_int), - ('sid_ctx_length', c_uint), - ('sid_ctx', c_ubyte * 32), - ('default_verify_callback', CFUNCTYPE(c_int, c_int, POINTER(X509_STORE_CTX))), - ('generate_session_id', GEN_SESSION_CB), - ('purpose', c_int), - ('trust', c_int), - ('quiet_shutdown', c_int), -] -assert sizeof(ssl_ctx_st) == 248, sizeof(ssl_ctx_st) -assert alignment(ssl_ctx_st) == 4, alignment(ssl_ctx_st) -cert_st._fields_ = [ -] -class ssl2_state_st(Structure): - pass -class ssl3_state_st(Structure): - pass -ssl_st._fields_ = [ - ('version', c_int), - ('type', c_int), - ('method', POINTER(SSL_METHOD)), - ('rbio', POINTER(BIO)), - ('wbio', POINTER(BIO)), - ('bbio', POINTER(BIO)), - ('rwstate', c_int), - ('in_handshake', c_int), - ('handshake_func', CFUNCTYPE(c_int)), - ('server', c_int), - ('new_session', c_int), - ('quiet_shutdown', c_int), - ('shutdown', c_int), - ('state', c_int), - ('rstate', c_int), - ('init_buf', POINTER(BUF_MEM)), - ('init_msg', c_void_p), - ('init_num', c_int), - ('init_off', c_int), - ('packet', POINTER(c_ubyte)), - ('packet_length', c_uint), - ('s2', POINTER(ssl2_state_st)), - ('s3', POINTER(ssl3_state_st)), - ('read_ahead', c_int), - ('msg_callback', CFUNCTYPE(None, c_int, c_int, c_int, c_void_p, c_ulong, POINTER(SSL), c_void_p)), - ('msg_callback_arg', c_void_p), - ('hit', c_int), - ('purpose', c_int), - ('trust', c_int), - ('cipher_list', POINTER(STACK)), - ('cipher_list_by_id', POINTER(STACK)), - ('enc_read_ctx', POINTER(EVP_CIPHER_CTX)), - ('read_hash', POINTER(EVP_MD)), - ('expand', POINTER(COMP_CTX)), - ('enc_write_ctx', POINTER(EVP_CIPHER_CTX)), - ('write_hash', POINTER(EVP_MD)), - ('compress', POINTER(COMP_CTX)), - ('cert', POINTER(cert_st)), - ('sid_ctx_length', c_uint), - ('sid_ctx', c_ubyte * 32), - ('session', POINTER(SSL_SESSION)), - ('generate_session_id', GEN_SESSION_CB), - ('verify_mode', c_int), - ('verify_depth', c_int), - ('verify_callback', CFUNCTYPE(c_int, c_int, POINTER(X509_STORE_CTX))), - ('info_callback', CFUNCTYPE(None, POINTER(SSL), c_int, c_int)), - ('error', c_int), - ('error_code', c_int), - ('ctx', POINTER(SSL_CTX)), - ('debug', c_int), - ('verify_result', c_long), - ('ex_data', CRYPTO_EX_DATA), - ('client_CA', POINTER(STACK)), - ('references', c_int), - ('options', c_ulong), - ('mode', c_ulong), - ('max_cert_list', c_long), - ('first_packet', c_int), - ('client_version', c_int), -] -assert sizeof(ssl_st) == 268, sizeof(ssl_st) -assert alignment(ssl_st) == 4, alignment(ssl_st) -class N13ssl2_state_st4DOLLAR_19E(Structure): - pass -N13ssl2_state_st4DOLLAR_19E._fields_ = [ - ('conn_id_length', c_uint), - ('cert_type', c_uint), - ('cert_length', c_uint), - ('csl', c_uint), - ('clear', c_uint), - ('enc', c_uint), - ('ccl', c_ubyte * 32), - ('cipher_spec_length', c_uint), - ('session_id_length', c_uint), - ('clen', c_uint), - ('rlen', c_uint), -] -assert sizeof(N13ssl2_state_st4DOLLAR_19E) == 72, sizeof(N13ssl2_state_st4DOLLAR_19E) -assert alignment(N13ssl2_state_st4DOLLAR_19E) == 4, alignment(N13ssl2_state_st4DOLLAR_19E) -ssl2_state_st._fields_ = [ - ('three_byte_header', c_int), - ('clear_text', c_int), - ('escape', c_int), - ('ssl2_rollback', c_int), - ('wnum', c_uint), - ('wpend_tot', c_int), - ('wpend_buf', POINTER(c_ubyte)), - ('wpend_off', c_int), - ('wpend_len', c_int), - ('wpend_ret', c_int), - ('rbuf_left', c_int), - ('rbuf_offs', c_int), - ('rbuf', POINTER(c_ubyte)), - ('wbuf', POINTER(c_ubyte)), - ('write_ptr', POINTER(c_ubyte)), - ('padding', c_uint), - ('rlength', c_uint), - ('ract_data_length', c_int), - ('wlength', c_uint), - ('wact_data_length', c_int), - ('ract_data', POINTER(c_ubyte)), - ('wact_data', POINTER(c_ubyte)), - ('mac_data', POINTER(c_ubyte)), - ('read_key', POINTER(c_ubyte)), - ('write_key', POINTER(c_ubyte)), - ('challenge_length', c_uint), - ('challenge', c_ubyte * 32), - ('conn_id_length', c_uint), - ('conn_id', c_ubyte * 16), - ('key_material_length', c_uint), - ('key_material', c_ubyte * 48), - ('read_sequence', c_ulong), - ('write_sequence', c_ulong), - ('tmp', N13ssl2_state_st4DOLLAR_19E), -] -assert sizeof(ssl2_state_st) == 288, sizeof(ssl2_state_st) -assert alignment(ssl2_state_st) == 4, alignment(ssl2_state_st) -SSL2_STATE = ssl2_state_st -class ssl3_record_st(Structure): - pass -ssl3_record_st._fields_ = [ - ('type', c_int), - ('length', c_uint), - ('off', c_uint), - ('data', POINTER(c_ubyte)), - ('input', POINTER(c_ubyte)), - ('comp', POINTER(c_ubyte)), -] -assert sizeof(ssl3_record_st) == 24, sizeof(ssl3_record_st) -assert alignment(ssl3_record_st) == 4, alignment(ssl3_record_st) -SSL3_RECORD = ssl3_record_st -class ssl3_buffer_st(Structure): - pass -size_t = __darwin_size_t -ssl3_buffer_st._fields_ = [ - ('buf', POINTER(c_ubyte)), - ('len', size_t), - ('offset', c_int), - ('left', c_int), -] -assert sizeof(ssl3_buffer_st) == 16, sizeof(ssl3_buffer_st) -assert alignment(ssl3_buffer_st) == 4, alignment(ssl3_buffer_st) -SSL3_BUFFER = ssl3_buffer_st -class N13ssl3_state_st4DOLLAR_20E(Structure): - pass -N13ssl3_state_st4DOLLAR_20E._fields_ = [ - ('cert_verify_md', c_ubyte * 72), - ('finish_md', c_ubyte * 72), - ('finish_md_len', c_int), - ('peer_finish_md', c_ubyte * 72), - ('peer_finish_md_len', c_int), - ('message_size', c_ulong), - ('message_type', c_int), - ('new_cipher', POINTER(SSL_CIPHER)), - ('dh', POINTER(DH)), - ('next_state', c_int), - ('reuse_message', c_int), - ('cert_req', c_int), - ('ctype_num', c_int), - ('ctype', c_char * 7), - ('ca_names', POINTER(STACK)), - ('use_rsa_tmp', c_int), - ('key_block_length', c_int), - ('key_block', POINTER(c_ubyte)), - ('new_sym_enc', POINTER(EVP_CIPHER)), - ('new_hash', POINTER(EVP_MD)), - ('new_compression', POINTER(SSL_COMP)), - ('cert_request', c_int), -] -assert sizeof(N13ssl3_state_st4DOLLAR_20E) == 296, sizeof(N13ssl3_state_st4DOLLAR_20E) -assert alignment(N13ssl3_state_st4DOLLAR_20E) == 4, alignment(N13ssl3_state_st4DOLLAR_20E) -ssl3_state_st._fields_ = [ - ('flags', c_long), - ('delay_buf_pop_ret', c_int), - ('read_sequence', c_ubyte * 8), - ('read_mac_secret', c_ubyte * 36), - ('write_sequence', c_ubyte * 8), - ('write_mac_secret', c_ubyte * 36), - ('server_random', c_ubyte * 32), - ('client_random', c_ubyte * 32), - ('need_empty_fragments', c_int), - ('empty_fragment_done', c_int), - ('rbuf', SSL3_BUFFER), - ('wbuf', SSL3_BUFFER), - ('rrec', SSL3_RECORD), - ('wrec', SSL3_RECORD), - ('alert_fragment', c_ubyte * 2), - ('alert_fragment_len', c_uint), - ('handshake_fragment', c_ubyte * 4), - ('handshake_fragment_len', c_uint), - ('wnum', c_uint), - ('wpend_tot', c_int), - ('wpend_type', c_int), - ('wpend_ret', c_int), - ('wpend_buf', POINTER(c_ubyte)), - ('finish_dgst1', EVP_MD_CTX), - ('finish_dgst2', EVP_MD_CTX), - ('change_cipher_spec', c_int), - ('warn_alert', c_int), - ('fatal_alert', c_int), - ('alert_dispatch', c_int), - ('send_alert', c_ubyte * 2), - ('renegotiate', c_int), - ('total_renegotiations', c_int), - ('num_renegotiations', c_int), - ('in_read_app_data', c_int), - ('tmp', N13ssl3_state_st4DOLLAR_20E), -] -assert sizeof(ssl3_state_st) == 648, sizeof(ssl3_state_st) -assert alignment(ssl3_state_st) == 4, alignment(ssl3_state_st) -SSL3_STATE = ssl3_state_st -stack_st._fields_ = [ - ('num', c_int), - ('data', POINTER(STRING)), - ('sorted', c_int), - ('num_alloc', c_int), - ('comp', CFUNCTYPE(c_int, POINTER(STRING), POINTER(STRING))), -] -assert sizeof(stack_st) == 20, sizeof(stack_st) -assert alignment(stack_st) == 4, alignment(stack_st) -class ui_st(Structure): - pass -ui_st._fields_ = [ -] -UI = ui_st -class ui_method_st(Structure): - pass -ui_method_st._fields_ = [ -] -UI_METHOD = ui_method_st -class ui_string_st(Structure): - pass -ui_string_st._fields_ = [ -] -UI_STRING = ui_string_st - -# values for enumeration 'UI_string_types' -UI_string_types = c_int # enum -class X509_objects_st(Structure): - pass -X509_objects_st._fields_ = [ - ('nid', c_int), - ('a2i', CFUNCTYPE(c_int)), - ('i2a', CFUNCTYPE(c_int)), -] -assert sizeof(X509_objects_st) == 12, sizeof(X509_objects_st) -assert alignment(X509_objects_st) == 4, alignment(X509_objects_st) -X509_OBJECTS = X509_objects_st -X509_algor_st._fields_ = [ - ('algorithm', POINTER(ASN1_OBJECT)), - ('parameter', POINTER(ASN1_TYPE)), -] -assert sizeof(X509_algor_st) == 8, sizeof(X509_algor_st) -assert alignment(X509_algor_st) == 4, alignment(X509_algor_st) -class X509_val_st(Structure): - pass -X509_val_st._fields_ = [ - ('notBefore', POINTER(ASN1_TIME)), - ('notAfter', POINTER(ASN1_TIME)), -] -assert sizeof(X509_val_st) == 8, sizeof(X509_val_st) -assert alignment(X509_val_st) == 4, alignment(X509_val_st) -X509_VAL = X509_val_st -class X509_pubkey_st(Structure): - pass -X509_pubkey_st._fields_ = [ - ('algor', POINTER(X509_ALGOR)), - ('public_key', POINTER(ASN1_BIT_STRING)), - ('pkey', POINTER(EVP_PKEY)), -] -assert sizeof(X509_pubkey_st) == 12, sizeof(X509_pubkey_st) -assert alignment(X509_pubkey_st) == 4, alignment(X509_pubkey_st) -X509_PUBKEY = X509_pubkey_st -class X509_sig_st(Structure): - pass -X509_sig_st._fields_ = [ - ('algor', POINTER(X509_ALGOR)), - ('digest', POINTER(ASN1_OCTET_STRING)), -] -assert sizeof(X509_sig_st) == 8, sizeof(X509_sig_st) -assert alignment(X509_sig_st) == 4, alignment(X509_sig_st) -X509_SIG = X509_sig_st -class X509_name_entry_st(Structure): - pass -X509_name_entry_st._fields_ = [ - ('object', POINTER(ASN1_OBJECT)), - ('value', POINTER(ASN1_STRING)), - ('set', c_int), - ('size', c_int), -] -assert sizeof(X509_name_entry_st) == 16, sizeof(X509_name_entry_st) -assert alignment(X509_name_entry_st) == 4, alignment(X509_name_entry_st) -X509_NAME_ENTRY = X509_name_entry_st -X509_name_st._fields_ = [ - ('entries', POINTER(STACK)), - ('modified', c_int), - ('bytes', POINTER(BUF_MEM)), - ('hash', c_ulong), -] -assert sizeof(X509_name_st) == 16, sizeof(X509_name_st) -assert alignment(X509_name_st) == 4, alignment(X509_name_st) -class X509_extension_st(Structure): - pass -X509_extension_st._fields_ = [ - ('object', POINTER(ASN1_OBJECT)), - ('critical', ASN1_BOOLEAN), - ('value', POINTER(ASN1_OCTET_STRING)), -] -assert sizeof(X509_extension_st) == 12, sizeof(X509_extension_st) -assert alignment(X509_extension_st) == 4, alignment(X509_extension_st) -X509_EXTENSION = X509_extension_st -class x509_attributes_st(Structure): - pass -class N18x509_attributes_st4DOLLAR_13E(Union): - pass -N18x509_attributes_st4DOLLAR_13E._fields_ = [ - ('ptr', STRING), - ('set', POINTER(STACK)), - ('single', POINTER(ASN1_TYPE)), -] -assert sizeof(N18x509_attributes_st4DOLLAR_13E) == 4, sizeof(N18x509_attributes_st4DOLLAR_13E) -assert alignment(N18x509_attributes_st4DOLLAR_13E) == 4, alignment(N18x509_attributes_st4DOLLAR_13E) -x509_attributes_st._fields_ = [ - ('object', POINTER(ASN1_OBJECT)), - ('single', c_int), - ('value', N18x509_attributes_st4DOLLAR_13E), -] -assert sizeof(x509_attributes_st) == 12, sizeof(x509_attributes_st) -assert alignment(x509_attributes_st) == 4, alignment(x509_attributes_st) -X509_ATTRIBUTE = x509_attributes_st -class X509_req_info_st(Structure): - pass -X509_req_info_st._fields_ = [ - ('enc', ASN1_ENCODING), - ('version', POINTER(ASN1_INTEGER)), - ('subject', POINTER(X509_NAME)), - ('pubkey', POINTER(X509_PUBKEY)), - ('attributes', POINTER(STACK)), -] -assert sizeof(X509_req_info_st) == 28, sizeof(X509_req_info_st) -assert alignment(X509_req_info_st) == 4, alignment(X509_req_info_st) -X509_REQ_INFO = X509_req_info_st -class X509_req_st(Structure): - pass -X509_req_st._fields_ = [ - ('req_info', POINTER(X509_REQ_INFO)), - ('sig_alg', POINTER(X509_ALGOR)), - ('signature', POINTER(ASN1_BIT_STRING)), - ('references', c_int), -] -assert sizeof(X509_req_st) == 16, sizeof(X509_req_st) -assert alignment(X509_req_st) == 4, alignment(X509_req_st) -X509_REQ = X509_req_st -class x509_cinf_st(Structure): - pass -x509_cinf_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('serialNumber', POINTER(ASN1_INTEGER)), - ('signature', POINTER(X509_ALGOR)), - ('issuer', POINTER(X509_NAME)), - ('validity', POINTER(X509_VAL)), - ('subject', POINTER(X509_NAME)), - ('key', POINTER(X509_PUBKEY)), - ('issuerUID', POINTER(ASN1_BIT_STRING)), - ('subjectUID', POINTER(ASN1_BIT_STRING)), - ('extensions', POINTER(STACK)), -] -assert sizeof(x509_cinf_st) == 40, sizeof(x509_cinf_st) -assert alignment(x509_cinf_st) == 4, alignment(x509_cinf_st) -X509_CINF = x509_cinf_st -class x509_cert_aux_st(Structure): - pass -x509_cert_aux_st._fields_ = [ - ('trust', POINTER(STACK)), - ('reject', POINTER(STACK)), - ('alias', POINTER(ASN1_UTF8STRING)), - ('keyid', POINTER(ASN1_OCTET_STRING)), - ('other', POINTER(STACK)), -] -assert sizeof(x509_cert_aux_st) == 20, sizeof(x509_cert_aux_st) -assert alignment(x509_cert_aux_st) == 4, alignment(x509_cert_aux_st) -X509_CERT_AUX = x509_cert_aux_st -class AUTHORITY_KEYID_st(Structure): - pass -x509_st._fields_ = [ - ('cert_info', POINTER(X509_CINF)), - ('sig_alg', POINTER(X509_ALGOR)), - ('signature', POINTER(ASN1_BIT_STRING)), - ('valid', c_int), - ('references', c_int), - ('name', STRING), - ('ex_data', CRYPTO_EX_DATA), - ('ex_pathlen', c_long), - ('ex_flags', c_ulong), - ('ex_kusage', c_ulong), - ('ex_xkusage', c_ulong), - ('ex_nscert', c_ulong), - ('skid', POINTER(ASN1_OCTET_STRING)), - ('akid', POINTER(AUTHORITY_KEYID_st)), - ('sha1_hash', c_ubyte * 20), - ('aux', POINTER(X509_CERT_AUX)), -] -assert sizeof(x509_st) == 84, sizeof(x509_st) -assert alignment(x509_st) == 4, alignment(x509_st) -AUTHORITY_KEYID_st._fields_ = [ -] -class x509_trust_st(Structure): - pass -x509_trust_st._fields_ = [ - ('trust', c_int), - ('flags', c_int), - ('check_trust', CFUNCTYPE(c_int, POINTER(x509_trust_st), POINTER(X509), c_int)), - ('name', STRING), - ('arg1', c_int), - ('arg2', c_void_p), -] -assert sizeof(x509_trust_st) == 24, sizeof(x509_trust_st) -assert alignment(x509_trust_st) == 4, alignment(x509_trust_st) -X509_TRUST = x509_trust_st -class X509_revoked_st(Structure): - pass -X509_revoked_st._fields_ = [ - ('serialNumber', POINTER(ASN1_INTEGER)), - ('revocationDate', POINTER(ASN1_TIME)), - ('extensions', POINTER(STACK)), - ('sequence', c_int), -] -assert sizeof(X509_revoked_st) == 16, sizeof(X509_revoked_st) -assert alignment(X509_revoked_st) == 4, alignment(X509_revoked_st) -X509_REVOKED = X509_revoked_st -class X509_crl_info_st(Structure): - pass -X509_crl_info_st._fields_ = [ - ('version', POINTER(ASN1_INTEGER)), - ('sig_alg', POINTER(X509_ALGOR)), - ('issuer', POINTER(X509_NAME)), - ('lastUpdate', POINTER(ASN1_TIME)), - ('nextUpdate', POINTER(ASN1_TIME)), - ('revoked', POINTER(STACK)), - ('extensions', POINTER(STACK)), - ('enc', ASN1_ENCODING), -] -assert sizeof(X509_crl_info_st) == 40, sizeof(X509_crl_info_st) -assert alignment(X509_crl_info_st) == 4, alignment(X509_crl_info_st) -X509_CRL_INFO = X509_crl_info_st -X509_crl_st._fields_ = [ - ('crl', POINTER(X509_CRL_INFO)), - ('sig_alg', POINTER(X509_ALGOR)), - ('signature', POINTER(ASN1_BIT_STRING)), - ('references', c_int), -] -assert sizeof(X509_crl_st) == 16, sizeof(X509_crl_st) -assert alignment(X509_crl_st) == 4, alignment(X509_crl_st) -class private_key_st(Structure): - pass -private_key_st._fields_ = [ - ('version', c_int), - ('enc_algor', POINTER(X509_ALGOR)), - ('enc_pkey', POINTER(ASN1_OCTET_STRING)), - ('dec_pkey', POINTER(EVP_PKEY)), - ('key_length', c_int), - ('key_data', STRING), - ('key_free', c_int), - ('cipher', EVP_CIPHER_INFO), - ('references', c_int), -] -assert sizeof(private_key_st) == 52, sizeof(private_key_st) -assert alignment(private_key_st) == 4, alignment(private_key_st) -X509_PKEY = private_key_st -class X509_info_st(Structure): - pass -X509_info_st._fields_ = [ - ('x509', POINTER(X509)), - ('crl', POINTER(X509_CRL)), - ('x_pkey', POINTER(X509_PKEY)), - ('enc_cipher', EVP_CIPHER_INFO), - ('enc_len', c_int), - ('enc_data', STRING), - ('references', c_int), -] -assert sizeof(X509_info_st) == 44, sizeof(X509_info_st) -assert alignment(X509_info_st) == 4, alignment(X509_info_st) -X509_INFO = X509_info_st -class Netscape_spkac_st(Structure): - pass -Netscape_spkac_st._fields_ = [ - ('pubkey', POINTER(X509_PUBKEY)), - ('challenge', POINTER(ASN1_IA5STRING)), -] -assert sizeof(Netscape_spkac_st) == 8, sizeof(Netscape_spkac_st) -assert alignment(Netscape_spkac_st) == 4, alignment(Netscape_spkac_st) -NETSCAPE_SPKAC = Netscape_spkac_st -class Netscape_spki_st(Structure): - pass -Netscape_spki_st._fields_ = [ - ('spkac', POINTER(NETSCAPE_SPKAC)), - ('sig_algor', POINTER(X509_ALGOR)), - ('signature', POINTER(ASN1_BIT_STRING)), -] -assert sizeof(Netscape_spki_st) == 12, sizeof(Netscape_spki_st) -assert alignment(Netscape_spki_st) == 4, alignment(Netscape_spki_st) -NETSCAPE_SPKI = Netscape_spki_st -class Netscape_certificate_sequence(Structure): - pass -Netscape_certificate_sequence._fields_ = [ - ('type', POINTER(ASN1_OBJECT)), - ('certs', POINTER(STACK)), -] -assert sizeof(Netscape_certificate_sequence) == 8, sizeof(Netscape_certificate_sequence) -assert alignment(Netscape_certificate_sequence) == 4, alignment(Netscape_certificate_sequence) -NETSCAPE_CERT_SEQUENCE = Netscape_certificate_sequence -class PBEPARAM_st(Structure): - pass -PBEPARAM_st._fields_ = [ - ('salt', POINTER(ASN1_OCTET_STRING)), - ('iter', POINTER(ASN1_INTEGER)), -] -assert sizeof(PBEPARAM_st) == 8, sizeof(PBEPARAM_st) -assert alignment(PBEPARAM_st) == 4, alignment(PBEPARAM_st) -PBEPARAM = PBEPARAM_st -class PBE2PARAM_st(Structure): - pass -PBE2PARAM_st._fields_ = [ - ('keyfunc', POINTER(X509_ALGOR)), - ('encryption', POINTER(X509_ALGOR)), -] -assert sizeof(PBE2PARAM_st) == 8, sizeof(PBE2PARAM_st) -assert alignment(PBE2PARAM_st) == 4, alignment(PBE2PARAM_st) -PBE2PARAM = PBE2PARAM_st -class PBKDF2PARAM_st(Structure): - pass -PBKDF2PARAM_st._fields_ = [ - ('salt', POINTER(ASN1_TYPE)), - ('iter', POINTER(ASN1_INTEGER)), - ('keylength', POINTER(ASN1_INTEGER)), - ('prf', POINTER(X509_ALGOR)), -] -assert sizeof(PBKDF2PARAM_st) == 16, sizeof(PBKDF2PARAM_st) -assert alignment(PBKDF2PARAM_st) == 4, alignment(PBKDF2PARAM_st) -PBKDF2PARAM = PBKDF2PARAM_st -class pkcs8_priv_key_info_st(Structure): - pass -pkcs8_priv_key_info_st._fields_ = [ - ('broken', c_int), - ('version', POINTER(ASN1_INTEGER)), - ('pkeyalg', POINTER(X509_ALGOR)), - ('pkey', POINTER(ASN1_TYPE)), - ('attributes', POINTER(STACK)), -] -assert sizeof(pkcs8_priv_key_info_st) == 20, sizeof(pkcs8_priv_key_info_st) -assert alignment(pkcs8_priv_key_info_st) == 4, alignment(pkcs8_priv_key_info_st) -PKCS8_PRIV_KEY_INFO = pkcs8_priv_key_info_st -class x509_hash_dir_st(Structure): - pass -x509_hash_dir_st._fields_ = [ - ('num_dirs', c_int), - ('dirs', POINTER(STRING)), - ('dirs_type', POINTER(c_int)), - ('num_dirs_alloced', c_int), -] -assert sizeof(x509_hash_dir_st) == 16, sizeof(x509_hash_dir_st) -assert alignment(x509_hash_dir_st) == 4, alignment(x509_hash_dir_st) -X509_HASH_DIR_CTX = x509_hash_dir_st -class x509_file_st(Structure): - pass -x509_file_st._fields_ = [ - ('num_paths', c_int), - ('num_alloced', c_int), - ('paths', POINTER(STRING)), - ('path_type', POINTER(c_int)), -] -assert sizeof(x509_file_st) == 16, sizeof(x509_file_st) -assert alignment(x509_file_st) == 4, alignment(x509_file_st) -X509_CERT_FILE_CTX = x509_file_st -class x509_object_st(Structure): - pass -class N14x509_object_st4DOLLAR_14E(Union): - pass -N14x509_object_st4DOLLAR_14E._fields_ = [ - ('ptr', STRING), - ('x509', POINTER(X509)), - ('crl', POINTER(X509_CRL)), - ('pkey', POINTER(EVP_PKEY)), -] -assert sizeof(N14x509_object_st4DOLLAR_14E) == 4, sizeof(N14x509_object_st4DOLLAR_14E) -assert alignment(N14x509_object_st4DOLLAR_14E) == 4, alignment(N14x509_object_st4DOLLAR_14E) -x509_object_st._fields_ = [ - ('type', c_int), - ('data', N14x509_object_st4DOLLAR_14E), -] -assert sizeof(x509_object_st) == 8, sizeof(x509_object_st) -assert alignment(x509_object_st) == 4, alignment(x509_object_st) -X509_OBJECT = x509_object_st -class x509_lookup_st(Structure): - pass -X509_LOOKUP = x509_lookup_st -class x509_lookup_method_st(Structure): - pass -x509_lookup_method_st._fields_ = [ - ('name', STRING), - ('new_item', CFUNCTYPE(c_int, POINTER(X509_LOOKUP))), - ('free', CFUNCTYPE(None, POINTER(X509_LOOKUP))), - ('init', CFUNCTYPE(c_int, POINTER(X509_LOOKUP))), - ('shutdown', CFUNCTYPE(c_int, POINTER(X509_LOOKUP))), - ('ctrl', CFUNCTYPE(c_int, POINTER(X509_LOOKUP), c_int, STRING, c_long, POINTER(STRING))), - ('get_by_subject', CFUNCTYPE(c_int, POINTER(X509_LOOKUP), c_int, POINTER(X509_NAME), POINTER(X509_OBJECT))), - ('get_by_issuer_serial', CFUNCTYPE(c_int, POINTER(X509_LOOKUP), c_int, POINTER(X509_NAME), POINTER(ASN1_INTEGER), POINTER(X509_OBJECT))), - ('get_by_fingerprint', CFUNCTYPE(c_int, POINTER(X509_LOOKUP), c_int, POINTER(c_ubyte), c_int, POINTER(X509_OBJECT))), - ('get_by_alias', CFUNCTYPE(c_int, POINTER(X509_LOOKUP), c_int, STRING, c_int, POINTER(X509_OBJECT))), -] -assert sizeof(x509_lookup_method_st) == 40, sizeof(x509_lookup_method_st) -assert alignment(x509_lookup_method_st) == 4, alignment(x509_lookup_method_st) -X509_LOOKUP_METHOD = x509_lookup_method_st -x509_store_st._fields_ = [ - ('cache', c_int), - ('objs', POINTER(STACK)), - ('get_cert_methods', POINTER(STACK)), - ('flags', c_ulong), - ('purpose', c_int), - ('trust', c_int), - ('verify', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX))), - ('verify_cb', CFUNCTYPE(c_int, c_int, POINTER(X509_STORE_CTX))), - ('get_issuer', CFUNCTYPE(c_int, POINTER(POINTER(X509)), POINTER(X509_STORE_CTX), POINTER(X509))), - ('check_issued', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(X509), POINTER(X509))), - ('check_revocation', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX))), - ('get_crl', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(POINTER(X509_CRL)), POINTER(X509))), - ('check_crl', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(X509_CRL))), - ('cert_crl', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(X509_CRL), POINTER(X509))), - ('cleanup', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX))), - ('ex_data', CRYPTO_EX_DATA), - ('references', c_int), - ('depth', c_int), -] -assert sizeof(x509_store_st) == 76, sizeof(x509_store_st) -assert alignment(x509_store_st) == 4, alignment(x509_store_st) -x509_lookup_st._fields_ = [ - ('init', c_int), - ('skip', c_int), - ('method', POINTER(X509_LOOKUP_METHOD)), - ('method_data', STRING), - ('store_ctx', POINTER(X509_STORE)), -] -assert sizeof(x509_lookup_st) == 20, sizeof(x509_lookup_st) -assert alignment(x509_lookup_st) == 4, alignment(x509_lookup_st) -time_t = __darwin_time_t -x509_store_ctx_st._fields_ = [ - ('ctx', POINTER(X509_STORE)), - ('current_method', c_int), - ('cert', POINTER(X509)), - ('untrusted', POINTER(STACK)), - ('purpose', c_int), - ('trust', c_int), - ('check_time', time_t), - ('flags', c_ulong), - ('other_ctx', c_void_p), - ('verify', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX))), - ('verify_cb', CFUNCTYPE(c_int, c_int, POINTER(X509_STORE_CTX))), - ('get_issuer', CFUNCTYPE(c_int, POINTER(POINTER(X509)), POINTER(X509_STORE_CTX), POINTER(X509))), - ('check_issued', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(X509), POINTER(X509))), - ('check_revocation', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX))), - ('get_crl', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(POINTER(X509_CRL)), POINTER(X509))), - ('check_crl', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(X509_CRL))), - ('cert_crl', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX), POINTER(X509_CRL), POINTER(X509))), - ('cleanup', CFUNCTYPE(c_int, POINTER(X509_STORE_CTX))), - ('depth', c_int), - ('valid', c_int), - ('last_untrusted', c_int), - ('chain', POINTER(STACK)), - ('error_depth', c_int), - ('error', c_int), - ('current_cert', POINTER(X509)), - ('current_issuer', POINTER(X509)), - ('current_crl', POINTER(X509_CRL)), - ('ex_data', CRYPTO_EX_DATA), -] -assert sizeof(x509_store_ctx_st) == 116, sizeof(x509_store_ctx_st) -assert alignment(x509_store_ctx_st) == 4, alignment(x509_store_ctx_st) -va_list = __darwin_va_list -__darwin_off_t = __int64_t -fpos_t = __darwin_off_t -class __sbuf(Structure): - pass -__sbuf._fields_ = [ - ('_base', POINTER(c_ubyte)), - ('_size', c_int), -] -assert sizeof(__sbuf) == 8, sizeof(__sbuf) -assert alignment(__sbuf) == 4, alignment(__sbuf) -class __sFILEX(Structure): - pass -__sFILEX._fields_ = [ -] -class __sFILE(Structure): - pass -__sFILE._pack_ = 4 -__sFILE._fields_ = [ - ('_p', POINTER(c_ubyte)), - ('_r', c_int), - ('_w', c_int), - ('_flags', c_short), - ('_file', c_short), - ('_bf', __sbuf), - ('_lbfsize', c_int), - ('_cookie', c_void_p), - ('_close', CFUNCTYPE(c_int, c_void_p)), - ('_read', CFUNCTYPE(c_int, c_void_p, STRING, c_int)), - ('_seek', CFUNCTYPE(fpos_t, c_void_p, c_longlong, c_int)), - ('_write', CFUNCTYPE(c_int, c_void_p, STRING, c_int)), - ('_ub', __sbuf), - ('_extra', POINTER(__sFILEX)), - ('_ur', c_int), - ('_ubuf', c_ubyte * 3), - ('_nbuf', c_ubyte * 1), - ('_lb', __sbuf), - ('_blksize', c_int), - ('_offset', fpos_t), -] -assert sizeof(__sFILE) == 88, sizeof(__sFILE) -assert alignment(__sFILE) == 4, alignment(__sFILE) -FILE = __sFILE -ct_rune_t = __darwin_ct_rune_t -rune_t = __darwin_rune_t -class div_t(Structure): - pass -div_t._fields_ = [ - ('quot', c_int), - ('rem', c_int), -] -assert sizeof(div_t) == 8, sizeof(div_t) -assert alignment(div_t) == 4, alignment(div_t) -class ldiv_t(Structure): - pass -ldiv_t._fields_ = [ - ('quot', c_long), - ('rem', c_long), -] -assert sizeof(ldiv_t) == 8, sizeof(ldiv_t) -assert alignment(ldiv_t) == 4, alignment(ldiv_t) -class lldiv_t(Structure): - pass -lldiv_t._pack_ = 4 -lldiv_t._fields_ = [ - ('quot', c_longlong), - ('rem', c_longlong), -] -assert sizeof(lldiv_t) == 16, sizeof(lldiv_t) -assert alignment(lldiv_t) == 4, alignment(lldiv_t) -__darwin_dev_t = __int32_t -dev_t = __darwin_dev_t -__darwin_mode_t = __uint16_t -mode_t = __darwin_mode_t -class mcontext(Structure): - pass -mcontext._fields_ = [ -] -class mcontext64(Structure): - pass -mcontext64._fields_ = [ -] -class __darwin_pthread_handler_rec(Structure): - pass -__darwin_pthread_handler_rec._fields_ = [ - ('__routine', CFUNCTYPE(None, c_void_p)), - ('__arg', c_void_p), - ('__next', POINTER(__darwin_pthread_handler_rec)), -] -assert sizeof(__darwin_pthread_handler_rec) == 12, sizeof(__darwin_pthread_handler_rec) -assert alignment(__darwin_pthread_handler_rec) == 4, alignment(__darwin_pthread_handler_rec) -class _opaque_pthread_attr_t(Structure): - pass -_opaque_pthread_attr_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 36), -] -assert sizeof(_opaque_pthread_attr_t) == 40, sizeof(_opaque_pthread_attr_t) -assert alignment(_opaque_pthread_attr_t) == 4, alignment(_opaque_pthread_attr_t) -class _opaque_pthread_cond_t(Structure): - pass -_opaque_pthread_cond_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 24), -] -assert sizeof(_opaque_pthread_cond_t) == 28, sizeof(_opaque_pthread_cond_t) -assert alignment(_opaque_pthread_cond_t) == 4, alignment(_opaque_pthread_cond_t) -class _opaque_pthread_condattr_t(Structure): - pass -_opaque_pthread_condattr_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 4), -] -assert sizeof(_opaque_pthread_condattr_t) == 8, sizeof(_opaque_pthread_condattr_t) -assert alignment(_opaque_pthread_condattr_t) == 4, alignment(_opaque_pthread_condattr_t) -class _opaque_pthread_mutex_t(Structure): - pass -_opaque_pthread_mutex_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 40), -] -assert sizeof(_opaque_pthread_mutex_t) == 44, sizeof(_opaque_pthread_mutex_t) -assert alignment(_opaque_pthread_mutex_t) == 4, alignment(_opaque_pthread_mutex_t) -class _opaque_pthread_mutexattr_t(Structure): - pass -_opaque_pthread_mutexattr_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 8), -] -assert sizeof(_opaque_pthread_mutexattr_t) == 12, sizeof(_opaque_pthread_mutexattr_t) -assert alignment(_opaque_pthread_mutexattr_t) == 4, alignment(_opaque_pthread_mutexattr_t) -class _opaque_pthread_once_t(Structure): - pass -_opaque_pthread_once_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 4), -] -assert sizeof(_opaque_pthread_once_t) == 8, sizeof(_opaque_pthread_once_t) -assert alignment(_opaque_pthread_once_t) == 4, alignment(_opaque_pthread_once_t) -class _opaque_pthread_rwlock_t(Structure): - pass -_opaque_pthread_rwlock_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 124), -] -assert sizeof(_opaque_pthread_rwlock_t) == 128, sizeof(_opaque_pthread_rwlock_t) -assert alignment(_opaque_pthread_rwlock_t) == 4, alignment(_opaque_pthread_rwlock_t) -class _opaque_pthread_rwlockattr_t(Structure): - pass -_opaque_pthread_rwlockattr_t._fields_ = [ - ('__sig', c_long), - ('__opaque', c_char * 12), -] -assert sizeof(_opaque_pthread_rwlockattr_t) == 16, sizeof(_opaque_pthread_rwlockattr_t) -assert alignment(_opaque_pthread_rwlockattr_t) == 4, alignment(_opaque_pthread_rwlockattr_t) -class _opaque_pthread_t(Structure): - pass -_opaque_pthread_t._fields_ = [ - ('__sig', c_long), - ('__cleanup_stack', POINTER(__darwin_pthread_handler_rec)), - ('__opaque', c_char * 596), -] -assert sizeof(_opaque_pthread_t) == 604, sizeof(_opaque_pthread_t) -assert alignment(_opaque_pthread_t) == 4, alignment(_opaque_pthread_t) -__darwin_blkcnt_t = __int64_t -__darwin_blksize_t = __int32_t -__darwin_fsblkcnt_t = c_uint -__darwin_fsfilcnt_t = c_uint -__darwin_gid_t = __uint32_t -__darwin_id_t = __uint32_t -__darwin_ino_t = __uint32_t -__darwin_mach_port_name_t = __darwin_natural_t -__darwin_mach_port_t = __darwin_mach_port_name_t -__darwin_mcontext_t = POINTER(mcontext) -__darwin_mcontext64_t = POINTER(mcontext64) -__darwin_pid_t = __int32_t -__darwin_pthread_attr_t = _opaque_pthread_attr_t -__darwin_pthread_cond_t = _opaque_pthread_cond_t -__darwin_pthread_condattr_t = _opaque_pthread_condattr_t -__darwin_pthread_key_t = c_ulong -__darwin_pthread_mutex_t = _opaque_pthread_mutex_t -__darwin_pthread_mutexattr_t = _opaque_pthread_mutexattr_t -__darwin_pthread_once_t = _opaque_pthread_once_t -__darwin_pthread_rwlock_t = _opaque_pthread_rwlock_t -__darwin_pthread_rwlockattr_t = _opaque_pthread_rwlockattr_t -__darwin_pthread_t = POINTER(_opaque_pthread_t) -__darwin_sigset_t = __uint32_t -__darwin_suseconds_t = __int32_t -__darwin_uid_t = __uint32_t -__darwin_useconds_t = __uint32_t -__darwin_uuid_t = c_ubyte * 16 -class sigaltstack(Structure): - pass -sigaltstack._fields_ = [ - ('ss_sp', c_void_p), - ('ss_size', __darwin_size_t), - ('ss_flags', c_int), -] -assert sizeof(sigaltstack) == 12, sizeof(sigaltstack) -assert alignment(sigaltstack) == 4, alignment(sigaltstack) -__darwin_stack_t = sigaltstack -class ucontext(Structure): - pass -ucontext._fields_ = [ - ('uc_onstack', c_int), - ('uc_sigmask', __darwin_sigset_t), - ('uc_stack', __darwin_stack_t), - ('uc_link', POINTER(ucontext)), - ('uc_mcsize', __darwin_size_t), - ('uc_mcontext', __darwin_mcontext_t), -] -assert sizeof(ucontext) == 32, sizeof(ucontext) -assert alignment(ucontext) == 4, alignment(ucontext) -__darwin_ucontext_t = ucontext -class ucontext64(Structure): - pass -ucontext64._fields_ = [ - ('uc_onstack', c_int), - ('uc_sigmask', __darwin_sigset_t), - ('uc_stack', __darwin_stack_t), - ('uc_link', POINTER(ucontext64)), - ('uc_mcsize', __darwin_size_t), - ('uc_mcontext64', __darwin_mcontext64_t), -] -assert sizeof(ucontext64) == 32, sizeof(ucontext64) -assert alignment(ucontext64) == 4, alignment(ucontext64) -__darwin_ucontext64_t = ucontext64 -class timeval(Structure): - pass -timeval._fields_ = [ - ('tv_sec', __darwin_time_t), - ('tv_usec', __darwin_suseconds_t), -] -assert sizeof(timeval) == 8, sizeof(timeval) -assert alignment(timeval) == 4, alignment(timeval) -rlim_t = __int64_t -class rusage(Structure): - pass -rusage._fields_ = [ - ('ru_utime', timeval), - ('ru_stime', timeval), - ('ru_maxrss', c_long), - ('ru_ixrss', c_long), - ('ru_idrss', c_long), - ('ru_isrss', c_long), - ('ru_minflt', c_long), - ('ru_majflt', c_long), - ('ru_nswap', c_long), - ('ru_inblock', c_long), - ('ru_oublock', c_long), - ('ru_msgsnd', c_long), - ('ru_msgrcv', c_long), - ('ru_nsignals', c_long), - ('ru_nvcsw', c_long), - ('ru_nivcsw', c_long), -] -assert sizeof(rusage) == 72, sizeof(rusage) -assert alignment(rusage) == 4, alignment(rusage) -class rlimit(Structure): - pass -rlimit._pack_ = 4 -rlimit._fields_ = [ - ('rlim_cur', rlim_t), - ('rlim_max', rlim_t), -] -assert sizeof(rlimit) == 16, sizeof(rlimit) -assert alignment(rlimit) == 4, alignment(rlimit) -mcontext_t = __darwin_mcontext_t -mcontext64_t = __darwin_mcontext64_t -pthread_attr_t = __darwin_pthread_attr_t -sigset_t = __darwin_sigset_t -ucontext_t = __darwin_ucontext_t -ucontext64_t = __darwin_ucontext64_t -uid_t = __darwin_uid_t -class sigval(Union): - pass -sigval._fields_ = [ - ('sival_int', c_int), - ('sival_ptr', c_void_p), -] -assert sizeof(sigval) == 4, sizeof(sigval) -assert alignment(sigval) == 4, alignment(sigval) -class sigevent(Structure): - pass -sigevent._fields_ = [ - ('sigev_notify', c_int), - ('sigev_signo', c_int), - ('sigev_value', sigval), - ('sigev_notify_function', CFUNCTYPE(None, sigval)), - ('sigev_notify_attributes', POINTER(pthread_attr_t)), -] -assert sizeof(sigevent) == 20, sizeof(sigevent) -assert alignment(sigevent) == 4, alignment(sigevent) -class __siginfo(Structure): - pass -pid_t = __darwin_pid_t -__siginfo._fields_ = [ - ('si_signo', c_int), - ('si_errno', c_int), - ('si_code', c_int), - ('si_pid', pid_t), - ('si_uid', uid_t), - ('si_status', c_int), - ('si_addr', c_void_p), - ('si_value', sigval), - ('si_band', c_long), - ('pad', c_ulong * 7), -] -assert sizeof(__siginfo) == 64, sizeof(__siginfo) -assert alignment(__siginfo) == 4, alignment(__siginfo) -siginfo_t = __siginfo -class __sigaction_u(Union): - pass -__sigaction_u._fields_ = [ - ('__sa_handler', CFUNCTYPE(None, c_int)), - ('__sa_sigaction', CFUNCTYPE(None, c_int, POINTER(__siginfo), c_void_p)), -] -assert sizeof(__sigaction_u) == 4, sizeof(__sigaction_u) -assert alignment(__sigaction_u) == 4, alignment(__sigaction_u) -class __sigaction(Structure): - pass -__sigaction._fields_ = [ - ('__sigaction_u', __sigaction_u), - ('sa_tramp', CFUNCTYPE(None, c_void_p, c_int, c_int, POINTER(siginfo_t), c_void_p)), - ('sa_mask', sigset_t), - ('sa_flags', c_int), -] -assert sizeof(__sigaction) == 16, sizeof(__sigaction) -assert alignment(__sigaction) == 4, alignment(__sigaction) -class sigaction(Structure): - pass -sigaction._fields_ = [ - ('__sigaction_u', __sigaction_u), - ('sa_mask', sigset_t), - ('sa_flags', c_int), -] -assert sizeof(sigaction) == 12, sizeof(sigaction) -assert alignment(sigaction) == 4, alignment(sigaction) -sig_t = CFUNCTYPE(None, c_int) -stack_t = __darwin_stack_t -class sigvec(Structure): - pass -sigvec._fields_ = [ - ('sv_handler', CFUNCTYPE(None, c_int)), - ('sv_mask', c_int), - ('sv_flags', c_int), -] -assert sizeof(sigvec) == 12, sizeof(sigvec) -assert alignment(sigvec) == 4, alignment(sigvec) -class sigstack(Structure): - pass -sigstack._fields_ = [ - ('ss_sp', STRING), - ('ss_onstack', c_int), -] -assert sizeof(sigstack) == 8, sizeof(sigstack) -assert alignment(sigstack) == 4, alignment(sigstack) -u_char = c_ubyte -u_short = c_ushort -u_int = c_uint -u_long = c_ulong -ushort = c_ushort -uint = c_uint -u_quad_t = u_int64_t -quad_t = int64_t -qaddr_t = POINTER(quad_t) -caddr_t = STRING -daddr_t = int32_t -fixpt_t = u_int32_t -blkcnt_t = __darwin_blkcnt_t -blksize_t = __darwin_blksize_t -gid_t = __darwin_gid_t -in_addr_t = __uint32_t -in_port_t = __uint16_t -ino_t = __darwin_ino_t -key_t = __int32_t -nlink_t = __uint16_t -off_t = __darwin_off_t -segsz_t = int32_t -swblk_t = int32_t -clock_t = __darwin_clock_t -ssize_t = __darwin_ssize_t -useconds_t = __darwin_useconds_t -suseconds_t = __darwin_suseconds_t -fd_mask = __int32_t -class fd_set(Structure): - pass -fd_set._fields_ = [ - ('fds_bits', __int32_t * 32), -] -assert sizeof(fd_set) == 128, sizeof(fd_set) -assert alignment(fd_set) == 4, alignment(fd_set) -pthread_cond_t = __darwin_pthread_cond_t -pthread_condattr_t = __darwin_pthread_condattr_t -pthread_mutex_t = __darwin_pthread_mutex_t -pthread_mutexattr_t = __darwin_pthread_mutexattr_t -pthread_once_t = __darwin_pthread_once_t -pthread_rwlock_t = __darwin_pthread_rwlock_t -pthread_rwlockattr_t = __darwin_pthread_rwlockattr_t -pthread_t = __darwin_pthread_t -pthread_key_t = __darwin_pthread_key_t -fsblkcnt_t = __darwin_fsblkcnt_t -fsfilcnt_t = __darwin_fsfilcnt_t - -# values for enumeration 'idtype_t' -idtype_t = c_int # enum -id_t = __darwin_id_t -class wait(Union): - pass -class N4wait3DOLLAR_3E(Structure): - pass -N4wait3DOLLAR_3E._fields_ = [ - ('w_Termsig', c_uint, 7), - ('w_Coredump', c_uint, 1), - ('w_Retcode', c_uint, 8), - ('w_Filler', c_uint, 16), -] -assert sizeof(N4wait3DOLLAR_3E) == 4, sizeof(N4wait3DOLLAR_3E) -assert alignment(N4wait3DOLLAR_3E) == 4, alignment(N4wait3DOLLAR_3E) -class N4wait3DOLLAR_4E(Structure): - pass -N4wait3DOLLAR_4E._fields_ = [ - ('w_Stopval', c_uint, 8), - ('w_Stopsig', c_uint, 8), - ('w_Filler', c_uint, 16), -] -assert sizeof(N4wait3DOLLAR_4E) == 4, sizeof(N4wait3DOLLAR_4E) -assert alignment(N4wait3DOLLAR_4E) == 4, alignment(N4wait3DOLLAR_4E) -wait._fields_ = [ - ('w_status', c_int), - ('w_T', N4wait3DOLLAR_3E), - ('w_S', N4wait3DOLLAR_4E), -] -assert sizeof(wait) == 4, sizeof(wait) -assert alignment(wait) == 4, alignment(wait) -class timespec(Structure): - pass -timespec._fields_ = [ - ('tv_sec', time_t), - ('tv_nsec', c_long), -] -assert sizeof(timespec) == 8, sizeof(timespec) -assert alignment(timespec) == 4, alignment(timespec) -class tm(Structure): - pass -tm._fields_ = [ - ('tm_sec', c_int), - ('tm_min', c_int), - ('tm_hour', c_int), - ('tm_mday', c_int), - ('tm_mon', c_int), - ('tm_year', c_int), - ('tm_wday', c_int), - ('tm_yday', c_int), - ('tm_isdst', c_int), - ('tm_gmtoff', c_long), - ('tm_zone', STRING), -] -assert sizeof(tm) == 44, sizeof(tm) -assert alignment(tm) == 4, alignment(tm) -__gnuc_va_list = STRING -ptrdiff_t = c_int -int8_t = c_byte -int16_t = c_short -uint8_t = c_ubyte -uint16_t = c_ushort -uint32_t = c_uint -uint64_t = c_ulonglong -int_least8_t = int8_t -int_least16_t = int16_t -int_least32_t = int32_t -int_least64_t = int64_t -uint_least8_t = uint8_t -uint_least16_t = uint16_t -uint_least32_t = uint32_t -uint_least64_t = uint64_t -int_fast8_t = int8_t -int_fast16_t = int16_t -int_fast32_t = int32_t -int_fast64_t = int64_t -uint_fast8_t = uint8_t -uint_fast16_t = uint16_t -uint_fast32_t = uint32_t -uint_fast64_t = uint64_t -intptr_t = c_long -uintptr_t = c_ulong -intmax_t = c_longlong -uintmax_t = c_ulonglong -__all__ = ['ENGINE', 'pkcs7_enc_content_st', '__int16_t', - 'X509_REVOKED', 'SSL_CTX', 'UIT_BOOLEAN', - '__darwin_time_t', 'ucontext64_t', 'int_fast32_t', - 'pem_ctx_st', 'uint8_t', 'fpos_t', 'X509', 'COMP_CTX', - 'tm', 'N10pem_ctx_st4DOLLAR_17E', 'swblk_t', - 'ASN1_TEMPLATE', '__darwin_pthread_t', 'fixpt_t', - 'BIO_METHOD', 'ASN1_PRINTABLESTRING', 'EVP_ENCODE_CTX', - 'dh_method', 'bio_f_buffer_ctx_struct', 'in_port_t', - 'X509_SIG', '__darwin_ssize_t', '__darwin_sigset_t', - 'wait', 'uint_fast16_t', 'N12asn1_type_st4DOLLAR_11E', - 'uint_least8_t', 'pthread_rwlock_t', 'ASN1_IA5STRING', - 'fsfilcnt_t', 'ucontext', '__uint64_t', 'timespec', - 'x509_cinf_st', 'COMP_METHOD', 'MD5_CTX', 'buf_mem_st', - 'ASN1_ENCODING_st', 'PBEPARAM', 'X509_NAME_ENTRY', - '__darwin_va_list', 'ucontext_t', 'lhash_st', - 'N4wait3DOLLAR_4E', '__darwin_uuid_t', - '_ossl_old_des_ks_struct', 'id_t', 'ASN1_BIT_STRING', - 'va_list', '__darwin_wchar_t', 'pthread_key_t', - 'pkcs7_signer_info_st', 'ASN1_METHOD', 'DSA_SIG', 'DSA', - 'UIT_NONE', 'pthread_t', '__darwin_useconds_t', - 'uint_fast8_t', 'UI_STRING', 'DES_cblock', - '__darwin_mcontext64_t', 'rlim_t', 'PEM_Encode_Seal_st', - 'SHAstate_st', 'u_quad_t', 'openssl_fptr', - '_opaque_pthread_rwlockattr_t', - 'N18x509_attributes_st4DOLLAR_13E', - '__darwin_pthread_rwlock_t', 'daddr_t', 'ui_string_st', - 'x509_file_st', 'X509_req_info_st', 'int_least64_t', - 'evp_Encode_Ctx_st', 'X509_OBJECTS', 'CRYPTO_EX_DATA', - '__int8_t', 'AUTHORITY_KEYID_st', '_opaque_pthread_attr_t', - 'sigstack', 'EVP_CIPHER_CTX', 'X509_extension_st', 'pid_t', - 'RSA_METHOD', 'PEM_USER', 'pem_recip_st', 'env_md_ctx_st', - 'rc5_key_st', 'ui_st', 'X509_PUBKEY', 'u_int8_t', - 'ASN1_ITEM_st', 'pkcs7_recip_info_st', 'ssl2_state_st', - 'off_t', 'N10ssl_ctx_st4DOLLAR_18E', 'crypto_ex_data_st', - 'ui_method_st', '__darwin_pthread_rwlockattr_t', - 'CRYPTO_EX_dup', '__darwin_ino_t', '__sFILE', - 'OSUnknownByteOrder', 'BN_MONT_CTX', 'ASN1_NULL', 'time_t', - 'CRYPTO_EX_new', 'asn1_type_st', 'CRYPTO_EX_DATA_FUNCS', - 'user_time_t', 'BIGNUM', 'pthread_rwlockattr_t', - 'ASN1_VALUE_st', 'DH_METHOD', '__darwin_off_t', - '_opaque_pthread_t', 'bn_blinding_st', 'RSA', 'ssize_t', - 'mcontext64_t', 'user_long_t', 'fsblkcnt_t', 'cert_st', - '__darwin_pthread_condattr_t', 'X509_PKEY', - '__darwin_id_t', '__darwin_nl_item', 'SSL2_STATE', 'FILE', - 'pthread_mutexattr_t', 'size_t', - '_ossl_old_des_key_schedule', 'pkcs7_issuer_and_serial_st', - 'sigval', 'CRYPTO_MEM_LEAK_CB', 'X509_NAME', 'blkcnt_t', - 'uint_least16_t', '__darwin_dev_t', 'evp_cipher_info_st', - 'BN_BLINDING', 'ssl3_state_st', 'uint_least64_t', - 'user_addr_t', 'DES_key_schedule', 'RIPEMD160_CTX', - 'u_char', 'X509_algor_st', 'uid_t', 'sess_cert_st', - 'u_int64_t', 'u_int16_t', 'sigset_t', '__darwin_ptrdiff_t', - 'ASN1_CTX', 'STACK', '__int32_t', 'UI_METHOD', - 'NETSCAPE_SPKI', 'UIT_PROMPT', 'st_CRYPTO_EX_DATA_IMPL', - 'cast_key_st', 'X509_HASH_DIR_CTX', 'sigevent', - 'user_ssize_t', 'clock_t', 'aes_key_st', - '__darwin_socklen_t', '__darwin_intptr_t', 'int_fast64_t', - 'asn1_string_table_st', 'uint_fast32_t', - 'ASN1_VISIBLESTRING', 'DSA_SIG_st', 'obj_name_st', - 'X509_LOOKUP_METHOD', 'u_int32_t', 'EVP_CIPHER_INFO', - '__gnuc_va_list', 'AES_KEY', 'PKCS7_ISSUER_AND_SERIAL', - 'BN_CTX', '__darwin_blkcnt_t', 'key_t', 'SHA_CTX', - 'pkcs7_signed_st', 'SSL', 'N10pem_ctx_st4DOLLAR_16E', - 'pthread_attr_t', 'EVP_MD', 'uint', 'ASN1_BOOLEAN', - 'ino_t', '__darwin_clock_t', 'ASN1_OCTET_STRING', - 'asn1_ctx_st', 'BIO_F_BUFFER_CTX', 'bn_mont_ctx_st', - 'X509_REQ_INFO', 'PEM_CTX', 'sigvec', - '__darwin_pthread_mutexattr_t', 'x509_attributes_st', - 'stack_t', '__darwin_mode_t', '__mbstate_t', - 'asn1_object_st', 'ASN1_ENCODING', '__uint8_t', - 'LHASH_NODE', 'PKCS7_SIGNER_INFO', 'asn1_method_st', - 'stack_st', 'bio_info_cb', 'div_t', 'UIT_VERIFY', - 'PBEPARAM_st', 'N4wait3DOLLAR_3E', 'quad_t', '__siginfo', - '__darwin_mbstate_t', 'rsa_st', 'ASN1_UNIVERSALSTRING', - 'uint64_t', 'ssl_comp_st', 'X509_OBJECT', 'pthread_cond_t', - 'DH', '__darwin_wctype_t', 'PKCS7_ENVELOPE', 'ASN1_TLC_st', - 'sig_atomic_t', 'BIO', 'nlink_t', 'BUF_MEM', 'SSL3_RECORD', - 'bio_method_st', 'timeval', 'UI_string_types', 'BIO_dummy', - 'ssl_ctx_st', 'NETSCAPE_CERT_SEQUENCE', - 'BIT_STRING_BITNAME_st', '__darwin_pthread_attr_t', - 'int8_t', '__darwin_wint_t', 'OBJ_NAME', - 'PKCS8_PRIV_KEY_INFO', 'PBE2PARAM_st', - 'LHASH_DOALL_FN_TYPE', 'x509_st', 'X509_VAL', 'dev_t', - 'ASN1_TEMPLATE_st', 'MD5state_st', '__uint16_t', - 'LHASH_DOALL_ARG_FN_TYPE', 'mdc2_ctx_st', 'SSL3_STATE', - 'ssl3_buffer_st', 'ASN1_ITEM_EXP', - '_opaque_pthread_condattr_t', 'mode_t', 'ASN1_VALUE', - 'qaddr_t', '__darwin_gid_t', 'EVP_PKEY', 'CRYPTO_EX_free', - '_ossl_old_des_cblock', 'X509_INFO', 'asn1_string_st', - 'intptr_t', 'UIT_INFO', 'int_fast8_t', 'sigaltstack', - 'env_md_st', 'LHASH', '__darwin_ucontext_t', - 'PKCS7_SIGN_ENVELOPE', '__darwin_mcontext_t', 'ct_rune_t', - 'MD2_CTX', 'pthread_once_t', 'SSL3_BUFFER', 'fd_mask', - 'ASN1_TYPE', 'PKCS7_SIGNED', 'ssl3_record_st', 'BF_KEY', - 'MD4state_st', 'MD4_CTX', 'int16_t', 'SSL_CIPHER', - 'rune_t', 'X509_TRUST', 'siginfo_t', 'X509_STORE', - '__sbuf', 'X509_STORE_CTX', '__darwin_blksize_t', 'ldiv_t', - 'ASN1_TIME', 'SSL_METHOD', 'X509_LOOKUP', - 'Netscape_spki_st', 'P_PID', 'sigaction', 'sig_t', - 'hostent', 'x509_cert_aux_st', '_opaque_pthread_cond_t', - 'segsz_t', 'ushort', '__darwin_ct_rune_t', 'fd_set', - 'BN_RECP_CTX', 'x509_lookup_st', 'uint16_t', 'pkcs7_st', - 'asn1_header_st', '__darwin_pthread_key_t', - 'x509_trust_st', '__darwin_pthread_handler_rec', 'int32_t', - 'X509_CRL_INFO', 'N11evp_pkey_st4DOLLAR_12E', 'MDC2_CTX', - 'N23_ossl_old_des_ks_struct4DOLLAR_10E', 'ASN1_HEADER', - 'X509_crl_info_st', 'LHASH_HASH_FN_TYPE', - '_opaque_pthread_mutexattr_t', 'ssl_st', - 'N8pkcs7_st4DOLLAR_15E', 'evp_pkey_st', - 'pkcs7_signedandenveloped_st', '__darwin_mach_port_t', - 'EVP_PBE_KEYGEN', '_opaque_pthread_mutex_t', - 'ASN1_UTCTIME', 'mcontext', 'crypto_ex_data_func_st', - 'u_long', 'PBKDF2PARAM_st', 'rc4_key_st', 'DSA_METHOD', - 'EVP_CIPHER', 'BIT_STRING_BITNAME', 'PKCS7_RECIP_INFO', - 'ssl3_enc_method', 'X509_CERT_AUX', 'uintmax_t', - 'int_fast16_t', 'RC5_32_KEY', 'ucontext64', 'ASN1_INTEGER', - 'u_short', 'N14x509_object_st4DOLLAR_14E', 'mcontext64', - 'X509_sig_st', 'ASN1_GENERALSTRING', 'PKCS7', '__sFILEX', - 'X509_name_entry_st', 'ssl_session_st', 'caddr_t', - 'bignum_st', 'X509_CINF', '__darwin_pthread_cond_t', - 'ASN1_TLC', 'PKCS7_ENCRYPT', 'NETSCAPE_SPKAC', - 'Netscape_spkac_st', 'idtype_t', 'UIT_ERROR', - 'uint_fast64_t', 'in_addr_t', 'pthread_mutex_t', - '__int64_t', 'ASN1_BMPSTRING', 'uint32_t', - 'PEM_ENCODE_SEAL_CTX', 'suseconds_t', 'ASN1_OBJECT', - 'X509_val_st', 'private_key_st', 'CRYPTO_dynlock', - 'X509_objects_st', 'CRYPTO_EX_DATA_IMPL', - 'pthread_condattr_t', 'PKCS7_DIGEST', 'uint_least32_t', - 'ASN1_STRING', '__uint32_t', 'P_PGID', 'rsa_meth_st', - 'X509_crl_st', 'RC2_KEY', '__darwin_fsfilcnt_t', - 'X509_revoked_st', 'PBE2PARAM', 'blksize_t', - 'Netscape_certificate_sequence', 'ssl_cipher_st', - 'bignum_ctx', 'register_t', 'ASN1_UTF8STRING', - 'pkcs7_encrypted_st', 'RC4_KEY', '__darwin_ucontext64_t', - 'N13ssl2_state_st4DOLLAR_19E', 'bn_recp_ctx_st', - 'CAST_KEY', 'X509_ATTRIBUTE', '__darwin_suseconds_t', - '__sigaction', 'user_ulong_t', 'syscall_arg_t', - 'evp_cipher_ctx_st', 'X509_ALGOR', 'mcontext_t', - 'const_DES_cblock', '__darwin_fsblkcnt_t', 'dsa_st', - 'int_least8_t', 'MD2state_st', 'X509_EXTENSION', - 'GEN_SESSION_CB', 'int_least16_t', '__darwin_wctrans_t', - 'PBKDF2PARAM', 'x509_lookup_method_st', 'pem_password_cb', - 'X509_info_st', 'x509_store_st', '__darwin_natural_t', - 'X509_pubkey_st', 'pkcs7_digest_st', '__darwin_size_t', - 'ASN1_STRING_TABLE', 'OSLittleEndian', 'RIPEMD160state_st', - 'pkcs7_enveloped_st', 'UI', 'ptrdiff_t', 'X509_REQ', - 'CRYPTO_dynlock_value', 'X509_req_st', 'x509_store_ctx_st', - 'N13ssl3_state_st4DOLLAR_20E', 'lhash_node_st', - '__darwin_pthread_mutex_t', 'LHASH_COMP_FN_TYPE', - '__darwin_rune_t', 'rlimit', '__darwin_pthread_once_t', - 'OSBigEndian', 'uintptr_t', '__darwin_uid_t', 'u_int', - 'ASN1_T61STRING', 'gid_t', 'ssl_method_st', 'ASN1_ITEM', - 'ASN1_ENUMERATED', '_opaque_pthread_rwlock_t', - 'pkcs8_priv_key_info_st', 'intmax_t', 'sigcontext', - 'X509_CRL', 'rc2_key_st', 'engine_st', 'x509_object_st', - '_opaque_pthread_once_t', 'DES_ks', 'SSL_COMP', - 'dsa_method', 'int64_t', 'bio_st', 'bf_key_st', - 'ASN1_GENERALIZEDTIME', 'PKCS7_ENC_CONTENT', - '__darwin_pid_t', 'lldiv_t', 'comp_method_st', - 'EVP_MD_CTX', 'evp_cipher_st', 'X509_name_st', - 'x509_hash_dir_st', '__darwin_mach_port_name_t', - 'useconds_t', 'user_size_t', 'SSL_SESSION', 'rusage', - 'ssl_crock_st', 'int_least32_t', '__sigaction_u', 'dh_st', - 'P_ALL', '__darwin_stack_t', 'N6DES_ks3DOLLAR_9E', - 'comp_ctx_st', 'X509_CERT_FILE_CTX'] diff --git a/Lib/test/test_lib2to3/data/py2_test_grammar.py b/Lib/test/test_lib2to3/data/py2_test_grammar.py deleted file mode 100644 index 1a631510f4dba..0000000000000 --- a/Lib/test/test_lib2to3/data/py2_test_grammar.py +++ /dev/null @@ -1,971 +0,0 @@ -# Python test set -- part 1, grammar. -# This just tests whether the parser accepts them all. - -# NOTE: When you run this test as a script from the command line, you -# get warnings about certain hex/oct constants. Since those are -# issued by the parser, you can't suppress them by adding a -# filterwarnings() call to this module. Therefore, to shut up the -# regression test, the filterwarnings() call has been added to -# regrtest.py. - -from test.test_support import check_syntax_error -import unittest -import sys -# testing import * -from sys import * - -class TokenTests(unittest.TestCase): - - def testBackslash(self): - # Backslash means line continuation: - x = 1 \ - + 1 - self.assertEquals(x, 2, 'backslash for line continuation') - - # Backslash does not means continuation in comments :\ - x = 0 - self.assertEquals(x, 0, 'backslash ending comment') - - def testPlainIntegers(self): - self.assertEquals(0xff, 255) - self.assertEquals(0377, 255) - self.assertEquals(2147483647, 017777777777) - # "0x" is not a valid literal - self.assertRaises(SyntaxError, eval, "0x") - from sys import maxint - if maxint == 2147483647: - self.assertEquals(-2147483647-1, -020000000000) - # XXX -2147483648 - self.assert_(037777777777 > 0) - self.assert_(0xffffffff > 0) - for s in '2147483648', '040000000000', '0x100000000': - try: - x = eval(s) - except OverflowError: - self.fail("OverflowError on huge integer literal %r" % s) - elif maxint == 9223372036854775807: - self.assertEquals(-9223372036854775807-1, -01000000000000000000000) - self.assert_(01777777777777777777777 > 0) - self.assert_(0xffffffffffffffff > 0) - for s in '9223372036854775808', '02000000000000000000000', \ - '0x10000000000000000': - try: - x = eval(s) - except OverflowError: - self.fail("OverflowError on huge integer literal %r" % s) - else: - self.fail('Weird maxint value %r' % maxint) - - def testLongIntegers(self): - x = 0L - x = 0l - x = 0xffffffffffffffffL - x = 0xffffffffffffffffl - x = 077777777777777777L - x = 077777777777777777l - x = 123456789012345678901234567890L - x = 123456789012345678901234567890l - - def testFloats(self): - x = 3.14 - x = 314. - x = 0.314 - # XXX x = 000.314 - x = .314 - x = 3e14 - x = 3E14 - x = 3e-14 - x = 3e+14 - x = 3.e14 - x = .3e14 - x = 3.1e4 - - def testStringLiterals(self): - x = ''; y = ""; self.assert_(len(x) == 0 and x == y) - x = '\''; y = "'"; self.assert_(len(x) == 1 and x == y and ord(x) == 39) - x = '"'; y = "\""; self.assert_(len(x) == 1 and x == y and ord(x) == 34) - x = "doesn't \"shrink\" does it" - y = 'doesn\'t "shrink" does it' - self.assert_(len(x) == 24 and x == y) - x = "does \"shrink\" doesn't it" - y = 'does "shrink" doesn\'t it' - self.assert_(len(x) == 24 and x == y) - x = """ -The "quick" -brown fox -jumps over -the 'lazy' dog. -""" - y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n' - self.assertEquals(x, y) - y = ''' -The "quick" -brown fox -jumps over -the 'lazy' dog. -''' - self.assertEquals(x, y) - y = "\n\ -The \"quick\"\n\ -brown fox\n\ -jumps over\n\ -the 'lazy' dog.\n\ -" - self.assertEquals(x, y) - y = '\n\ -The \"quick\"\n\ -brown fox\n\ -jumps over\n\ -the \'lazy\' dog.\n\ -' - self.assertEquals(x, y) - - -class GrammarTests(unittest.TestCase): - - # single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE - # XXX can't test in a script -- this rule is only used when interactive - - # file_input: (NEWLINE | stmt)* ENDMARKER - # Being tested as this very moment this very module - - # expr_input: testlist NEWLINE - # XXX Hard to test -- used only in calls to input() - - def testEvalInput(self): - # testlist ENDMARKER - x = eval('1, 0 or 1') - - def testFuncdef(self): - ### 'def' NAME parameters ':' suite - ### parameters: '(' [varargslist] ')' - ### varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] - ### | ('**'|'*' '*') NAME) - ### | fpdef ['=' test] (',' fpdef ['=' test])* [','] - ### fpdef: NAME | '(' fplist ')' - ### fplist: fpdef (',' fpdef)* [','] - ### arglist: (argument ',')* (argument | *' test [',' '**' test] | '**' test) - ### argument: [test '='] test # Really [keyword '='] test - def f1(): pass - f1() - f1(*()) - f1(*(), **{}) - def f2(one_argument): pass - def f3(two, arguments): pass - def f4(two, (compound, (argument, list))): pass - def f5((compound, first), two): pass - self.assertEquals(f2.func_code.co_varnames, ('one_argument',)) - self.assertEquals(f3.func_code.co_varnames, ('two', 'arguments')) - if sys.platform.startswith('java'): - self.assertEquals(f4.func_code.co_varnames, - ('two', '(compound, (argument, list))', 'compound', 'argument', - 'list',)) - self.assertEquals(f5.func_code.co_varnames, - ('(compound, first)', 'two', 'compound', 'first')) - else: - self.assertEquals(f4.func_code.co_varnames, - ('two', '.1', 'compound', 'argument', 'list')) - self.assertEquals(f5.func_code.co_varnames, - ('.0', 'two', 'compound', 'first')) - def a1(one_arg,): pass - def a2(two, args,): pass - def v0(*rest): pass - def v1(a, *rest): pass - def v2(a, b, *rest): pass - def v3(a, (b, c), *rest): return a, b, c, rest - - f1() - f2(1) - f2(1,) - f3(1, 2) - f3(1, 2,) - f4(1, (2, (3, 4))) - v0() - v0(1) - v0(1,) - v0(1,2) - v0(1,2,3,4,5,6,7,8,9,0) - v1(1) - v1(1,) - v1(1,2) - v1(1,2,3) - v1(1,2,3,4,5,6,7,8,9,0) - v2(1,2) - v2(1,2,3) - v2(1,2,3,4) - v2(1,2,3,4,5,6,7,8,9,0) - v3(1,(2,3)) - v3(1,(2,3),4) - v3(1,(2,3),4,5,6,7,8,9,0) - - # ceval unpacks the formal arguments into the first argcount names; - # thus, the names nested inside tuples must appear after these names. - if sys.platform.startswith('java'): - self.assertEquals(v3.func_code.co_varnames, ('a', '(b, c)', 'rest', 'b', 'c')) - else: - self.assertEquals(v3.func_code.co_varnames, ('a', '.1', 'rest', 'b', 'c')) - self.assertEquals(v3(1, (2, 3), 4), (1, 2, 3, (4,))) - def d01(a=1): pass - d01() - d01(1) - d01(*(1,)) - d01(**{'a':2}) - def d11(a, b=1): pass - d11(1) - d11(1, 2) - d11(1, **{'b':2}) - def d21(a, b, c=1): pass - d21(1, 2) - d21(1, 2, 3) - d21(*(1, 2, 3)) - d21(1, *(2, 3)) - d21(1, 2, *(3,)) - d21(1, 2, **{'c':3}) - def d02(a=1, b=2): pass - d02() - d02(1) - d02(1, 2) - d02(*(1, 2)) - d02(1, *(2,)) - d02(1, **{'b':2}) - d02(**{'a': 1, 'b': 2}) - def d12(a, b=1, c=2): pass - d12(1) - d12(1, 2) - d12(1, 2, 3) - def d22(a, b, c=1, d=2): pass - d22(1, 2) - d22(1, 2, 3) - d22(1, 2, 3, 4) - def d01v(a=1, *rest): pass - d01v() - d01v(1) - d01v(1, 2) - d01v(*(1, 2, 3, 4)) - d01v(*(1,)) - d01v(**{'a':2}) - def d11v(a, b=1, *rest): pass - d11v(1) - d11v(1, 2) - d11v(1, 2, 3) - def d21v(a, b, c=1, *rest): pass - d21v(1, 2) - d21v(1, 2, 3) - d21v(1, 2, 3, 4) - d21v(*(1, 2, 3, 4)) - d21v(1, 2, **{'c': 3}) - def d02v(a=1, b=2, *rest): pass - d02v() - d02v(1) - d02v(1, 2) - d02v(1, 2, 3) - d02v(1, *(2, 3, 4)) - d02v(**{'a': 1, 'b': 2}) - def d12v(a, b=1, c=2, *rest): pass - d12v(1) - d12v(1, 2) - d12v(1, 2, 3) - d12v(1, 2, 3, 4) - d12v(*(1, 2, 3, 4)) - d12v(1, 2, *(3, 4, 5)) - d12v(1, *(2,), **{'c': 3}) - def d22v(a, b, c=1, d=2, *rest): pass - d22v(1, 2) - d22v(1, 2, 3) - d22v(1, 2, 3, 4) - d22v(1, 2, 3, 4, 5) - d22v(*(1, 2, 3, 4)) - d22v(1, 2, *(3, 4, 5)) - d22v(1, *(2, 3), **{'d': 4}) - def d31v((x)): pass - d31v(1) - def d32v((x,)): pass - d32v((1,)) - - # keyword arguments after *arglist - def f(*args, **kwargs): - return args, kwargs - self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4), - {'x':2, 'y':5})) - self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)") - self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)") - - # Check ast errors in *args and *kwargs - check_syntax_error(self, "f(*g(1=2))") - check_syntax_error(self, "f(**g(1=2))") - - def testLambdef(self): - ### lambdef: 'lambda' [varargslist] ':' test - l1 = lambda : 0 - self.assertEquals(l1(), 0) - l2 = lambda : a[d] # XXX just testing the expression - l3 = lambda : [2 < x for x in [-1, 3, 0L]] - self.assertEquals(l3(), [0, 1, 0]) - l4 = lambda x = lambda y = lambda z=1 : z : y() : x() - self.assertEquals(l4(), 1) - l5 = lambda x, y, z=2: x + y + z - self.assertEquals(l5(1, 2), 5) - self.assertEquals(l5(1, 2, 3), 6) - check_syntax_error(self, "lambda x: x = 2") - check_syntax_error(self, "lambda (None,): None") - - ### stmt: simple_stmt | compound_stmt - # Tested below - - def testSimpleStmt(self): - ### simple_stmt: small_stmt (';' small_stmt)* [';'] - x = 1; pass; del x - def foo(): - # verify statements that end with semi-colons - x = 1; pass; del x; - foo() - - ### small_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt - # Tested below - - def testExprStmt(self): - # (exprlist '=')* exprlist - 1 - 1, 2, 3 - x = 1 - x = 1, 2, 3 - x = y = z = 1, 2, 3 - x, y, z = 1, 2, 3 - abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) - - check_syntax_error(self, "x + 1 = 1") - check_syntax_error(self, "a + 1 = b + 2") - - def testPrintStmt(self): - # 'print' (test ',')* [test] - import StringIO - - # Can't test printing to real stdout without comparing output - # which is not available in unittest. - save_stdout = sys.stdout - sys.stdout = StringIO.StringIO() - - print 1, 2, 3 - print 1, 2, 3, - print - print 0 or 1, 0 or 1, - print 0 or 1 - - # 'print' '>>' test ',' - print >> sys.stdout, 1, 2, 3 - print >> sys.stdout, 1, 2, 3, - print >> sys.stdout - print >> sys.stdout, 0 or 1, 0 or 1, - print >> sys.stdout, 0 or 1 - - # test printing to an instance - class Gulp: - def write(self, msg): pass - - gulp = Gulp() - print >> gulp, 1, 2, 3 - print >> gulp, 1, 2, 3, - print >> gulp - print >> gulp, 0 or 1, 0 or 1, - print >> gulp, 0 or 1 - - # test print >> None - def driver(): - oldstdout = sys.stdout - sys.stdout = Gulp() - try: - tellme(Gulp()) - tellme() - finally: - sys.stdout = oldstdout - - # we should see this once - def tellme(file=sys.stdout): - print >> file, 'hello world' - - driver() - - # we should not see this at all - def tellme(file=None): - print >> file, 'goodbye universe' - - driver() - - self.assertEqual(sys.stdout.getvalue(), '''\ -1 2 3 -1 2 3 -1 1 1 -1 2 3 -1 2 3 -1 1 1 -hello world -''') - sys.stdout = save_stdout - - # syntax errors - check_syntax_error(self, 'print ,') - check_syntax_error(self, 'print >> x,') - - def testDelStmt(self): - # 'del' exprlist - abc = [1,2,3] - x, y, z = abc - xyz = x, y, z - - del abc - del x, y, (z, xyz) - - def testPassStmt(self): - # 'pass' - pass - - # flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt - # Tested below - - def testBreakStmt(self): - # 'break' - while 1: break - - def testContinueStmt(self): - # 'continue' - i = 1 - while i: i = 0; continue - - msg = "" - while not msg: - msg = "ok" - try: - continue - msg = "continue failed to continue inside try" - except: - msg = "continue inside try called except block" - if msg != "ok": - self.fail(msg) - - msg = "" - while not msg: - msg = "finally block not called" - try: - continue - finally: - msg = "ok" - if msg != "ok": - self.fail(msg) - - def test_break_continue_loop(self): - # This test warrants an explanation. It is a test specifically for SF bugs - # #463359 and #462937. The bug is that a 'break' statement executed or - # exception raised inside a try/except inside a loop, *after* a continue - # statement has been executed in that loop, will cause the wrong number of - # arguments to be popped off the stack and the instruction pointer reset to - # a very small number (usually 0.) Because of this, the following test - # *must* written as a function, and the tracking vars *must* be function - # arguments with default values. Otherwise, the test will loop and loop. - - def test_inner(extra_burning_oil = 1, count=0): - big_hippo = 2 - while big_hippo: - count += 1 - try: - if extra_burning_oil and big_hippo == 1: - extra_burning_oil -= 1 - break - big_hippo -= 1 - continue - except: - raise - if count > 2 or big_hippo <> 1: - self.fail("continue then break in try/except in loop broken!") - test_inner() - - def testReturn(self): - # 'return' [testlist] - def g1(): return - def g2(): return 1 - g1() - x = g2() - check_syntax_error(self, "class foo:return 1") - - def testYield(self): - check_syntax_error(self, "class foo:yield 1") - - def testRaise(self): - # 'raise' test [',' test] - try: raise RuntimeError, 'just testing' - except RuntimeError: pass - try: raise KeyboardInterrupt - except KeyboardInterrupt: pass - - def testImport(self): - # 'import' dotted_as_names - import sys - import time, sys - # 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names) - from time import time - from time import (time) - # not testable inside a function, but already done at top of the module - # from sys import * - from sys import path, argv - from sys import (path, argv) - from sys import (path, argv,) - - def testGlobal(self): - # 'global' NAME (',' NAME)* - global a - global a, b - global one, two, three, four, five, six, seven, eight, nine, ten - - def testExec(self): - # 'exec' expr ['in' expr [',' expr]] - z = None - del z - exec 'z=1+1\n' - if z != 2: self.fail('exec \'z=1+1\'\\n') - del z - exec 'z=1+1' - if z != 2: self.fail('exec \'z=1+1\'') - z = None - del z - import types - if hasattr(types, "UnicodeType"): - exec r"""if 1: - exec u'z=1+1\n' - if z != 2: self.fail('exec u\'z=1+1\'\\n') - del z - exec u'z=1+1' - if z != 2: self.fail('exec u\'z=1+1\'')""" - g = {} - exec 'z = 1' in g - if g.has_key('__builtins__'): del g['__builtins__'] - if g != {'z': 1}: self.fail('exec \'z = 1\' in g') - g = {} - l = {} - - import warnings - warnings.filterwarnings("ignore", "global statement", module="<string>") - exec 'global a; a = 1; b = 2' in g, l - if g.has_key('__builtins__'): del g['__builtins__'] - if l.has_key('__builtins__'): del l['__builtins__'] - if (g, l) != ({'a':1}, {'b':2}): - self.fail('exec ... in g (%s), l (%s)' %(g,l)) - - def testAssert(self): - # assert_stmt: 'assert' test [',' test] - assert 1 - assert 1, 1 - assert lambda x:x - assert 1, lambda x:x+1 - try: - assert 0, "msg" - except AssertionError, e: - self.assertEquals(e.args[0], "msg") - else: - if __debug__: - self.fail("AssertionError not raised by assert 0") - - ### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef - # Tested below - - def testIf(self): - # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] - if 1: pass - if 1: pass - else: pass - if 0: pass - elif 0: pass - if 0: pass - elif 0: pass - elif 0: pass - elif 0: pass - else: pass - - def testWhile(self): - # 'while' test ':' suite ['else' ':' suite] - while 0: pass - while 0: pass - else: pass - - # Issue1920: "while 0" is optimized away, - # ensure that the "else" clause is still present. - x = 0 - while 0: - x = 1 - else: - x = 2 - self.assertEquals(x, 2) - - def testFor(self): - # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] - for i in 1, 2, 3: pass - for i, j, k in (): pass - else: pass - class Squares: - def __init__(self, max): - self.max = max - self.sofar = [] - def __len__(self): return len(self.sofar) - def __getitem__(self, i): - if not 0 <= i < self.max: raise IndexError - n = len(self.sofar) - while n <= i: - self.sofar.append(n*n) - n = n+1 - return self.sofar[i] - n = 0 - for x in Squares(10): n = n+x - if n != 285: - self.fail('for over growing sequence') - - result = [] - for x, in [(1,), (2,), (3,)]: - result.append(x) - self.assertEqual(result, [1, 2, 3]) - - def testTry(self): - ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] - ### | 'try' ':' suite 'finally' ':' suite - ### except_clause: 'except' [expr [('as' | ',') expr]] - try: - 1/0 - except ZeroDivisionError: - pass - else: - pass - try: 1/0 - except EOFError: pass - except TypeError as msg: pass - except RuntimeError, msg: pass - except: pass - else: pass - try: 1/0 - except (EOFError, TypeError, ZeroDivisionError): pass - try: 1/0 - except (EOFError, TypeError, ZeroDivisionError), msg: pass - try: pass - finally: pass - - def testSuite(self): - # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT - if 1: pass - if 1: - pass - if 1: - # - # - # - pass - pass - # - pass - # - - def testTest(self): - ### and_test ('or' and_test)* - ### and_test: not_test ('and' not_test)* - ### not_test: 'not' not_test | comparison - if not 1: pass - if 1 and 1: pass - if 1 or 1: pass - if not not not 1: pass - if not 1 and 1 and 1: pass - if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass - - def testComparison(self): - ### comparison: expr (comp_op expr)* - ### comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' - if 1: pass - x = (1 == 1) - if 1 == 1: pass - if 1 != 1: pass - if 1 <> 1: pass - if 1 < 1: pass - if 1 > 1: pass - if 1 <= 1: pass - if 1 >= 1: pass - if 1 is 1: pass - if 1 is not 1: pass - if 1 in (): pass - if 1 not in (): pass - if 1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1: pass - - def testBinaryMaskOps(self): - x = 1 & 1 - x = 1 ^ 1 - x = 1 | 1 - - def testShiftOps(self): - x = 1 << 1 - x = 1 >> 1 - x = 1 << 1 >> 1 - - def testAdditiveOps(self): - x = 1 - x = 1 + 1 - x = 1 - 1 - 1 - x = 1 - 1 + 1 - 1 + 1 - - def testMultiplicativeOps(self): - x = 1 * 1 - x = 1 / 1 - x = 1 % 1 - x = 1 / 1 * 1 % 1 - - def testUnaryOps(self): - x = +1 - x = -1 - x = ~1 - x = ~1 ^ 1 & 1 | 1 & 1 ^ -1 - x = -1*1/1 + 1*1 - ---1*1 - - def testSelectors(self): - ### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME - ### subscript: expr | [expr] ':' [expr] - - import sys, time - c = sys.path[0] - x = time.time() - x = sys.modules['time'].time() - a = '01234' - c = a[0] - c = a[-1] - s = a[0:5] - s = a[:5] - s = a[0:] - s = a[:] - s = a[-5:] - s = a[:-1] - s = a[-4:-3] - # A rough test of SF bug 1333982. https://bugs.python.org/issue1333982 - # The testing here is fairly incomplete. - # Test cases should include: commas with 1 and 2 colons - d = {} - d[1] = 1 - d[1,] = 2 - d[1,2] = 3 - d[1,2,3] = 4 - L = list(d) - L.sort() - self.assertEquals(str(L), '[1, (1,), (1, 2), (1, 2, 3)]') - - def testAtoms(self): - ### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING - ### dictmaker: test ':' test (',' test ':' test)* [','] - - x = (1) - x = (1 or 2 or 3) - x = (1 or 2 or 3, 2, 3) - - x = [] - x = [1] - x = [1 or 2 or 3] - x = [1 or 2 or 3, 2, 3] - x = [] - - x = {} - x = {'one': 1} - x = {'one': 1,} - x = {'one' or 'two': 1 or 2} - x = {'one': 1, 'two': 2} - x = {'one': 1, 'two': 2,} - x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} - - x = `x` - x = `1 or 2 or 3` - self.assertEqual(`1,2`, '(1, 2)') - - x = x - x = 'x' - x = 123 - - ### exprlist: expr (',' expr)* [','] - ### testlist: test (',' test)* [','] - # These have been exercised enough above - - def testClassdef(self): - # 'class' NAME ['(' [testlist] ')'] ':' suite - class B: pass - class B2(): pass - class C1(B): pass - class C2(B): pass - class D(C1, C2, B): pass - class C: - def meth1(self): pass - def meth2(self, arg): pass - def meth3(self, a1, a2): pass - # decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE - # decorators: decorator+ - # decorated: decorators (classdef | funcdef) - def class_decorator(x): - x.decorated = True - return x - @class_decorator - class G: - pass - self.assertEqual(G.decorated, True) - - def testListcomps(self): - # list comprehension tests - nums = [1, 2, 3, 4, 5] - strs = ["Apple", "Banana", "Coconut"] - spcs = [" Apple", " Banana ", "Coco nut "] - - self.assertEqual([s.strip() for s in spcs], ['Apple', 'Banana', 'Coco nut']) - self.assertEqual([3 * x for x in nums], [3, 6, 9, 12, 15]) - self.assertEqual([x for x in nums if x > 2], [3, 4, 5]) - self.assertEqual([(i, s) for i in nums for s in strs], - [(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), - (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), - (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), - (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), - (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]) - self.assertEqual([(i, s) for i in nums for s in [f for f in strs if "n" in f]], - [(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), - (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), - (5, 'Banana'), (5, 'Coconut')]) - self.assertEqual([(lambda a:[a**i for i in range(a+1)])(j) for j in range(5)], - [[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]]) - - def test_in_func(l): - return [None < x < 3 for x in l if x > 2] - - self.assertEqual(test_in_func(nums), [False, False, False]) - - def test_nested_front(): - self.assertEqual([[y for y in [x, x + 1]] for x in [1,3,5]], - [[1, 2], [3, 4], [5, 6]]) - - test_nested_front() - - check_syntax_error(self, "[i, s for i in nums for s in strs]") - check_syntax_error(self, "[x if y]") - - suppliers = [ - (1, "Boeing"), - (2, "Ford"), - (3, "Macdonalds") - ] - - parts = [ - (10, "Airliner"), - (20, "Engine"), - (30, "Cheeseburger") - ] - - suppart = [ - (1, 10), (1, 20), (2, 20), (3, 30) - ] - - x = [ - (sname, pname) - for (sno, sname) in suppliers - for (pno, pname) in parts - for (sp_sno, sp_pno) in suppart - if sno == sp_sno and pno == sp_pno - ] - - self.assertEqual(x, [('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), - ('Macdonalds', 'Cheeseburger')]) - - def testGenexps(self): - # generator expression tests - g = ([x for x in range(10)] for x in range(1)) - self.assertEqual(g.next(), [x for x in range(10)]) - try: - g.next() - self.fail('should produce StopIteration exception') - except StopIteration: - pass - - a = 1 - try: - g = (a for d in a) - g.next() - self.fail('should produce TypeError') - except TypeError: - pass - - self.assertEqual(list((x, y) for x in 'abcd' for y in 'abcd'), [(x, y) for x in 'abcd' for y in 'abcd']) - self.assertEqual(list((x, y) for x in 'ab' for y in 'xy'), [(x, y) for x in 'ab' for y in 'xy']) - - a = [x for x in range(10)] - b = (x for x in (y for y in a)) - self.assertEqual(sum(b), sum([x for x in range(10)])) - - self.assertEqual(sum(x**2 for x in range(10)), sum([x**2 for x in range(10)])) - self.assertEqual(sum(x*x for x in range(10) if x%2), sum([x*x for x in range(10) if x%2])) - self.assertEqual(sum(x for x in (y for y in range(10))), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in (y for y in (z for z in range(10)))), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in [y for y in (z for z in range(10))]), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True)) if True), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True) if False) if True), 0) - check_syntax_error(self, "foo(x for x in range(10), 100)") - check_syntax_error(self, "foo(100, x for x in range(10))") - - def testComprehensionSpecials(self): - # test for outmost iterable precomputation - x = 10; g = (i for i in range(x)); x = 5 - self.assertEqual(len(list(g)), 10) - - # This should hold, since we're only precomputing outmost iterable. - x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x)) - x = 5; t = True; - self.assertEqual([(i,j) for i in range(10) for j in range(5)], list(g)) - - # Grammar allows multiple adjacent 'if's in listcomps and genexps, - # even though it's silly. Make sure it works (ifelse broke this.) - self.assertEqual([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7]) - self.assertEqual(list(x for x in range(10) if x % 2 if x % 3), [1, 5, 7]) - - # verify unpacking single element tuples in listcomp/genexp. - self.assertEqual([x for x, in [(4,), (5,), (6,)]], [4, 5, 6]) - self.assertEqual(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9]) - - def test_with_statement(self): - class manager(object): - def __enter__(self): - return (1, 2) - def __exit__(self, *args): - pass - - with manager(): - pass - with manager() as x: - pass - with manager() as (x, y): - pass - with manager(), manager(): - pass - with manager() as x, manager() as y: - pass - with manager() as x, manager(): - pass - - def testIfElseExpr(self): - # Test ifelse expressions in various cases - def _checkeval(msg, ret): - "helper to check that evaluation of expressions is done correctly" - print x - return ret - - self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) - self.assertEqual([ x() for x in (lambda: True, lambda: False) if x() ], [True]) - self.assertEqual([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ], [True]) - self.assertEqual((5 if 1 else _checkeval("check 1", 0)), 5) - self.assertEqual((_checkeval("check 2", 0) if 0 else 5), 5) - self.assertEqual((5 and 6 if 0 else 1), 1) - self.assertEqual(((5 and 6) if 0 else 1), 1) - self.assertEqual((5 and (6 if 1 else 1)), 6) - self.assertEqual((0 or _checkeval("check 3", 2) if 0 else 3), 3) - self.assertEqual((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)), 1) - self.assertEqual((0 or 5 if 1 else _checkeval("check 6", 3)), 5) - self.assertEqual((not 5 if 1 else 1), False) - self.assertEqual((not 5 if 0 else 1), 1) - self.assertEqual((6 + 1 if 1 else 2), 7) - self.assertEqual((6 - 1 if 1 else 2), 5) - self.assertEqual((6 * 2 if 1 else 4), 12) - self.assertEqual((6 / 2 if 1 else 3), 3) - self.assertEqual((6 < 4 if 0 else 2), 2) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_lib2to3/data/py3_test_grammar.py b/Lib/test/test_lib2to3/data/py3_test_grammar.py deleted file mode 100644 index 774851f5bd7e8..0000000000000 --- a/Lib/test/test_lib2to3/data/py3_test_grammar.py +++ /dev/null @@ -1,956 +0,0 @@ -# Python test set -- part 1, grammar. -# This just tests whether the parser accepts them all. - -# NOTE: When you run this test as a script from the command line, you -# get warnings about certain hex/oct constants. Since those are -# issued by the parser, you can't suppress them by adding a -# filterwarnings() call to this module. Therefore, to shut up the -# regression test, the filterwarnings() call has been added to -# regrtest.py. - -from test.support import check_syntax_error -import unittest -import sys -# testing import * -from sys import * - -class TokenTests(unittest.TestCase): - - def testBackslash(self): - # Backslash means line continuation: - x = 1 \ - + 1 - self.assertEquals(x, 2, 'backslash for line continuation') - - # Backslash does not means continuation in comments :\ - x = 0 - self.assertEquals(x, 0, 'backslash ending comment') - - def testPlainIntegers(self): - self.assertEquals(type(000), type(0)) - self.assertEquals(0xff, 255) - self.assertEquals(0o377, 255) - self.assertEquals(2147483647, 0o17777777777) - self.assertEquals(0b1001, 9) - # "0x" is not a valid literal - self.assertRaises(SyntaxError, eval, "0x") - from sys import maxsize - if maxsize == 2147483647: - self.assertEquals(-2147483647-1, -0o20000000000) - # XXX -2147483648 - self.assert_(0o37777777777 > 0) - self.assert_(0xffffffff > 0) - self.assert_(0b1111111111111111111111111111111 > 0) - for s in ('2147483648', '0o40000000000', '0x100000000', - '0b10000000000000000000000000000000'): - try: - x = eval(s) - except OverflowError: - self.fail("OverflowError on huge integer literal %r" % s) - elif maxsize == 9223372036854775807: - self.assertEquals(-9223372036854775807-1, -0o1000000000000000000000) - self.assert_(0o1777777777777777777777 > 0) - self.assert_(0xffffffffffffffff > 0) - self.assert_(0b11111111111111111111111111111111111111111111111111111111111111 > 0) - for s in '9223372036854775808', '0o2000000000000000000000', \ - '0x10000000000000000', \ - '0b100000000000000000000000000000000000000000000000000000000000000': - try: - x = eval(s) - except OverflowError: - self.fail("OverflowError on huge integer literal %r" % s) - else: - self.fail('Weird maxsize value %r' % maxsize) - - def testLongIntegers(self): - x = 0 - x = 0xffffffffffffffff - x = 0Xffffffffffffffff - x = 0o77777777777777777 - x = 0O77777777777777777 - x = 123456789012345678901234567890 - x = 0b100000000000000000000000000000000000000000000000000000000000000000000 - x = 0B111111111111111111111111111111111111111111111111111111111111111111111 - - def testUnderscoresInNumbers(self): - # Integers - x = 1_0 - x = 123_456_7_89 - x = 0xabc_123_4_5 - x = 0X_abc_123 - x = 0B11_01 - x = 0b_11_01 - x = 0o45_67 - x = 0O_45_67 - - # Floats - x = 3_1.4 - x = 03_1.4 - x = 3_1. - x = .3_1 - x = 3.1_4 - x = 0_3.1_4 - x = 3e1_4 - x = 3_1e+4_1 - x = 3_1E-4_1 - - def testFloats(self): - x = 3.14 - x = 314. - x = 0.314 - # XXX x = 000.314 - x = .314 - x = 3e14 - x = 3E14 - x = 3e-14 - x = 3e+14 - x = 3.e14 - x = .3e14 - x = 3.1e4 - - def testStringLiterals(self): - x = ''; y = ""; self.assert_(len(x) == 0 and x == y) - x = '\''; y = "'"; self.assert_(len(x) == 1 and x == y and ord(x) == 39) - x = '"'; y = "\""; self.assert_(len(x) == 1 and x == y and ord(x) == 34) - x = "doesn't \"shrink\" does it" - y = 'doesn\'t "shrink" does it' - self.assert_(len(x) == 24 and x == y) - x = "does \"shrink\" doesn't it" - y = 'does "shrink" doesn\'t it' - self.assert_(len(x) == 24 and x == y) - x = """ -The "quick" -brown fox -jumps over -the 'lazy' dog. -""" - y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n' - self.assertEquals(x, y) - y = ''' -The "quick" -brown fox -jumps over -the 'lazy' dog. -''' - self.assertEquals(x, y) - y = "\n\ -The \"quick\"\n\ -brown fox\n\ -jumps over\n\ -the 'lazy' dog.\n\ -" - self.assertEquals(x, y) - y = '\n\ -The \"quick\"\n\ -brown fox\n\ -jumps over\n\ -the \'lazy\' dog.\n\ -' - self.assertEquals(x, y) - x = rf"hello \{True}"; y = f"hello \\{True}" - self.assertEquals(x, y) - - def testEllipsis(self): - x = ... - self.assert_(x is Ellipsis) - self.assertRaises(SyntaxError, eval, ".. .") - -class GrammarTests(unittest.TestCase): - - # single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE - # XXX can't test in a script -- this rule is only used when interactive - - # file_input: (NEWLINE | stmt)* ENDMARKER - # Being tested as this very moment this very module - - # expr_input: testlist NEWLINE - # XXX Hard to test -- used only in calls to input() - - def testEvalInput(self): - # testlist ENDMARKER - x = eval('1, 0 or 1') - - def testFuncdef(self): - ### [decorators] 'def' NAME parameters ['->' test] ':' suite - ### decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE - ### decorators: decorator+ - ### parameters: '(' [typedargslist] ')' - ### typedargslist: ((tfpdef ['=' test] ',')* - ### ('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef) - ### | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) - ### tfpdef: NAME [':' test] - ### varargslist: ((vfpdef ['=' test] ',')* - ### ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef) - ### | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) - ### vfpdef: NAME - def f1(): pass - f1() - f1(*()) - f1(*(), **{}) - def f2(one_argument): pass - def f3(two, arguments): pass - self.assertEquals(f2.__code__.co_varnames, ('one_argument',)) - self.assertEquals(f3.__code__.co_varnames, ('two', 'arguments')) - def a1(one_arg,): pass - def a2(two, args,): pass - def v0(*rest): pass - def v1(a, *rest): pass - def v2(a, b, *rest): pass - - f1() - f2(1) - f2(1,) - f3(1, 2) - f3(1, 2,) - v0() - v0(1) - v0(1,) - v0(1,2) - v0(1,2,3,4,5,6,7,8,9,0) - v1(1) - v1(1,) - v1(1,2) - v1(1,2,3) - v1(1,2,3,4,5,6,7,8,9,0) - v2(1,2) - v2(1,2,3) - v2(1,2,3,4) - v2(1,2,3,4,5,6,7,8,9,0) - - def d01(a=1): pass - d01() - d01(1) - d01(*(1,)) - d01(**{'a':2}) - def d11(a, b=1): pass - d11(1) - d11(1, 2) - d11(1, **{'b':2}) - def d21(a, b, c=1): pass - d21(1, 2) - d21(1, 2, 3) - d21(*(1, 2, 3)) - d21(1, *(2, 3)) - d21(1, 2, *(3,)) - d21(1, 2, **{'c':3}) - def d02(a=1, b=2): pass - d02() - d02(1) - d02(1, 2) - d02(*(1, 2)) - d02(1, *(2,)) - d02(1, **{'b':2}) - d02(**{'a': 1, 'b': 2}) - def d12(a, b=1, c=2): pass - d12(1) - d12(1, 2) - d12(1, 2, 3) - def d22(a, b, c=1, d=2): pass - d22(1, 2) - d22(1, 2, 3) - d22(1, 2, 3, 4) - def d01v(a=1, *rest): pass - d01v() - d01v(1) - d01v(1, 2) - d01v(*(1, 2, 3, 4)) - d01v(*(1,)) - d01v(**{'a':2}) - def d11v(a, b=1, *rest): pass - d11v(1) - d11v(1, 2) - d11v(1, 2, 3) - def d21v(a, b, c=1, *rest): pass - d21v(1, 2) - d21v(1, 2, 3) - d21v(1, 2, 3, 4) - d21v(*(1, 2, 3, 4)) - d21v(1, 2, **{'c': 3}) - def d02v(a=1, b=2, *rest): pass - d02v() - d02v(1) - d02v(1, 2) - d02v(1, 2, 3) - d02v(1, *(2, 3, 4)) - d02v(**{'a': 1, 'b': 2}) - def d12v(a, b=1, c=2, *rest): pass - d12v(1) - d12v(1, 2) - d12v(1, 2, 3) - d12v(1, 2, 3, 4) - d12v(*(1, 2, 3, 4)) - d12v(1, 2, *(3, 4, 5)) - d12v(1, *(2,), **{'c': 3}) - def d22v(a, b, c=1, d=2, *rest): pass - d22v(1, 2) - d22v(1, 2, 3) - d22v(1, 2, 3, 4) - d22v(1, 2, 3, 4, 5) - d22v(*(1, 2, 3, 4)) - d22v(1, 2, *(3, 4, 5)) - d22v(1, *(2, 3), **{'d': 4}) - - # keyword argument type tests - try: - str('x', **{b'foo':1 }) - except TypeError: - pass - else: - self.fail('Bytes should not work as keyword argument names') - # keyword only argument tests - def pos0key1(*, key): return key - pos0key1(key=100) - def pos2key2(p1, p2, *, k1, k2=100): return p1,p2,k1,k2 - pos2key2(1, 2, k1=100) - pos2key2(1, 2, k1=100, k2=200) - pos2key2(1, 2, k2=100, k1=200) - def pos2key2dict(p1, p2, *, k1=100, k2, **kwarg): return p1,p2,k1,k2,kwarg - pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200) - pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100) - - # keyword arguments after *arglist - def f(*args, **kwargs): - return args, kwargs - self.assertEquals(f(1, x=2, *[3, 4], y=5), ((1, 3, 4), - {'x':2, 'y':5})) - self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)") - self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)") - - # argument annotation tests - def f(x) -> list: pass - self.assertEquals(f.__annotations__, {'return': list}) - def f(x:int): pass - self.assertEquals(f.__annotations__, {'x': int}) - def f(*x:str): pass - self.assertEquals(f.__annotations__, {'x': str}) - def f(**x:float): pass - self.assertEquals(f.__annotations__, {'x': float}) - def f(x, y:1+2): pass - self.assertEquals(f.__annotations__, {'y': 3}) - def f(a, b:1, c:2, d): pass - self.assertEquals(f.__annotations__, {'b': 1, 'c': 2}) - def f(a, b:1, c:2, d, e:3=4, f=5, *g:6): pass - self.assertEquals(f.__annotations__, - {'b': 1, 'c': 2, 'e': 3, 'g': 6}) - def f(a, b:1, c:2, d, e:3=4, f=5, *g:6, h:7, i=8, j:9=10, - **k:11) -> 12: pass - self.assertEquals(f.__annotations__, - {'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9, - 'k': 11, 'return': 12}) - # Check for SF Bug #1697248 - mixing decorators and a return annotation - def null(x): return x - @null - def f(x) -> list: pass - self.assertEquals(f.__annotations__, {'return': list}) - - # test closures with a variety of oparg's - closure = 1 - def f(): return closure - def f(x=1): return closure - def f(*, k=1): return closure - def f() -> int: return closure - - # Check ast errors in *args and *kwargs - check_syntax_error(self, "f(*g(1=2))") - check_syntax_error(self, "f(**g(1=2))") - - def testLambdef(self): - ### lambdef: 'lambda' [varargslist] ':' test - l1 = lambda : 0 - self.assertEquals(l1(), 0) - l2 = lambda : a[d] # XXX just testing the expression - l3 = lambda : [2 < x for x in [-1, 3, 0]] - self.assertEquals(l3(), [0, 1, 0]) - l4 = lambda x = lambda y = lambda z=1 : z : y() : x() - self.assertEquals(l4(), 1) - l5 = lambda x, y, z=2: x + y + z - self.assertEquals(l5(1, 2), 5) - self.assertEquals(l5(1, 2, 3), 6) - check_syntax_error(self, "lambda x: x = 2") - check_syntax_error(self, "lambda (None,): None") - l6 = lambda x, y, *, k=20: x+y+k - self.assertEquals(l6(1,2), 1+2+20) - self.assertEquals(l6(1,2,k=10), 1+2+10) - - - ### stmt: simple_stmt | compound_stmt - # Tested below - - def testSimpleStmt(self): - ### simple_stmt: small_stmt (';' small_stmt)* [';'] - x = 1; pass; del x - def foo(): - # verify statements that end with semi-colons - x = 1; pass; del x; - foo() - - ### small_stmt: expr_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt - # Tested below - - def testExprStmt(self): - # (exprlist '=')* exprlist - 1 - 1, 2, 3 - x = 1 - x = 1, 2, 3 - x = y = z = 1, 2, 3 - x, y, z = 1, 2, 3 - abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) - - check_syntax_error(self, "x + 1 = 1") - check_syntax_error(self, "a + 1 = b + 2") - - def testDelStmt(self): - # 'del' exprlist - abc = [1,2,3] - x, y, z = abc - xyz = x, y, z - - del abc - del x, y, (z, xyz) - - def testPassStmt(self): - # 'pass' - pass - - # flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt - # Tested below - - def testBreakStmt(self): - # 'break' - while 1: break - - def testContinueStmt(self): - # 'continue' - i = 1 - while i: i = 0; continue - - msg = "" - while not msg: - msg = "ok" - try: - continue - msg = "continue failed to continue inside try" - except: - msg = "continue inside try called except block" - if msg != "ok": - self.fail(msg) - - msg = "" - while not msg: - msg = "finally block not called" - try: - continue - finally: - msg = "ok" - if msg != "ok": - self.fail(msg) - - def test_break_continue_loop(self): - # This test warrants an explanation. It is a test specifically for SF bugs - # #463359 and #462937. The bug is that a 'break' statement executed or - # exception raised inside a try/except inside a loop, *after* a continue - # statement has been executed in that loop, will cause the wrong number of - # arguments to be popped off the stack and the instruction pointer reset to - # a very small number (usually 0.) Because of this, the following test - # *must* written as a function, and the tracking vars *must* be function - # arguments with default values. Otherwise, the test will loop and loop. - - def test_inner(extra_burning_oil = 1, count=0): - big_hippo = 2 - while big_hippo: - count += 1 - try: - if extra_burning_oil and big_hippo == 1: - extra_burning_oil -= 1 - break - big_hippo -= 1 - continue - except: - raise - if count > 2 or big_hippo != 1: - self.fail("continue then break in try/except in loop broken!") - test_inner() - - def testReturn(self): - # 'return' [testlist_star_expr] - def g1(): return - def g2(): return 1 - return_list = [2, 3] - def g3(): return 1, *return_list - g1() - x = g2() - x3 = g3() - check_syntax_error(self, "class foo:return 1") - - def testYield(self): - # 'yield' [yield_arg] - def g1(): yield 1 - yield_list = [2, 3] - def g2(): yield 1, *yield_list - def g3(): yield from iter(yield_list) - x1 = g1() - x2 = g2() - x3 = g3() - check_syntax_error(self, "class foo:yield 1") - check_syntax_error(self, "def g4(): yield from *a") - - def testRaise(self): - # 'raise' test [',' test] - try: raise RuntimeError('just testing') - except RuntimeError: pass - try: raise KeyboardInterrupt - except KeyboardInterrupt: pass - - def testImport(self): - # 'import' dotted_as_names - import sys - import time, sys - # 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names) - from time import time - from time import (time) - # not testable inside a function, but already done at top of the module - # from sys import * - from sys import path, argv - from sys import (path, argv) - from sys import (path, argv,) - - def testGlobal(self): - # 'global' NAME (',' NAME)* - global a - global a, b - global one, two, three, four, five, six, seven, eight, nine, ten - - def testNonlocal(self): - # 'nonlocal' NAME (',' NAME)* - x = 0 - y = 0 - def f(): - nonlocal x - nonlocal x, y - - def testAssert(self): - # assert_stmt: 'assert' test [',' test] - assert 1 - assert 1, 1 - assert lambda x:x - assert 1, lambda x:x+1 - try: - assert 0, "msg" - except AssertionError as e: - self.assertEquals(e.args[0], "msg") - else: - if __debug__: - self.fail("AssertionError not raised by assert 0") - - ### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef - # Tested below - - def testIf(self): - # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] - if 1: pass - if 1: pass - else: pass - if 0: pass - elif 0: pass - if 0: pass - elif 0: pass - elif 0: pass - elif 0: pass - else: pass - - def testWhile(self): - # 'while' test ':' suite ['else' ':' suite] - while 0: pass - while 0: pass - else: pass - - # Issue1920: "while 0" is optimized away, - # ensure that the "else" clause is still present. - x = 0 - while 0: - x = 1 - else: - x = 2 - self.assertEquals(x, 2) - - def testFor(self): - # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] - for i in 1, 2, 3: pass - for i, j, k in (): pass - else: pass - class Squares: - def __init__(self, max): - self.max = max - self.sofar = [] - def __len__(self): return len(self.sofar) - def __getitem__(self, i): - if not 0 <= i < self.max: raise IndexError - n = len(self.sofar) - while n <= i: - self.sofar.append(n*n) - n = n+1 - return self.sofar[i] - n = 0 - for x in Squares(10): n = n+x - if n != 285: - self.fail('for over growing sequence') - - result = [] - for x, in [(1,), (2,), (3,)]: - result.append(x) - self.assertEqual(result, [1, 2, 3]) - - def testTry(self): - ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] - ### | 'try' ':' suite 'finally' ':' suite - ### except_clause: 'except' [expr ['as' expr]] - try: - 1/0 - except ZeroDivisionError: - pass - else: - pass - try: 1/0 - except EOFError: pass - except TypeError as msg: pass - except RuntimeError as msg: pass - except: pass - else: pass - try: 1/0 - except (EOFError, TypeError, ZeroDivisionError): pass - try: 1/0 - except (EOFError, TypeError, ZeroDivisionError) as msg: pass - try: pass - finally: pass - - def testSuite(self): - # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT - if 1: pass - if 1: - pass - if 1: - # - # - # - pass - pass - # - pass - # - - def testTest(self): - ### and_test ('or' and_test)* - ### and_test: not_test ('and' not_test)* - ### not_test: 'not' not_test | comparison - if not 1: pass - if 1 and 1: pass - if 1 or 1: pass - if not not not 1: pass - if not 1 and 1 and 1: pass - if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass - - def testComparison(self): - ### comparison: expr (comp_op expr)* - ### comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not' - if 1: pass - x = (1 == 1) - if 1 == 1: pass - if 1 != 1: pass - if 1 < 1: pass - if 1 > 1: pass - if 1 <= 1: pass - if 1 >= 1: pass - if 1 is 1: pass - if 1 is not 1: pass - if 1 in (): pass - if 1 not in (): pass - if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1: pass - - def testBinaryMaskOps(self): - x = 1 & 1 - x = 1 ^ 1 - x = 1 | 1 - - def testShiftOps(self): - x = 1 << 1 - x = 1 >> 1 - x = 1 << 1 >> 1 - - def testAdditiveOps(self): - x = 1 - x = 1 + 1 - x = 1 - 1 - 1 - x = 1 - 1 + 1 - 1 + 1 - - def testMultiplicativeOps(self): - x = 1 * 1 - x = 1 / 1 - x = 1 % 1 - x = 1 / 1 * 1 % 1 - - def testUnaryOps(self): - x = +1 - x = -1 - x = ~1 - x = ~1 ^ 1 & 1 | 1 & 1 ^ -1 - x = -1*1/1 + 1*1 - ---1*1 - - def testSelectors(self): - ### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME - ### subscript: expr | [expr] ':' [expr] - - import sys, time - c = sys.path[0] - x = time.time() - x = sys.modules['time'].time() - a = '01234' - c = a[0] - c = a[-1] - s = a[0:5] - s = a[:5] - s = a[0:] - s = a[:] - s = a[-5:] - s = a[:-1] - s = a[-4:-3] - # A rough test of SF bug 1333982. https://bugs.python.org/issue1333982 - # The testing here is fairly incomplete. - # Test cases should include: commas with 1 and 2 colons - d = {} - d[1] = 1 - d[1,] = 2 - d[1,2] = 3 - d[1,2,3] = 4 - L = list(d) - L.sort(key=lambda x: x if isinstance(x, tuple) else ()) - self.assertEquals(str(L), '[1, (1,), (1, 2), (1, 2, 3)]') - - def testAtoms(self): - ### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictsetmaker] '}' | NAME | NUMBER | STRING - ### dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [',']) - - x = (1) - x = (1 or 2 or 3) - x = (1 or 2 or 3, 2, 3) - - x = [] - x = [1] - x = [1 or 2 or 3] - x = [1 or 2 or 3, 2, 3] - x = [] - - x = {} - x = {'one': 1} - x = {'one': 1,} - x = {'one' or 'two': 1 or 2} - x = {'one': 1, 'two': 2} - x = {'one': 1, 'two': 2,} - x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} - - x = {'one'} - x = {'one', 1,} - x = {'one', 'two', 'three'} - x = {2, 3, 4,} - - x = x - x = 'x' - x = 123 - - ### exprlist: expr (',' expr)* [','] - ### testlist: test (',' test)* [','] - # These have been exercised enough above - - def testClassdef(self): - # 'class' NAME ['(' [testlist] ')'] ':' suite - class B: pass - class B2(): pass - class C1(B): pass - class C2(B): pass - class D(C1, C2, B): pass - class C: - def meth1(self): pass - def meth2(self, arg): pass - def meth3(self, a1, a2): pass - - # decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE - # decorators: decorator+ - # decorated: decorators (classdef | funcdef) - def class_decorator(x): return x - @class_decorator - class G: pass - - def testDictcomps(self): - # dictorsetmaker: ( (test ':' test (comp_for | - # (',' test ':' test)* [','])) | - # (test (comp_for | (',' test)* [','])) ) - nums = [1, 2, 3] - self.assertEqual({i:i+1 for i in nums}, {1: 2, 2: 3, 3: 4}) - - def testListcomps(self): - # list comprehension tests - nums = [1, 2, 3, 4, 5] - strs = ["Apple", "Banana", "Coconut"] - spcs = [" Apple", " Banana ", "Coco nut "] - - self.assertEqual([s.strip() for s in spcs], ['Apple', 'Banana', 'Coco nut']) - self.assertEqual([3 * x for x in nums], [3, 6, 9, 12, 15]) - self.assertEqual([x for x in nums if x > 2], [3, 4, 5]) - self.assertEqual([(i, s) for i in nums for s in strs], - [(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), - (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), - (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), - (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), - (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]) - self.assertEqual([(i, s) for i in nums for s in [f for f in strs if "n" in f]], - [(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), - (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), - (5, 'Banana'), (5, 'Coconut')]) - self.assertEqual([(lambda a:[a**i for i in range(a+1)])(j) for j in range(5)], - [[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]]) - - def test_in_func(l): - return [0 < x < 3 for x in l if x > 2] - - self.assertEqual(test_in_func(nums), [False, False, False]) - - def test_nested_front(): - self.assertEqual([[y for y in [x, x + 1]] for x in [1,3,5]], - [[1, 2], [3, 4], [5, 6]]) - - test_nested_front() - - check_syntax_error(self, "[i, s for i in nums for s in strs]") - check_syntax_error(self, "[x if y]") - - suppliers = [ - (1, "Boeing"), - (2, "Ford"), - (3, "Macdonalds") - ] - - parts = [ - (10, "Airliner"), - (20, "Engine"), - (30, "Cheeseburger") - ] - - suppart = [ - (1, 10), (1, 20), (2, 20), (3, 30) - ] - - x = [ - (sname, pname) - for (sno, sname) in suppliers - for (pno, pname) in parts - for (sp_sno, sp_pno) in suppart - if sno == sp_sno and pno == sp_pno - ] - - self.assertEqual(x, [('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), - ('Macdonalds', 'Cheeseburger')]) - - def testGenexps(self): - # generator expression tests - g = ([x for x in range(10)] for x in range(1)) - self.assertEqual(next(g), [x for x in range(10)]) - try: - next(g) - self.fail('should produce StopIteration exception') - except StopIteration: - pass - - a = 1 - try: - g = (a for d in a) - next(g) - self.fail('should produce TypeError') - except TypeError: - pass - - self.assertEqual(list((x, y) for x in 'abcd' for y in 'abcd'), [(x, y) for x in 'abcd' for y in 'abcd']) - self.assertEqual(list((x, y) for x in 'ab' for y in 'xy'), [(x, y) for x in 'ab' for y in 'xy']) - - a = [x for x in range(10)] - b = (x for x in (y for y in a)) - self.assertEqual(sum(b), sum([x for x in range(10)])) - - self.assertEqual(sum(x**2 for x in range(10)), sum([x**2 for x in range(10)])) - self.assertEqual(sum(x*x for x in range(10) if x%2), sum([x*x for x in range(10) if x%2])) - self.assertEqual(sum(x for x in (y for y in range(10))), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in (y for y in (z for z in range(10)))), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in [y for y in (z for z in range(10))]), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True)) if True), sum([x for x in range(10)])) - self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True) if False) if True), 0) - check_syntax_error(self, "foo(x for x in range(10), 100)") - check_syntax_error(self, "foo(100, x for x in range(10))") - - def testComprehensionSpecials(self): - # test for outmost iterable precomputation - x = 10; g = (i for i in range(x)); x = 5 - self.assertEqual(len(list(g)), 10) - - # This should hold, since we're only precomputing outmost iterable. - x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x)) - x = 5; t = True; - self.assertEqual([(i,j) for i in range(10) for j in range(5)], list(g)) - - # Grammar allows multiple adjacent 'if's in listcomps and genexps, - # even though it's silly. Make sure it works (ifelse broke this.) - self.assertEqual([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7]) - self.assertEqual(list(x for x in range(10) if x % 2 if x % 3), [1, 5, 7]) - - # verify unpacking single element tuples in listcomp/genexp. - self.assertEqual([x for x, in [(4,), (5,), (6,)]], [4, 5, 6]) - self.assertEqual(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9]) - - def test_with_statement(self): - class manager(object): - def __enter__(self): - return (1, 2) - def __exit__(self, *args): - pass - - with manager(): - pass - with manager() as x: - pass - with manager() as (x, y): - pass - with manager(), manager(): - pass - with manager() as x, manager() as y: - pass - with manager() as x, manager(): - pass - - def testIfElseExpr(self): - # Test ifelse expressions in various cases - def _checkeval(msg, ret): - "helper to check that evaluation of expressions is done correctly" - print(x) - return ret - - # the next line is not allowed anymore - #self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) - self.assertEqual([ x() for x in (lambda: True, lambda: False) if x() ], [True]) - self.assertEqual([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ], [True]) - self.assertEqual((5 if 1 else _checkeval("check 1", 0)), 5) - self.assertEqual((_checkeval("check 2", 0) if 0 else 5), 5) - self.assertEqual((5 and 6 if 0 else 1), 1) - self.assertEqual(((5 and 6) if 0 else 1), 1) - self.assertEqual((5 and (6 if 1 else 1)), 6) - self.assertEqual((0 or _checkeval("check 3", 2) if 0 else 3), 3) - self.assertEqual((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)), 1) - self.assertEqual((0 or 5 if 1 else _checkeval("check 6", 3)), 5) - self.assertEqual((not 5 if 1 else 1), False) - self.assertEqual((not 5 if 0 else 1), 1) - self.assertEqual((6 + 1 if 1 else 2), 7) - self.assertEqual((6 - 1 if 1 else 2), 5) - self.assertEqual((6 * 2 if 1 else 4), 12) - self.assertEqual((6 / 2 if 1 else 3), 3) - self.assertEqual((6 < 4 if 0 else 2), 2) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_lib2to3/pytree_idempotency.py b/Lib/test/test_lib2to3/pytree_idempotency.py deleted file mode 100755 index eb2e2aa02ae0e..0000000000000 --- a/Lib/test/test_lib2to3/pytree_idempotency.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Main program for testing the infrastructure.""" - -from __future__ import print_function - -__author__ = "Guido van Rossum <guido at python.org>" - -# Support imports (need to be imported first) -from . import support - -# Python imports -import os -import sys -import logging - -# Local imports -from lib2to3 import pytree -from lib2to3 import pgen2 -from lib2to3.pgen2 import driver - -logging.basicConfig() - -def main(): - gr = driver.load_grammar("Grammar.txt") - dr = driver.Driver(gr, convert=pytree.convert) - - fn = "example.py" - tree = dr.parse_file(fn, debug=True) - if not diff(fn, tree): - print("No diffs.") - if not sys.argv[1:]: - return # Pass a dummy argument to run the complete test suite below - - problems = [] - - # Process every imported module - for name in sys.modules: - mod = sys.modules[name] - if mod is None or not hasattr(mod, "__file__"): - continue - fn = mod.__file__ - if fn.endswith(".pyc"): - fn = fn[:-1] - if not fn.endswith(".py"): - continue - print("Parsing", fn, file=sys.stderr) - tree = dr.parse_file(fn, debug=True) - if diff(fn, tree): - problems.append(fn) - - # Process every single module on sys.path (but not in packages) - for dir in sys.path: - try: - names = os.listdir(dir) - except OSError: - continue - print("Scanning", dir, "...", file=sys.stderr) - for name in names: - if not name.endswith(".py"): - continue - print("Parsing", name, file=sys.stderr) - fn = os.path.join(dir, name) - try: - tree = dr.parse_file(fn, debug=True) - except pgen2.parse.ParseError as err: - print("ParseError:", err) - else: - if diff(fn, tree): - problems.append(fn) - - # Show summary of problem files - if not problems: - print("No problems. Congratulations!") - else: - print("Problems in following files:") - for fn in problems: - print("***", fn) - -def diff(fn, tree): - f = open("@", "w") - try: - f.write(str(tree)) - finally: - f.close() - try: - return os.system("diff -u %s @" % fn) - finally: - os.remove("@") - -if __name__ == "__main__": - main() diff --git a/Lib/test/test_lib2to3/support.py b/Lib/test/test_lib2to3/support.py deleted file mode 100644 index 9e56273e95992..0000000000000 --- a/Lib/test/test_lib2to3/support.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Support code for test_*.py files""" -# Author: Collin Winter - -# Python imports -import unittest -import os -import os.path -from textwrap import dedent - -# Local imports -import lib2to3 -from lib2to3 import pytree, refactor -from lib2to3.pgen2 import driver as pgen2_driver - -lib2to3_dir = os.path.dirname(lib2to3.__file__) -test_dir = os.path.dirname(__file__) -proj_dir = os.path.normpath(os.path.join(test_dir, "..")) -grammar_path = os.path.join(lib2to3_dir, "Grammar.txt") -grammar = pgen2_driver.load_grammar(grammar_path) -grammar_no_print_statement = pgen2_driver.load_grammar(grammar_path) -del grammar_no_print_statement.keywords["print"] -driver = pgen2_driver.Driver(grammar, convert=pytree.convert) -driver_no_print_statement = pgen2_driver.Driver( - grammar_no_print_statement, - convert=pytree.convert -) - -def parse_string(string): - return driver.parse_string(reformat(string), debug=True) - -def run_all_tests(test_mod=None, tests=None): - if tests is None: - tests = unittest.TestLoader().loadTestsFromModule(test_mod) - unittest.TextTestRunner(verbosity=2).run(tests) - -def reformat(string): - return dedent(string) + "\n\n" - -def get_refactorer(fixer_pkg="lib2to3", fixers=None, options=None): - """ - A convenience function for creating a RefactoringTool for tests. - - fixers is a list of fixers for the RefactoringTool to use. By default - "lib2to3.fixes.*" is used. options is an optional dictionary of options to - be passed to the RefactoringTool. - """ - if fixers is not None: - fixers = [fixer_pkg + ".fixes.fix_" + fix for fix in fixers] - else: - fixers = refactor.get_fixers_from_package(fixer_pkg + ".fixes") - options = options or {} - return refactor.RefactoringTool(fixers, options, explicit=True) - -def _all_project_files(root, files): - for dirpath, dirnames, filenames in os.walk(root): - for filename in filenames: - if not filename.endswith(".py"): - continue - files.append(os.path.join(dirpath, filename)) - -def all_project_files(): - files = [] - _all_project_files(lib2to3_dir, files) - _all_project_files(test_dir, files) - # Sort to get more reproducible tests - files.sort() - return files - -TestCase = unittest.TestCase diff --git a/Lib/test/test_lib2to3/test_all_fixers.py b/Lib/test/test_lib2to3/test_all_fixers.py deleted file mode 100644 index d0fca7072482c..0000000000000 --- a/Lib/test/test_lib2to3/test_all_fixers.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Tests that run all fixer modules over an input stream. - -This has been broken out into its own test module because of its -running time. -""" -# Author: Collin Winter - -# Python imports -import os.path -import test.support -import unittest - -# Local imports -from . import support - - - at test.support.requires_resource('cpu') -class Test_all(support.TestCase): - - def setUp(self): - self.refactor = support.get_refactorer() - - def refactor_file(self, filepath): - if test.support.verbose: - print(f"Refactor file: {filepath}") - if os.path.basename(filepath) == 'infinite_recursion.py': - # bpo-46542: Processing infinite_recursion.py can crash Python - # if Python is built in debug mode: lower the recursion limit - # to prevent a crash. - with test.support.infinite_recursion(150): - self.refactor.refactor_file(filepath) - else: - self.refactor.refactor_file(filepath) - - def test_all_project_files(self): - for filepath in support.all_project_files(): - with self.subTest(filepath=filepath): - self.refactor_file(filepath) - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_lib2to3/test_fixers.py b/Lib/test/test_lib2to3/test_fixers.py deleted file mode 100644 index 68efeee7abb4d..0000000000000 --- a/Lib/test/test_lib2to3/test_fixers.py +++ /dev/null @@ -1,4649 +0,0 @@ -""" Test suite for the fixer modules """ - -# Python imports -import os -from itertools import chain -from operator import itemgetter - -# Local imports -from lib2to3 import pygram, fixer_util -from test.test_lib2to3 import support - - -class FixerTestCase(support.TestCase): - - # Other test cases can subclass this class and replace "fixer_pkg" with - # their own. - def setUp(self, fix_list=None, fixer_pkg="lib2to3", options=None): - if fix_list is None: - fix_list = [self.fixer] - self.refactor = support.get_refactorer(fixer_pkg, fix_list, options) - self.fixer_log = [] - self.filename = "<string>" - - for fixer in chain(self.refactor.pre_order, - self.refactor.post_order): - fixer.log = self.fixer_log - - def _check(self, before, after): - before = support.reformat(before) - after = support.reformat(after) - tree = self.refactor.refactor_string(before, self.filename) - self.assertEqual(after, str(tree)) - return tree - - def check(self, before, after, ignore_warnings=False): - tree = self._check(before, after) - self.assertTrue(tree.was_changed) - if not ignore_warnings: - self.assertEqual(self.fixer_log, []) - - def warns(self, before, after, message, unchanged=False): - tree = self._check(before, after) - self.assertIn(message, "".join(self.fixer_log)) - if not unchanged: - self.assertTrue(tree.was_changed) - - def warns_unchanged(self, before, message): - self.warns(before, before, message, unchanged=True) - - def unchanged(self, before, ignore_warnings=False): - self._check(before, before) - if not ignore_warnings: - self.assertEqual(self.fixer_log, []) - - def assert_runs_after(self, *names): - fixes = [self.fixer] - fixes.extend(names) - r = support.get_refactorer("lib2to3", fixes) - (pre, post) = r.get_fixers() - n = "fix_" + self.fixer - if post and post[-1].__class__.__module__.endswith(n): - # We're the last fixer to run - return - if pre and pre[-1].__class__.__module__.endswith(n) and not post: - # We're the last in pre and post is empty - return - self.fail("Fixer run order (%s) is incorrect; %s should be last."\ - %(", ".join([x.__class__.__module__ for x in (pre+post)]), n)) - -class Test_ne(FixerTestCase): - fixer = "ne" - - def test_basic(self): - b = """if x <> y: - pass""" - - a = """if x != y: - pass""" - self.check(b, a) - - def test_no_spaces(self): - b = """if x<>y: - pass""" - - a = """if x!=y: - pass""" - self.check(b, a) - - def test_chained(self): - b = """if x<>y<>z: - pass""" - - a = """if x!=y!=z: - pass""" - self.check(b, a) - -class Test_has_key(FixerTestCase): - fixer = "has_key" - - def test_1(self): - b = """x = d.has_key("x") or d.has_key("y")""" - a = """x = "x" in d or "y" in d""" - self.check(b, a) - - def test_2(self): - b = """x = a.b.c.d.has_key("x") ** 3""" - a = """x = ("x" in a.b.c.d) ** 3""" - self.check(b, a) - - def test_3(self): - b = """x = a.b.has_key(1 + 2).__repr__()""" - a = """x = (1 + 2 in a.b).__repr__()""" - self.check(b, a) - - def test_4(self): - b = """x = a.b.has_key(1 + 2).__repr__() ** -3 ** 4""" - a = """x = (1 + 2 in a.b).__repr__() ** -3 ** 4""" - self.check(b, a) - - def test_5(self): - b = """x = a.has_key(f or g)""" - a = """x = (f or g) in a""" - self.check(b, a) - - def test_6(self): - b = """x = a + b.has_key(c)""" - a = """x = a + (c in b)""" - self.check(b, a) - - def test_7(self): - b = """x = a.has_key(lambda: 12)""" - a = """x = (lambda: 12) in a""" - self.check(b, a) - - def test_8(self): - b = """x = a.has_key(a for a in b)""" - a = """x = (a for a in b) in a""" - self.check(b, a) - - def test_9(self): - b = """if not a.has_key(b): pass""" - a = """if b not in a: pass""" - self.check(b, a) - - def test_10(self): - b = """if not a.has_key(b).__repr__(): pass""" - a = """if not (b in a).__repr__(): pass""" - self.check(b, a) - - def test_11(self): - b = """if not a.has_key(b) ** 2: pass""" - a = """if not (b in a) ** 2: pass""" - self.check(b, a) - -class Test_apply(FixerTestCase): - fixer = "apply" - - def test_1(self): - b = """x = apply(f, g + h)""" - a = """x = f(*g + h)""" - self.check(b, a) - - def test_2(self): - b = """y = apply(f, g, h)""" - a = """y = f(*g, **h)""" - self.check(b, a) - - def test_3(self): - b = """z = apply(fs[0], g or h, h or g)""" - a = """z = fs[0](*g or h, **h or g)""" - self.check(b, a) - - def test_4(self): - b = """apply(f, (x, y) + t)""" - a = """f(*(x, y) + t)""" - self.check(b, a) - - def test_5(self): - b = """apply(f, args,)""" - a = """f(*args)""" - self.check(b, a) - - def test_6(self): - b = """apply(f, args, kwds,)""" - a = """f(*args, **kwds)""" - self.check(b, a) - - # Test that complex functions are parenthesized - - def test_complex_1(self): - b = """x = apply(f+g, args)""" - a = """x = (f+g)(*args)""" - self.check(b, a) - - def test_complex_2(self): - b = """x = apply(f*g, args)""" - a = """x = (f*g)(*args)""" - self.check(b, a) - - def test_complex_3(self): - b = """x = apply(f**g, args)""" - a = """x = (f**g)(*args)""" - self.check(b, a) - - # But dotted names etc. not - - def test_dotted_name(self): - b = """x = apply(f.g, args)""" - a = """x = f.g(*args)""" - self.check(b, a) - - def test_subscript(self): - b = """x = apply(f[x], args)""" - a = """x = f[x](*args)""" - self.check(b, a) - - def test_call(self): - b = """x = apply(f(), args)""" - a = """x = f()(*args)""" - self.check(b, a) - - # Extreme case - def test_extreme(self): - b = """x = apply(a.b.c.d.e.f, args, kwds)""" - a = """x = a.b.c.d.e.f(*args, **kwds)""" - self.check(b, a) - - # XXX Comments in weird places still get lost - def test_weird_comments(self): - b = """apply( # foo - f, # bar - args)""" - a = """f(*args)""" - self.check(b, a) - - # These should *not* be touched - - def test_unchanged_1(self): - s = """apply()""" - self.unchanged(s) - - def test_unchanged_2(self): - s = """apply(f)""" - self.unchanged(s) - - def test_unchanged_3(self): - s = """apply(f,)""" - self.unchanged(s) - - def test_unchanged_4(self): - s = """apply(f, args, kwds, extras)""" - self.unchanged(s) - - def test_unchanged_5(self): - s = """apply(f, *args, **kwds)""" - self.unchanged(s) - - def test_unchanged_6(self): - s = """apply(f, *args)""" - self.unchanged(s) - - def test_unchanged_6b(self): - s = """apply(f, **kwds)""" - self.unchanged(s) - - def test_unchanged_7(self): - s = """apply(func=f, args=args, kwds=kwds)""" - self.unchanged(s) - - def test_unchanged_8(self): - s = """apply(f, args=args, kwds=kwds)""" - self.unchanged(s) - - def test_unchanged_9(self): - s = """apply(f, args, kwds=kwds)""" - self.unchanged(s) - - def test_space_1(self): - a = """apply( f, args, kwds)""" - b = """f(*args, **kwds)""" - self.check(a, b) - - def test_space_2(self): - a = """apply( f ,args,kwds )""" - b = """f(*args, **kwds)""" - self.check(a, b) - -class Test_reload(FixerTestCase): - fixer = "reload" - - def test(self): - b = """reload(a)""" - a = """import importlib\nimportlib.reload(a)""" - self.check(b, a) - - def test_comment(self): - b = """reload( a ) # comment""" - a = """import importlib\nimportlib.reload( a ) # comment""" - self.check(b, a) - - # PEP 8 comments - b = """reload( a ) # comment""" - a = """import importlib\nimportlib.reload( a ) # comment""" - self.check(b, a) - - def test_space(self): - b = """reload( a )""" - a = """import importlib\nimportlib.reload( a )""" - self.check(b, a) - - b = """reload( a)""" - a = """import importlib\nimportlib.reload( a)""" - self.check(b, a) - - b = """reload(a )""" - a = """import importlib\nimportlib.reload(a )""" - self.check(b, a) - - def test_unchanged(self): - s = """reload(a=1)""" - self.unchanged(s) - - s = """reload(f, g)""" - self.unchanged(s) - - s = """reload(f, *h)""" - self.unchanged(s) - - s = """reload(f, *h, **i)""" - self.unchanged(s) - - s = """reload(f, **i)""" - self.unchanged(s) - - s = """reload(*h, **i)""" - self.unchanged(s) - - s = """reload(*h)""" - self.unchanged(s) - - s = """reload(**i)""" - self.unchanged(s) - - s = """reload()""" - self.unchanged(s) - -class Test_intern(FixerTestCase): - fixer = "intern" - - def test_prefix_preservation(self): - b = """x = intern( a )""" - a = """import sys\nx = sys.intern( a )""" - self.check(b, a) - - b = """y = intern("b" # test - )""" - a = """import sys\ny = sys.intern("b" # test - )""" - self.check(b, a) - - b = """z = intern(a+b+c.d, )""" - a = """import sys\nz = sys.intern(a+b+c.d, )""" - self.check(b, a) - - def test(self): - b = """x = intern(a)""" - a = """import sys\nx = sys.intern(a)""" - self.check(b, a) - - b = """z = intern(a+b+c.d,)""" - a = """import sys\nz = sys.intern(a+b+c.d,)""" - self.check(b, a) - - b = """intern("y%s" % 5).replace("y", "")""" - a = """import sys\nsys.intern("y%s" % 5).replace("y", "")""" - self.check(b, a) - - # These should not be refactored - - def test_unchanged(self): - s = """intern(a=1)""" - self.unchanged(s) - - s = """intern(f, g)""" - self.unchanged(s) - - s = """intern(*h)""" - self.unchanged(s) - - s = """intern(**i)""" - self.unchanged(s) - - s = """intern()""" - self.unchanged(s) - -class Test_reduce(FixerTestCase): - fixer = "reduce" - - def test_simple_call(self): - b = "reduce(a, b, c)" - a = "from functools import reduce\nreduce(a, b, c)" - self.check(b, a) - - def test_bug_7253(self): - # fix_tuple_params was being bad and orphaning nodes in the tree. - b = "def x(arg): reduce(sum, [])" - a = "from functools import reduce\ndef x(arg): reduce(sum, [])" - self.check(b, a) - - def test_call_with_lambda(self): - b = "reduce(lambda x, y: x + y, seq)" - a = "from functools import reduce\nreduce(lambda x, y: x + y, seq)" - self.check(b, a) - - def test_unchanged(self): - s = "reduce(a)" - self.unchanged(s) - - s = "reduce(a, b=42)" - self.unchanged(s) - - s = "reduce(a, b, c, d)" - self.unchanged(s) - - s = "reduce(**c)" - self.unchanged(s) - - s = "reduce()" - self.unchanged(s) - -class Test_print(FixerTestCase): - fixer = "print" - - def test_prefix_preservation(self): - b = """print 1, 1+1, 1+1+1""" - a = """print(1, 1+1, 1+1+1)""" - self.check(b, a) - - def test_idempotency(self): - s = """print()""" - self.unchanged(s) - - s = """print('')""" - self.unchanged(s) - - def test_idempotency_print_as_function(self): - self.refactor.driver.grammar = pygram.python_grammar_no_print_statement - s = """print(1, 1+1, 1+1+1)""" - self.unchanged(s) - - s = """print()""" - self.unchanged(s) - - s = """print('')""" - self.unchanged(s) - - def test_1(self): - b = """print 1, 1+1, 1+1+1""" - a = """print(1, 1+1, 1+1+1)""" - self.check(b, a) - - def test_2(self): - b = """print 1, 2""" - a = """print(1, 2)""" - self.check(b, a) - - def test_3(self): - b = """print""" - a = """print()""" - self.check(b, a) - - def test_4(self): - # from bug 3000 - b = """print whatever; print""" - a = """print(whatever); print()""" - self.check(b, a) - - def test_5(self): - b = """print; print whatever;""" - a = """print(); print(whatever);""" - self.check(b, a) - - def test_tuple(self): - b = """print (a, b, c)""" - a = """print((a, b, c))""" - self.check(b, a) - - # trailing commas - - def test_trailing_comma_1(self): - b = """print 1, 2, 3,""" - a = """print(1, 2, 3, end=' ')""" - self.check(b, a) - - def test_trailing_comma_2(self): - b = """print 1, 2,""" - a = """print(1, 2, end=' ')""" - self.check(b, a) - - def test_trailing_comma_3(self): - b = """print 1,""" - a = """print(1, end=' ')""" - self.check(b, a) - - # >> stuff - - def test_vargs_without_trailing_comma(self): - b = """print >>sys.stderr, 1, 2, 3""" - a = """print(1, 2, 3, file=sys.stderr)""" - self.check(b, a) - - def test_with_trailing_comma(self): - b = """print >>sys.stderr, 1, 2,""" - a = """print(1, 2, end=' ', file=sys.stderr)""" - self.check(b, a) - - def test_no_trailing_comma(self): - b = """print >>sys.stderr, 1+1""" - a = """print(1+1, file=sys.stderr)""" - self.check(b, a) - - def test_spaces_before_file(self): - b = """print >> sys.stderr""" - a = """print(file=sys.stderr)""" - self.check(b, a) - - def test_with_future_print_function(self): - s = "from __future__ import print_function\n" \ - "print('Hai!', end=' ')" - self.unchanged(s) - - b = "print 'Hello, world!'" - a = "print('Hello, world!')" - self.check(b, a) - - -class Test_exec(FixerTestCase): - fixer = "exec" - - def test_prefix_preservation(self): - b = """ exec code in ns1, ns2""" - a = """ exec(code, ns1, ns2)""" - self.check(b, a) - - def test_basic(self): - b = """exec code""" - a = """exec(code)""" - self.check(b, a) - - def test_with_globals(self): - b = """exec code in ns""" - a = """exec(code, ns)""" - self.check(b, a) - - def test_with_globals_locals(self): - b = """exec code in ns1, ns2""" - a = """exec(code, ns1, ns2)""" - self.check(b, a) - - def test_complex_1(self): - b = """exec (a.b()) in ns""" - a = """exec((a.b()), ns)""" - self.check(b, a) - - def test_complex_2(self): - b = """exec a.b() + c in ns""" - a = """exec(a.b() + c, ns)""" - self.check(b, a) - - # These should not be touched - - def test_unchanged_1(self): - s = """exec(code)""" - self.unchanged(s) - - def test_unchanged_2(self): - s = """exec (code)""" - self.unchanged(s) - - def test_unchanged_3(self): - s = """exec(code, ns)""" - self.unchanged(s) - - def test_unchanged_4(self): - s = """exec(code, ns1, ns2)""" - self.unchanged(s) - -class Test_repr(FixerTestCase): - fixer = "repr" - - def test_prefix_preservation(self): - b = """x = `1 + 2`""" - a = """x = repr(1 + 2)""" - self.check(b, a) - - def test_simple_1(self): - b = """x = `1 + 2`""" - a = """x = repr(1 + 2)""" - self.check(b, a) - - def test_simple_2(self): - b = """y = `x`""" - a = """y = repr(x)""" - self.check(b, a) - - def test_complex(self): - b = """z = `y`.__repr__()""" - a = """z = repr(y).__repr__()""" - self.check(b, a) - - def test_tuple(self): - b = """x = `1, 2, 3`""" - a = """x = repr((1, 2, 3))""" - self.check(b, a) - - def test_nested(self): - b = """x = `1 + `2``""" - a = """x = repr(1 + repr(2))""" - self.check(b, a) - - def test_nested_tuples(self): - b = """x = `1, 2 + `3, 4``""" - a = """x = repr((1, 2 + repr((3, 4))))""" - self.check(b, a) - -class Test_except(FixerTestCase): - fixer = "except" - - def test_prefix_preservation(self): - b = """ - try: - pass - except (RuntimeError, ImportError), e: - pass""" - a = """ - try: - pass - except (RuntimeError, ImportError) as e: - pass""" - self.check(b, a) - - def test_simple(self): - b = """ - try: - pass - except Foo, e: - pass""" - a = """ - try: - pass - except Foo as e: - pass""" - self.check(b, a) - - def test_simple_no_space_before_target(self): - b = """ - try: - pass - except Foo,e: - pass""" - a = """ - try: - pass - except Foo as e: - pass""" - self.check(b, a) - - def test_tuple_unpack(self): - b = """ - def foo(): - try: - pass - except Exception, (f, e): - pass - except ImportError, e: - pass""" - - a = """ - def foo(): - try: - pass - except Exception as xxx_todo_changeme: - (f, e) = xxx_todo_changeme.args - pass - except ImportError as e: - pass""" - self.check(b, a) - - def test_multi_class(self): - b = """ - try: - pass - except (RuntimeError, ImportError), e: - pass""" - - a = """ - try: - pass - except (RuntimeError, ImportError) as e: - pass""" - self.check(b, a) - - def test_list_unpack(self): - b = """ - try: - pass - except Exception, [a, b]: - pass""" - - a = """ - try: - pass - except Exception as xxx_todo_changeme: - [a, b] = xxx_todo_changeme.args - pass""" - self.check(b, a) - - def test_weird_target_1(self): - b = """ - try: - pass - except Exception, d[5]: - pass""" - - a = """ - try: - pass - except Exception as xxx_todo_changeme: - d[5] = xxx_todo_changeme - pass""" - self.check(b, a) - - def test_weird_target_2(self): - b = """ - try: - pass - except Exception, a.foo: - pass""" - - a = """ - try: - pass - except Exception as xxx_todo_changeme: - a.foo = xxx_todo_changeme - pass""" - self.check(b, a) - - def test_weird_target_3(self): - b = """ - try: - pass - except Exception, a().foo: - pass""" - - a = """ - try: - pass - except Exception as xxx_todo_changeme: - a().foo = xxx_todo_changeme - pass""" - self.check(b, a) - - def test_bare_except(self): - b = """ - try: - pass - except Exception, a: - pass - except: - pass""" - - a = """ - try: - pass - except Exception as a: - pass - except: - pass""" - self.check(b, a) - - def test_bare_except_and_else_finally(self): - b = """ - try: - pass - except Exception, a: - pass - except: - pass - else: - pass - finally: - pass""" - - a = """ - try: - pass - except Exception as a: - pass - except: - pass - else: - pass - finally: - pass""" - self.check(b, a) - - def test_multi_fixed_excepts_before_bare_except(self): - b = """ - try: - pass - except TypeError, b: - pass - except Exception, a: - pass - except: - pass""" - - a = """ - try: - pass - except TypeError as b: - pass - except Exception as a: - pass - except: - pass""" - self.check(b, a) - - def test_one_line_suites(self): - b = """ - try: raise TypeError - except TypeError, e: - pass - """ - a = """ - try: raise TypeError - except TypeError as e: - pass - """ - self.check(b, a) - b = """ - try: - raise TypeError - except TypeError, e: pass - """ - a = """ - try: - raise TypeError - except TypeError as e: pass - """ - self.check(b, a) - b = """ - try: raise TypeError - except TypeError, e: pass - """ - a = """ - try: raise TypeError - except TypeError as e: pass - """ - self.check(b, a) - b = """ - try: raise TypeError - except TypeError, e: pass - else: function() - finally: done() - """ - a = """ - try: raise TypeError - except TypeError as e: pass - else: function() - finally: done() - """ - self.check(b, a) - - # These should not be touched: - - def test_unchanged_1(self): - s = """ - try: - pass - except: - pass""" - self.unchanged(s) - - def test_unchanged_2(self): - s = """ - try: - pass - except Exception: - pass""" - self.unchanged(s) - - def test_unchanged_3(self): - s = """ - try: - pass - except (Exception, SystemExit): - pass""" - self.unchanged(s) - -class Test_raise(FixerTestCase): - fixer = "raise" - - def test_basic(self): - b = """raise Exception, 5""" - a = """raise Exception(5)""" - self.check(b, a) - - def test_prefix_preservation(self): - b = """raise Exception,5""" - a = """raise Exception(5)""" - self.check(b, a) - - b = """raise Exception, 5""" - a = """raise Exception(5)""" - self.check(b, a) - - def test_with_comments(self): - b = """raise Exception, 5 # foo""" - a = """raise Exception(5) # foo""" - self.check(b, a) - - b = """raise E, (5, 6) % (a, b) # foo""" - a = """raise E((5, 6) % (a, b)) # foo""" - self.check(b, a) - - b = """def foo(): - raise Exception, 5, 6 # foo""" - a = """def foo(): - raise Exception(5).with_traceback(6) # foo""" - self.check(b, a) - - def test_None_value(self): - b = """raise Exception(5), None, tb""" - a = """raise Exception(5).with_traceback(tb)""" - self.check(b, a) - - def test_tuple_value(self): - b = """raise Exception, (5, 6, 7)""" - a = """raise Exception(5, 6, 7)""" - self.check(b, a) - - def test_tuple_detection(self): - b = """raise E, (5, 6) % (a, b)""" - a = """raise E((5, 6) % (a, b))""" - self.check(b, a) - - def test_tuple_exc_1(self): - b = """raise (((E1, E2), E3), E4), V""" - a = """raise E1(V)""" - self.check(b, a) - - def test_tuple_exc_2(self): - b = """raise (E1, (E2, E3), E4), V""" - a = """raise E1(V)""" - self.check(b, a) - - # These should produce a warning - - def test_string_exc(self): - s = """raise 'foo'""" - self.warns_unchanged(s, "Python 3 does not support string exceptions") - - def test_string_exc_val(self): - s = """raise "foo", 5""" - self.warns_unchanged(s, "Python 3 does not support string exceptions") - - def test_string_exc_val_tb(self): - s = """raise "foo", 5, 6""" - self.warns_unchanged(s, "Python 3 does not support string exceptions") - - # These should result in traceback-assignment - - def test_tb_1(self): - b = """def foo(): - raise Exception, 5, 6""" - a = """def foo(): - raise Exception(5).with_traceback(6)""" - self.check(b, a) - - def test_tb_2(self): - b = """def foo(): - a = 5 - raise Exception, 5, 6 - b = 6""" - a = """def foo(): - a = 5 - raise Exception(5).with_traceback(6) - b = 6""" - self.check(b, a) - - def test_tb_3(self): - b = """def foo(): - raise Exception,5,6""" - a = """def foo(): - raise Exception(5).with_traceback(6)""" - self.check(b, a) - - def test_tb_4(self): - b = """def foo(): - a = 5 - raise Exception,5,6 - b = 6""" - a = """def foo(): - a = 5 - raise Exception(5).with_traceback(6) - b = 6""" - self.check(b, a) - - def test_tb_5(self): - b = """def foo(): - raise Exception, (5, 6, 7), 6""" - a = """def foo(): - raise Exception(5, 6, 7).with_traceback(6)""" - self.check(b, a) - - def test_tb_6(self): - b = """def foo(): - a = 5 - raise Exception, (5, 6, 7), 6 - b = 6""" - a = """def foo(): - a = 5 - raise Exception(5, 6, 7).with_traceback(6) - b = 6""" - self.check(b, a) - -class Test_throw(FixerTestCase): - fixer = "throw" - - def test_1(self): - b = """g.throw(Exception, 5)""" - a = """g.throw(Exception(5))""" - self.check(b, a) - - def test_2(self): - b = """g.throw(Exception,5)""" - a = """g.throw(Exception(5))""" - self.check(b, a) - - def test_3(self): - b = """g.throw(Exception, (5, 6, 7))""" - a = """g.throw(Exception(5, 6, 7))""" - self.check(b, a) - - def test_4(self): - b = """5 + g.throw(Exception, 5)""" - a = """5 + g.throw(Exception(5))""" - self.check(b, a) - - # These should produce warnings - - def test_warn_1(self): - s = """g.throw("foo")""" - self.warns_unchanged(s, "Python 3 does not support string exceptions") - - def test_warn_2(self): - s = """g.throw("foo", 5)""" - self.warns_unchanged(s, "Python 3 does not support string exceptions") - - def test_warn_3(self): - s = """g.throw("foo", 5, 6)""" - self.warns_unchanged(s, "Python 3 does not support string exceptions") - - # These should not be touched - - def test_untouched_1(self): - s = """g.throw(Exception)""" - self.unchanged(s) - - def test_untouched_2(self): - s = """g.throw(Exception(5, 6))""" - self.unchanged(s) - - def test_untouched_3(self): - s = """5 + g.throw(Exception(5, 6))""" - self.unchanged(s) - - # These should result in traceback-assignment - - def test_tb_1(self): - b = """def foo(): - g.throw(Exception, 5, 6)""" - a = """def foo(): - g.throw(Exception(5).with_traceback(6))""" - self.check(b, a) - - def test_tb_2(self): - b = """def foo(): - a = 5 - g.throw(Exception, 5, 6) - b = 6""" - a = """def foo(): - a = 5 - g.throw(Exception(5).with_traceback(6)) - b = 6""" - self.check(b, a) - - def test_tb_3(self): - b = """def foo(): - g.throw(Exception,5,6)""" - a = """def foo(): - g.throw(Exception(5).with_traceback(6))""" - self.check(b, a) - - def test_tb_4(self): - b = """def foo(): - a = 5 - g.throw(Exception,5,6) - b = 6""" - a = """def foo(): - a = 5 - g.throw(Exception(5).with_traceback(6)) - b = 6""" - self.check(b, a) - - def test_tb_5(self): - b = """def foo(): - g.throw(Exception, (5, 6, 7), 6)""" - a = """def foo(): - g.throw(Exception(5, 6, 7).with_traceback(6))""" - self.check(b, a) - - def test_tb_6(self): - b = """def foo(): - a = 5 - g.throw(Exception, (5, 6, 7), 6) - b = 6""" - a = """def foo(): - a = 5 - g.throw(Exception(5, 6, 7).with_traceback(6)) - b = 6""" - self.check(b, a) - - def test_tb_7(self): - b = """def foo(): - a + g.throw(Exception, 5, 6)""" - a = """def foo(): - a + g.throw(Exception(5).with_traceback(6))""" - self.check(b, a) - - def test_tb_8(self): - b = """def foo(): - a = 5 - a + g.throw(Exception, 5, 6) - b = 6""" - a = """def foo(): - a = 5 - a + g.throw(Exception(5).with_traceback(6)) - b = 6""" - self.check(b, a) - -class Test_long(FixerTestCase): - fixer = "long" - - def test_1(self): - b = """x = long(x)""" - a = """x = int(x)""" - self.check(b, a) - - def test_2(self): - b = """y = isinstance(x, long)""" - a = """y = isinstance(x, int)""" - self.check(b, a) - - def test_3(self): - b = """z = type(x) in (int, long)""" - a = """z = type(x) in (int, int)""" - self.check(b, a) - - def test_unchanged(self): - s = """long = True""" - self.unchanged(s) - - s = """s.long = True""" - self.unchanged(s) - - s = """def long(): pass""" - self.unchanged(s) - - s = """class long(): pass""" - self.unchanged(s) - - s = """def f(long): pass""" - self.unchanged(s) - - s = """def f(g, long): pass""" - self.unchanged(s) - - s = """def f(x, long=True): pass""" - self.unchanged(s) - - def test_prefix_preservation(self): - b = """x = long( x )""" - a = """x = int( x )""" - self.check(b, a) - - -class Test_execfile(FixerTestCase): - fixer = "execfile" - - def test_conversion(self): - b = """execfile("fn")""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'))""" - self.check(b, a) - - b = """execfile("fn", glob)""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), glob)""" - self.check(b, a) - - b = """execfile("fn", glob, loc)""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), glob, loc)""" - self.check(b, a) - - b = """execfile("fn", globals=glob)""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals=glob)""" - self.check(b, a) - - b = """execfile("fn", locals=loc)""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), locals=loc)""" - self.check(b, a) - - b = """execfile("fn", globals=glob, locals=loc)""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals=glob, locals=loc)""" - self.check(b, a) - - def test_spacing(self): - b = """execfile( "fn" )""" - a = """exec(compile(open( "fn", "rb" ).read(), "fn", 'exec'))""" - self.check(b, a) - - b = """execfile("fn", globals = glob)""" - a = """exec(compile(open("fn", "rb").read(), "fn", 'exec'), globals = glob)""" - self.check(b, a) - - -class Test_isinstance(FixerTestCase): - fixer = "isinstance" - - def test_remove_multiple_items(self): - b = """isinstance(x, (int, int, int))""" - a = """isinstance(x, int)""" - self.check(b, a) - - b = """isinstance(x, (int, float, int, int, float))""" - a = """isinstance(x, (int, float))""" - self.check(b, a) - - b = """isinstance(x, (int, float, int, int, float, str))""" - a = """isinstance(x, (int, float, str))""" - self.check(b, a) - - b = """isinstance(foo() + bar(), (x(), y(), x(), int, int))""" - a = """isinstance(foo() + bar(), (x(), y(), x(), int))""" - self.check(b, a) - - def test_prefix_preservation(self): - b = """if isinstance( foo(), ( bar, bar, baz )) : pass""" - a = """if isinstance( foo(), ( bar, baz )) : pass""" - self.check(b, a) - - def test_unchanged(self): - self.unchanged("isinstance(x, (str, int))") - -class Test_dict(FixerTestCase): - fixer = "dict" - - def test_prefix_preservation(self): - b = "if d. keys ( ) : pass" - a = "if list(d. keys ( )) : pass" - self.check(b, a) - - b = "if d. items ( ) : pass" - a = "if list(d. items ( )) : pass" - self.check(b, a) - - b = "if d. iterkeys ( ) : pass" - a = "if iter(d. keys ( )) : pass" - self.check(b, a) - - b = "[i for i in d. iterkeys( ) ]" - a = "[i for i in d. keys( ) ]" - self.check(b, a) - - b = "if d. viewkeys ( ) : pass" - a = "if d. keys ( ) : pass" - self.check(b, a) - - b = "[i for i in d. viewkeys( ) ]" - a = "[i for i in d. keys( ) ]" - self.check(b, a) - - def test_trailing_comment(self): - b = "d.keys() # foo" - a = "list(d.keys()) # foo" - self.check(b, a) - - b = "d.items() # foo" - a = "list(d.items()) # foo" - self.check(b, a) - - b = "d.iterkeys() # foo" - a = "iter(d.keys()) # foo" - self.check(b, a) - - b = """[i for i in d.iterkeys() # foo - ]""" - a = """[i for i in d.keys() # foo - ]""" - self.check(b, a) - - b = """[i for i in d.iterkeys() # foo - ]""" - a = """[i for i in d.keys() # foo - ]""" - self.check(b, a) - - b = "d.viewitems() # foo" - a = "d.items() # foo" - self.check(b, a) - - def test_unchanged(self): - for wrapper in fixer_util.consuming_calls: - s = "s = %s(d.keys())" % wrapper - self.unchanged(s) - - s = "s = %s(d.values())" % wrapper - self.unchanged(s) - - s = "s = %s(d.items())" % wrapper - self.unchanged(s) - - def test_01(self): - b = "d.keys()" - a = "list(d.keys())" - self.check(b, a) - - b = "a[0].foo().keys()" - a = "list(a[0].foo().keys())" - self.check(b, a) - - def test_02(self): - b = "d.items()" - a = "list(d.items())" - self.check(b, a) - - def test_03(self): - b = "d.values()" - a = "list(d.values())" - self.check(b, a) - - def test_04(self): - b = "d.iterkeys()" - a = "iter(d.keys())" - self.check(b, a) - - def test_05(self): - b = "d.iteritems()" - a = "iter(d.items())" - self.check(b, a) - - def test_06(self): - b = "d.itervalues()" - a = "iter(d.values())" - self.check(b, a) - - def test_07(self): - s = "list(d.keys())" - self.unchanged(s) - - def test_08(self): - s = "sorted(d.keys())" - self.unchanged(s) - - def test_09(self): - b = "iter(d.keys())" - a = "iter(list(d.keys()))" - self.check(b, a) - - def test_10(self): - b = "foo(d.keys())" - a = "foo(list(d.keys()))" - self.check(b, a) - - def test_11(self): - b = "for i in d.keys(): print i" - a = "for i in list(d.keys()): print i" - self.check(b, a) - - def test_12(self): - b = "for i in d.iterkeys(): print i" - a = "for i in d.keys(): print i" - self.check(b, a) - - def test_13(self): - b = "[i for i in d.keys()]" - a = "[i for i in list(d.keys())]" - self.check(b, a) - - def test_14(self): - b = "[i for i in d.iterkeys()]" - a = "[i for i in d.keys()]" - self.check(b, a) - - def test_15(self): - b = "(i for i in d.keys())" - a = "(i for i in list(d.keys()))" - self.check(b, a) - - def test_16(self): - b = "(i for i in d.iterkeys())" - a = "(i for i in d.keys())" - self.check(b, a) - - def test_17(self): - b = "iter(d.iterkeys())" - a = "iter(d.keys())" - self.check(b, a) - - def test_18(self): - b = "list(d.iterkeys())" - a = "list(d.keys())" - self.check(b, a) - - def test_19(self): - b = "sorted(d.iterkeys())" - a = "sorted(d.keys())" - self.check(b, a) - - def test_20(self): - b = "foo(d.iterkeys())" - a = "foo(iter(d.keys()))" - self.check(b, a) - - def test_21(self): - b = "print h.iterkeys().next()" - a = "print iter(h.keys()).next()" - self.check(b, a) - - def test_22(self): - b = "print h.keys()[0]" - a = "print list(h.keys())[0]" - self.check(b, a) - - def test_23(self): - b = "print list(h.iterkeys().next())" - a = "print list(iter(h.keys()).next())" - self.check(b, a) - - def test_24(self): - b = "for x in h.keys()[0]: print x" - a = "for x in list(h.keys())[0]: print x" - self.check(b, a) - - def test_25(self): - b = "d.viewkeys()" - a = "d.keys()" - self.check(b, a) - - def test_26(self): - b = "d.viewitems()" - a = "d.items()" - self.check(b, a) - - def test_27(self): - b = "d.viewvalues()" - a = "d.values()" - self.check(b, a) - - def test_28(self): - b = "[i for i in d.viewkeys()]" - a = "[i for i in d.keys()]" - self.check(b, a) - - def test_29(self): - b = "(i for i in d.viewkeys())" - a = "(i for i in d.keys())" - self.check(b, a) - - def test_30(self): - b = "iter(d.viewkeys())" - a = "iter(d.keys())" - self.check(b, a) - - def test_31(self): - b = "list(d.viewkeys())" - a = "list(d.keys())" - self.check(b, a) - - def test_32(self): - b = "sorted(d.viewkeys())" - a = "sorted(d.keys())" - self.check(b, a) - -class Test_xrange(FixerTestCase): - fixer = "xrange" - - def test_prefix_preservation(self): - b = """x = xrange( 10 )""" - a = """x = range( 10 )""" - self.check(b, a) - - b = """x = xrange( 1 , 10 )""" - a = """x = range( 1 , 10 )""" - self.check(b, a) - - b = """x = xrange( 0 , 10 , 2 )""" - a = """x = range( 0 , 10 , 2 )""" - self.check(b, a) - - def test_single_arg(self): - b = """x = xrange(10)""" - a = """x = range(10)""" - self.check(b, a) - - def test_two_args(self): - b = """x = xrange(1, 10)""" - a = """x = range(1, 10)""" - self.check(b, a) - - def test_three_args(self): - b = """x = xrange(0, 10, 2)""" - a = """x = range(0, 10, 2)""" - self.check(b, a) - - def test_wrap_in_list(self): - b = """x = range(10, 3, 9)""" - a = """x = list(range(10, 3, 9))""" - self.check(b, a) - - b = """x = foo(range(10, 3, 9))""" - a = """x = foo(list(range(10, 3, 9)))""" - self.check(b, a) - - b = """x = range(10, 3, 9) + [4]""" - a = """x = list(range(10, 3, 9)) + [4]""" - self.check(b, a) - - b = """x = range(10)[::-1]""" - a = """x = list(range(10))[::-1]""" - self.check(b, a) - - b = """x = range(10) [3]""" - a = """x = list(range(10)) [3]""" - self.check(b, a) - - def test_xrange_in_for(self): - b = """for i in xrange(10):\n j=i""" - a = """for i in range(10):\n j=i""" - self.check(b, a) - - b = """[i for i in xrange(10)]""" - a = """[i for i in range(10)]""" - self.check(b, a) - - def test_range_in_for(self): - self.unchanged("for i in range(10): pass") - self.unchanged("[i for i in range(10)]") - - def test_in_contains_test(self): - self.unchanged("x in range(10, 3, 9)") - - def test_in_consuming_context(self): - for call in fixer_util.consuming_calls: - self.unchanged("a = %s(range(10))" % call) - -class Test_xrange_with_reduce(FixerTestCase): - - def setUp(self): - super(Test_xrange_with_reduce, self).setUp(["xrange", "reduce"]) - - def test_double_transform(self): - b = """reduce(x, xrange(5))""" - a = """from functools import reduce -reduce(x, range(5))""" - self.check(b, a) - -class Test_raw_input(FixerTestCase): - fixer = "raw_input" - - def test_prefix_preservation(self): - b = """x = raw_input( )""" - a = """x = input( )""" - self.check(b, a) - - b = """x = raw_input( '' )""" - a = """x = input( '' )""" - self.check(b, a) - - def test_1(self): - b = """x = raw_input()""" - a = """x = input()""" - self.check(b, a) - - def test_2(self): - b = """x = raw_input('')""" - a = """x = input('')""" - self.check(b, a) - - def test_3(self): - b = """x = raw_input('prompt')""" - a = """x = input('prompt')""" - self.check(b, a) - - def test_4(self): - b = """x = raw_input(foo(a) + 6)""" - a = """x = input(foo(a) + 6)""" - self.check(b, a) - - def test_5(self): - b = """x = raw_input(invite).split()""" - a = """x = input(invite).split()""" - self.check(b, a) - - def test_6(self): - b = """x = raw_input(invite) . split ()""" - a = """x = input(invite) . split ()""" - self.check(b, a) - - def test_8(self): - b = "x = int(raw_input())" - a = "x = int(input())" - self.check(b, a) - -class Test_funcattrs(FixerTestCase): - fixer = "funcattrs" - - attrs = ["closure", "doc", "name", "defaults", "code", "globals", "dict"] - - def test(self): - for attr in self.attrs: - b = "a.func_%s" % attr - a = "a.__%s__" % attr - self.check(b, a) - - b = "self.foo.func_%s.foo_bar" % attr - a = "self.foo.__%s__.foo_bar" % attr - self.check(b, a) - - def test_unchanged(self): - for attr in self.attrs: - s = "foo(func_%s + 5)" % attr - self.unchanged(s) - - s = "f(foo.__%s__)" % attr - self.unchanged(s) - - s = "f(foo.__%s__.foo)" % attr - self.unchanged(s) - -class Test_xreadlines(FixerTestCase): - fixer = "xreadlines" - - def test_call(self): - b = "for x in f.xreadlines(): pass" - a = "for x in f: pass" - self.check(b, a) - - b = "for x in foo().xreadlines(): pass" - a = "for x in foo(): pass" - self.check(b, a) - - b = "for x in (5 + foo()).xreadlines(): pass" - a = "for x in (5 + foo()): pass" - self.check(b, a) - - def test_attr_ref(self): - b = "foo(f.xreadlines + 5)" - a = "foo(f.__iter__ + 5)" - self.check(b, a) - - b = "foo(f().xreadlines + 5)" - a = "foo(f().__iter__ + 5)" - self.check(b, a) - - b = "foo((5 + f()).xreadlines + 5)" - a = "foo((5 + f()).__iter__ + 5)" - self.check(b, a) - - def test_unchanged(self): - s = "for x in f.xreadlines(5): pass" - self.unchanged(s) - - s = "for x in f.xreadlines(k=5): pass" - self.unchanged(s) - - s = "for x in f.xreadlines(*k, **v): pass" - self.unchanged(s) - - s = "foo(xreadlines)" - self.unchanged(s) - - -class ImportsFixerTests: - - def test_import_module(self): - for old, new in self.modules.items(): - b = "import %s" % old - a = "import %s" % new - self.check(b, a) - - b = "import foo, %s, bar" % old - a = "import foo, %s, bar" % new - self.check(b, a) - - def test_import_from(self): - for old, new in self.modules.items(): - b = "from %s import foo" % old - a = "from %s import foo" % new - self.check(b, a) - - b = "from %s import foo, bar" % old - a = "from %s import foo, bar" % new - self.check(b, a) - - b = "from %s import (yes, no)" % old - a = "from %s import (yes, no)" % new - self.check(b, a) - - def test_import_module_as(self): - for old, new in self.modules.items(): - b = "import %s as foo_bar" % old - a = "import %s as foo_bar" % new - self.check(b, a) - - b = "import %s as foo_bar" % old - a = "import %s as foo_bar" % new - self.check(b, a) - - def test_import_from_as(self): - for old, new in self.modules.items(): - b = "from %s import foo as bar" % old - a = "from %s import foo as bar" % new - self.check(b, a) - - def test_star(self): - for old, new in self.modules.items(): - b = "from %s import *" % old - a = "from %s import *" % new - self.check(b, a) - - def test_import_module_usage(self): - for old, new in self.modules.items(): - b = """ - import %s - foo(%s.bar) - """ % (old, old) - a = """ - import %s - foo(%s.bar) - """ % (new, new) - self.check(b, a) - - b = """ - from %s import x - %s = 23 - """ % (old, old) - a = """ - from %s import x - %s = 23 - """ % (new, old) - self.check(b, a) - - s = """ - def f(): - %s.method() - """ % (old,) - self.unchanged(s) - - # test nested usage - b = """ - import %s - %s.bar(%s.foo) - """ % (old, old, old) - a = """ - import %s - %s.bar(%s.foo) - """ % (new, new, new) - self.check(b, a) - - b = """ - import %s - x.%s - """ % (old, old) - a = """ - import %s - x.%s - """ % (new, old) - self.check(b, a) - - -class Test_imports(FixerTestCase, ImportsFixerTests): - fixer = "imports" - from lib2to3.fixes.fix_imports import MAPPING as modules - - def test_multiple_imports(self): - b = """import urlparse, cStringIO""" - a = """import urllib.parse, io""" - self.check(b, a) - - def test_multiple_imports_as(self): - b = """ - import copy_reg as bar, HTMLParser as foo, urlparse - s = urlparse.spam(bar.foo()) - """ - a = """ - import copyreg as bar, html.parser as foo, urllib.parse - s = urllib.parse.spam(bar.foo()) - """ - self.check(b, a) - - -class Test_imports2(FixerTestCase, ImportsFixerTests): - fixer = "imports2" - from lib2to3.fixes.fix_imports2 import MAPPING as modules - - -class Test_imports_fixer_order(FixerTestCase, ImportsFixerTests): - - def setUp(self): - super(Test_imports_fixer_order, self).setUp(['imports', 'imports2']) - from lib2to3.fixes.fix_imports2 import MAPPING as mapping2 - self.modules = mapping2.copy() - from lib2to3.fixes.fix_imports import MAPPING as mapping1 - for key in ('dbhash', 'dumbdbm', 'dbm', 'gdbm'): - self.modules[key] = mapping1[key] - - def test_after_local_imports_refactoring(self): - for fix in ("imports", "imports2"): - self.fixer = fix - self.assert_runs_after("import") - - -class Test_urllib(FixerTestCase): - fixer = "urllib" - from lib2to3.fixes.fix_urllib import MAPPING as modules - - def test_import_module(self): - for old, changes in self.modules.items(): - b = "import %s" % old - a = "import %s" % ", ".join(map(itemgetter(0), changes)) - self.check(b, a) - - def test_import_from(self): - for old, changes in self.modules.items(): - all_members = [] - for new, members in changes: - for member in members: - all_members.append(member) - b = "from %s import %s" % (old, member) - a = "from %s import %s" % (new, member) - self.check(b, a) - - s = "from foo import %s" % member - self.unchanged(s) - - b = "from %s import %s" % (old, ", ".join(members)) - a = "from %s import %s" % (new, ", ".join(members)) - self.check(b, a) - - s = "from foo import %s" % ", ".join(members) - self.unchanged(s) - - # test the breaking of a module into multiple replacements - b = "from %s import %s" % (old, ", ".join(all_members)) - a = "\n".join(["from %s import %s" % (new, ", ".join(members)) - for (new, members) in changes]) - self.check(b, a) - - def test_import_module_as(self): - for old in self.modules: - s = "import %s as foo" % old - self.warns_unchanged(s, "This module is now multiple modules") - - def test_import_from_as(self): - for old, changes in self.modules.items(): - for new, members in changes: - for member in members: - b = "from %s import %s as foo_bar" % (old, member) - a = "from %s import %s as foo_bar" % (new, member) - self.check(b, a) - b = "from %s import %s as blah, %s" % (old, member, member) - a = "from %s import %s as blah, %s" % (new, member, member) - self.check(b, a) - - def test_star(self): - for old in self.modules: - s = "from %s import *" % old - self.warns_unchanged(s, "Cannot handle star imports") - - def test_indented(self): - b = """ -def foo(): - from urllib import urlencode, urlopen -""" - a = """ -def foo(): - from urllib.parse import urlencode - from urllib.request import urlopen -""" - self.check(b, a) - - b = """ -def foo(): - other() - from urllib import urlencode, urlopen -""" - a = """ -def foo(): - other() - from urllib.parse import urlencode - from urllib.request import urlopen -""" - self.check(b, a) - - def test_single_import(self): - b = "from urllib import getproxies" - a = "from urllib.request import getproxies" - - self.check(b, a) - - def test_import_module_usage(self): - for old, changes in self.modules.items(): - for new, members in changes: - for member in members: - new_import = ", ".join([n for (n, mems) - in self.modules[old]]) - b = """ - import %s - foo(%s.%s) - """ % (old, old, member) - a = """ - import %s - foo(%s.%s) - """ % (new_import, new, member) - self.check(b, a) - b = """ - import %s - %s.%s(%s.%s) - """ % (old, old, member, old, member) - a = """ - import %s - %s.%s(%s.%s) - """ % (new_import, new, member, new, member) - self.check(b, a) - - -class Test_input(FixerTestCase): - fixer = "input" - - def test_prefix_preservation(self): - b = """x = input( )""" - a = """x = eval(input( ))""" - self.check(b, a) - - b = """x = input( '' )""" - a = """x = eval(input( '' ))""" - self.check(b, a) - - def test_trailing_comment(self): - b = """x = input() # foo""" - a = """x = eval(input()) # foo""" - self.check(b, a) - - def test_idempotency(self): - s = """x = eval(input())""" - self.unchanged(s) - - s = """x = eval(input(''))""" - self.unchanged(s) - - s = """x = eval(input(foo(5) + 9))""" - self.unchanged(s) - - def test_1(self): - b = """x = input()""" - a = """x = eval(input())""" - self.check(b, a) - - def test_2(self): - b = """x = input('')""" - a = """x = eval(input(''))""" - self.check(b, a) - - def test_3(self): - b = """x = input('prompt')""" - a = """x = eval(input('prompt'))""" - self.check(b, a) - - def test_4(self): - b = """x = input(foo(5) + 9)""" - a = """x = eval(input(foo(5) + 9))""" - self.check(b, a) - -class Test_tuple_params(FixerTestCase): - fixer = "tuple_params" - - def test_unchanged_1(self): - s = """def foo(): pass""" - self.unchanged(s) - - def test_unchanged_2(self): - s = """def foo(a, b, c): pass""" - self.unchanged(s) - - def test_unchanged_3(self): - s = """def foo(a=3, b=4, c=5): pass""" - self.unchanged(s) - - def test_1(self): - b = """ - def foo(((a, b), c)): - x = 5""" - - a = """ - def foo(xxx_todo_changeme): - ((a, b), c) = xxx_todo_changeme - x = 5""" - self.check(b, a) - - def test_2(self): - b = """ - def foo(((a, b), c), d): - x = 5""" - - a = """ - def foo(xxx_todo_changeme, d): - ((a, b), c) = xxx_todo_changeme - x = 5""" - self.check(b, a) - - def test_3(self): - b = """ - def foo(((a, b), c), d) -> e: - x = 5""" - - a = """ - def foo(xxx_todo_changeme, d) -> e: - ((a, b), c) = xxx_todo_changeme - x = 5""" - self.check(b, a) - - def test_semicolon(self): - b = """ - def foo(((a, b), c)): x = 5; y = 7""" - - a = """ - def foo(xxx_todo_changeme): ((a, b), c) = xxx_todo_changeme; x = 5; y = 7""" - self.check(b, a) - - def test_keywords(self): - b = """ - def foo(((a, b), c), d, e=5) -> z: - x = 5""" - - a = """ - def foo(xxx_todo_changeme, d, e=5) -> z: - ((a, b), c) = xxx_todo_changeme - x = 5""" - self.check(b, a) - - def test_varargs(self): - b = """ - def foo(((a, b), c), d, *vargs, **kwargs) -> z: - x = 5""" - - a = """ - def foo(xxx_todo_changeme, d, *vargs, **kwargs) -> z: - ((a, b), c) = xxx_todo_changeme - x = 5""" - self.check(b, a) - - def test_multi_1(self): - b = """ - def foo(((a, b), c), (d, e, f)) -> z: - x = 5""" - - a = """ - def foo(xxx_todo_changeme, xxx_todo_changeme1) -> z: - ((a, b), c) = xxx_todo_changeme - (d, e, f) = xxx_todo_changeme1 - x = 5""" - self.check(b, a) - - def test_multi_2(self): - b = """ - def foo(x, ((a, b), c), d, (e, f, g), y) -> z: - x = 5""" - - a = """ - def foo(x, xxx_todo_changeme, d, xxx_todo_changeme1, y) -> z: - ((a, b), c) = xxx_todo_changeme - (e, f, g) = xxx_todo_changeme1 - x = 5""" - self.check(b, a) - - def test_docstring(self): - b = """ - def foo(((a, b), c), (d, e, f)) -> z: - "foo foo foo foo" - x = 5""" - - a = """ - def foo(xxx_todo_changeme, xxx_todo_changeme1) -> z: - "foo foo foo foo" - ((a, b), c) = xxx_todo_changeme - (d, e, f) = xxx_todo_changeme1 - x = 5""" - self.check(b, a) - - def test_lambda_no_change(self): - s = """lambda x: x + 5""" - self.unchanged(s) - - def test_lambda_parens_single_arg(self): - b = """lambda (x): x + 5""" - a = """lambda x: x + 5""" - self.check(b, a) - - b = """lambda(x): x + 5""" - a = """lambda x: x + 5""" - self.check(b, a) - - b = """lambda ((((x)))): x + 5""" - a = """lambda x: x + 5""" - self.check(b, a) - - b = """lambda((((x)))): x + 5""" - a = """lambda x: x + 5""" - self.check(b, a) - - def test_lambda_simple(self): - b = """lambda (x, y): x + f(y)""" - a = """lambda x_y: x_y[0] + f(x_y[1])""" - self.check(b, a) - - b = """lambda(x, y): x + f(y)""" - a = """lambda x_y: x_y[0] + f(x_y[1])""" - self.check(b, a) - - b = """lambda (((x, y))): x + f(y)""" - a = """lambda x_y: x_y[0] + f(x_y[1])""" - self.check(b, a) - - b = """lambda(((x, y))): x + f(y)""" - a = """lambda x_y: x_y[0] + f(x_y[1])""" - self.check(b, a) - - def test_lambda_one_tuple(self): - b = """lambda (x,): x + f(x)""" - a = """lambda x1: x1[0] + f(x1[0])""" - self.check(b, a) - - b = """lambda (((x,))): x + f(x)""" - a = """lambda x1: x1[0] + f(x1[0])""" - self.check(b, a) - - def test_lambda_simple_multi_use(self): - b = """lambda (x, y): x + x + f(x) + x""" - a = """lambda x_y: x_y[0] + x_y[0] + f(x_y[0]) + x_y[0]""" - self.check(b, a) - - def test_lambda_simple_reverse(self): - b = """lambda (x, y): y + x""" - a = """lambda x_y: x_y[1] + x_y[0]""" - self.check(b, a) - - def test_lambda_nested(self): - b = """lambda (x, (y, z)): x + y + z""" - a = """lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]""" - self.check(b, a) - - b = """lambda (((x, (y, z)))): x + y + z""" - a = """lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]""" - self.check(b, a) - - def test_lambda_nested_multi_use(self): - b = """lambda (x, (y, z)): x + y + f(y)""" - a = """lambda x_y_z: x_y_z[0] + x_y_z[1][0] + f(x_y_z[1][0])""" - self.check(b, a) - -class Test_methodattrs(FixerTestCase): - fixer = "methodattrs" - - attrs = ["func", "self", "class"] - - def test(self): - for attr in self.attrs: - b = "a.im_%s" % attr - if attr == "class": - a = "a.__self__.__class__" - else: - a = "a.__%s__" % attr - self.check(b, a) - - b = "self.foo.im_%s.foo_bar" % attr - if attr == "class": - a = "self.foo.__self__.__class__.foo_bar" - else: - a = "self.foo.__%s__.foo_bar" % attr - self.check(b, a) - - def test_unchanged(self): - for attr in self.attrs: - s = "foo(im_%s + 5)" % attr - self.unchanged(s) - - s = "f(foo.__%s__)" % attr - self.unchanged(s) - - s = "f(foo.__%s__.foo)" % attr - self.unchanged(s) - -class Test_next(FixerTestCase): - fixer = "next" - - def test_1(self): - b = """it.next()""" - a = """next(it)""" - self.check(b, a) - - def test_2(self): - b = """a.b.c.d.next()""" - a = """next(a.b.c.d)""" - self.check(b, a) - - def test_3(self): - b = """(a + b).next()""" - a = """next((a + b))""" - self.check(b, a) - - def test_4(self): - b = """a().next()""" - a = """next(a())""" - self.check(b, a) - - def test_5(self): - b = """a().next() + b""" - a = """next(a()) + b""" - self.check(b, a) - - def test_6(self): - b = """c( a().next() + b)""" - a = """c( next(a()) + b)""" - self.check(b, a) - - def test_prefix_preservation_1(self): - b = """ - for a in b: - foo(a) - a.next() - """ - a = """ - for a in b: - foo(a) - next(a) - """ - self.check(b, a) - - def test_prefix_preservation_2(self): - b = """ - for a in b: - foo(a) # abc - # def - a.next() - """ - a = """ - for a in b: - foo(a) # abc - # def - next(a) - """ - self.check(b, a) - - def test_prefix_preservation_3(self): - b = """ - next = 5 - for a in b: - foo(a) - a.next() - """ - a = """ - next = 5 - for a in b: - foo(a) - a.__next__() - """ - self.check(b, a, ignore_warnings=True) - - def test_prefix_preservation_4(self): - b = """ - next = 5 - for a in b: - foo(a) # abc - # def - a.next() - """ - a = """ - next = 5 - for a in b: - foo(a) # abc - # def - a.__next__() - """ - self.check(b, a, ignore_warnings=True) - - def test_prefix_preservation_5(self): - b = """ - next = 5 - for a in b: - foo(foo(a), # abc - a.next()) - """ - a = """ - next = 5 - for a in b: - foo(foo(a), # abc - a.__next__()) - """ - self.check(b, a, ignore_warnings=True) - - def test_prefix_preservation_6(self): - b = """ - for a in b: - foo(foo(a), # abc - a.next()) - """ - a = """ - for a in b: - foo(foo(a), # abc - next(a)) - """ - self.check(b, a) - - def test_method_1(self): - b = """ - class A: - def next(self): - pass - """ - a = """ - class A: - def __next__(self): - pass - """ - self.check(b, a) - - def test_method_2(self): - b = """ - class A(object): - def next(self): - pass - """ - a = """ - class A(object): - def __next__(self): - pass - """ - self.check(b, a) - - def test_method_3(self): - b = """ - class A: - def next(x): - pass - """ - a = """ - class A: - def __next__(x): - pass - """ - self.check(b, a) - - def test_method_4(self): - b = """ - class A: - def __init__(self, foo): - self.foo = foo - - def next(self): - pass - - def __iter__(self): - return self - """ - a = """ - class A: - def __init__(self, foo): - self.foo = foo - - def __next__(self): - pass - - def __iter__(self): - return self - """ - self.check(b, a) - - def test_method_unchanged(self): - s = """ - class A: - def next(self, a, b): - pass - """ - self.unchanged(s) - - def test_shadowing_assign_simple(self): - s = """ - next = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_assign_tuple_1(self): - s = """ - (next, a) = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_assign_tuple_2(self): - s = """ - (a, (b, (next, c)), a) = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_assign_list_1(self): - s = """ - [next, a] = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_assign_list_2(self): - s = """ - [a, [b, [next, c]], a] = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_builtin_assign(self): - s = """ - def foo(): - __builtin__.next = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_builtin_assign_in_tuple(self): - s = """ - def foo(): - (a, __builtin__.next) = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_builtin_assign_in_list(self): - s = """ - def foo(): - [a, __builtin__.next] = foo - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_assign_to_next(self): - s = """ - def foo(): - A.next = foo - - class A: - def next(self, a, b): - pass - """ - self.unchanged(s) - - def test_assign_to_next_in_tuple(self): - s = """ - def foo(): - (a, A.next) = foo - - class A: - def next(self, a, b): - pass - """ - self.unchanged(s) - - def test_assign_to_next_in_list(self): - s = """ - def foo(): - [a, A.next] = foo - - class A: - def next(self, a, b): - pass - """ - self.unchanged(s) - - def test_shadowing_import_1(self): - s = """ - import foo.bar as next - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_import_2(self): - s = """ - import bar, bar.foo as next - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_import_3(self): - s = """ - import bar, bar.foo as next, baz - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_import_from_1(self): - s = """ - from x import next - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_import_from_2(self): - s = """ - from x.a import next - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_import_from_3(self): - s = """ - from x import a, next, b - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_import_from_4(self): - s = """ - from x.a import a, next, b - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_funcdef_1(self): - s = """ - def next(a): - pass - - class A: - def next(self, a, b): - pass - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_funcdef_2(self): - b = """ - def next(a): - pass - - class A: - def next(self): - pass - - it.next() - """ - a = """ - def next(a): - pass - - class A: - def __next__(self): - pass - - it.__next__() - """ - self.warns(b, a, "Calls to builtin next() possibly shadowed") - - def test_shadowing_global_1(self): - s = """ - def f(): - global next - next = 5 - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_global_2(self): - s = """ - def f(): - global a, next, b - next = 5 - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_for_simple(self): - s = """ - for next in it(): - pass - - b = 5 - c = 6 - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_for_tuple_1(self): - s = """ - for next, b in it(): - pass - - b = 5 - c = 6 - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_shadowing_for_tuple_2(self): - s = """ - for a, (next, c), b in it(): - pass - - b = 5 - c = 6 - """ - self.warns_unchanged(s, "Calls to builtin next() possibly shadowed") - - def test_noncall_access_1(self): - b = """gnext = g.next""" - a = """gnext = g.__next__""" - self.check(b, a) - - def test_noncall_access_2(self): - b = """f(g.next + 5)""" - a = """f(g.__next__ + 5)""" - self.check(b, a) - - def test_noncall_access_3(self): - b = """f(g().next + 5)""" - a = """f(g().__next__ + 5)""" - self.check(b, a) - -class Test_nonzero(FixerTestCase): - fixer = "nonzero" - - def test_1(self): - b = """ - class A: - def __nonzero__(self): - pass - """ - a = """ - class A: - def __bool__(self): - pass - """ - self.check(b, a) - - def test_2(self): - b = """ - class A(object): - def __nonzero__(self): - pass - """ - a = """ - class A(object): - def __bool__(self): - pass - """ - self.check(b, a) - - def test_unchanged_1(self): - s = """ - class A(object): - def __bool__(self): - pass - """ - self.unchanged(s) - - def test_unchanged_2(self): - s = """ - class A(object): - def __nonzero__(self, a): - pass - """ - self.unchanged(s) - - def test_unchanged_func(self): - s = """ - def __nonzero__(self): - pass - """ - self.unchanged(s) - -class Test_numliterals(FixerTestCase): - fixer = "numliterals" - - def test_octal_1(self): - b = """0755""" - a = """0o755""" - self.check(b, a) - - def test_long_int_1(self): - b = """a = 12L""" - a = """a = 12""" - self.check(b, a) - - def test_long_int_2(self): - b = """a = 12l""" - a = """a = 12""" - self.check(b, a) - - def test_long_hex(self): - b = """b = 0x12l""" - a = """b = 0x12""" - self.check(b, a) - - def test_comments_and_spacing(self): - b = """b = 0x12L""" - a = """b = 0x12""" - self.check(b, a) - - b = """b = 0755 # spam""" - a = """b = 0o755 # spam""" - self.check(b, a) - - def test_unchanged_int(self): - s = """5""" - self.unchanged(s) - - def test_unchanged_float(self): - s = """5.0""" - self.unchanged(s) - - def test_unchanged_octal(self): - s = """0o755""" - self.unchanged(s) - - def test_unchanged_hex(self): - s = """0xABC""" - self.unchanged(s) - - def test_unchanged_exp(self): - s = """5.0e10""" - self.unchanged(s) - - def test_unchanged_complex_int(self): - s = """5 + 4j""" - self.unchanged(s) - - def test_unchanged_complex_float(self): - s = """5.4 + 4.9j""" - self.unchanged(s) - - def test_unchanged_complex_bare(self): - s = """4j""" - self.unchanged(s) - s = """4.4j""" - self.unchanged(s) - -class Test_renames(FixerTestCase): - fixer = "renames" - - modules = {"sys": ("maxint", "maxsize"), - } - - def test_import_from(self): - for mod, (old, new) in list(self.modules.items()): - b = "from %s import %s" % (mod, old) - a = "from %s import %s" % (mod, new) - self.check(b, a) - - s = "from foo import %s" % old - self.unchanged(s) - - def test_import_from_as(self): - for mod, (old, new) in list(self.modules.items()): - b = "from %s import %s as foo_bar" % (mod, old) - a = "from %s import %s as foo_bar" % (mod, new) - self.check(b, a) - - def test_import_module_usage(self): - for mod, (old, new) in list(self.modules.items()): - b = """ - import %s - foo(%s, %s.%s) - """ % (mod, mod, mod, old) - a = """ - import %s - foo(%s, %s.%s) - """ % (mod, mod, mod, new) - self.check(b, a) - - def XXX_test_from_import_usage(self): - # not implemented yet - for mod, (old, new) in list(self.modules.items()): - b = """ - from %s import %s - foo(%s, %s) - """ % (mod, old, mod, old) - a = """ - from %s import %s - foo(%s, %s) - """ % (mod, new, mod, new) - self.check(b, a) - -class Test_unicode(FixerTestCase): - fixer = "unicode" - - def test_whitespace(self): - b = """unicode( x)""" - a = """str( x)""" - self.check(b, a) - - b = """ unicode(x )""" - a = """ str(x )""" - self.check(b, a) - - b = """ u'h'""" - a = """ 'h'""" - self.check(b, a) - - def test_unicode_call(self): - b = """unicode(x, y, z)""" - a = """str(x, y, z)""" - self.check(b, a) - - def test_unichr(self): - b = """unichr(u'h')""" - a = """chr('h')""" - self.check(b, a) - - def test_unicode_literal_1(self): - b = '''u"x"''' - a = '''"x"''' - self.check(b, a) - - def test_unicode_literal_2(self): - b = """ur'x'""" - a = """r'x'""" - self.check(b, a) - - def test_unicode_literal_3(self): - b = """UR'''x''' """ - a = """R'''x''' """ - self.check(b, a) - - def test_native_literal_escape_u(self): - b = r"""'\\\u20ac\U0001d121\\u20ac'""" - a = r"""'\\\\u20ac\\U0001d121\\u20ac'""" - self.check(b, a) - - b = r"""r'\\\u20ac\U0001d121\\u20ac'""" - a = r"""r'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - def test_bytes_literal_escape_u(self): - b = r"""b'\\\u20ac\U0001d121\\u20ac'""" - a = r"""b'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - b = r"""br'\\\u20ac\U0001d121\\u20ac'""" - a = r"""br'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - def test_unicode_literal_escape_u(self): - b = r"""u'\\\u20ac\U0001d121\\u20ac'""" - a = r"""'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - b = r"""ur'\\\u20ac\U0001d121\\u20ac'""" - a = r"""r'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - def test_native_unicode_literal_escape_u(self): - f = 'from __future__ import unicode_literals\n' - b = f + r"""'\\\u20ac\U0001d121\\u20ac'""" - a = f + r"""'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - b = f + r"""r'\\\u20ac\U0001d121\\u20ac'""" - a = f + r"""r'\\\u20ac\U0001d121\\u20ac'""" - self.check(b, a) - - -class Test_filter(FixerTestCase): - fixer = "filter" - - def test_prefix_preservation(self): - b = """x = filter( foo, 'abc' )""" - a = """x = list(filter( foo, 'abc' ))""" - self.check(b, a) - - b = """x = filter( None , 'abc' )""" - a = """x = [_f for _f in 'abc' if _f]""" - self.check(b, a) - - def test_filter_basic(self): - b = """x = filter(None, 'abc')""" - a = """x = [_f for _f in 'abc' if _f]""" - self.check(b, a) - - b = """x = len(filter(f, 'abc'))""" - a = """x = len(list(filter(f, 'abc')))""" - self.check(b, a) - - b = """x = filter(lambda x: x%2 == 0, range(10))""" - a = """x = [x for x in range(10) if x%2 == 0]""" - self.check(b, a) - - # Note the parens around x - b = """x = filter(lambda (x): x%2 == 0, range(10))""" - a = """x = [x for x in range(10) if x%2 == 0]""" - self.check(b, a) - - # bpo-38871 - b = """filter(lambda x: True if x > 2 else False, [1, 2, 3])""" - a = """[x for x in [1, 2, 3] if (True if x > 2 else False)]""" - self.check(b, a) - - def test_filter_trailers(self): - b = """x = filter(None, 'abc')[0]""" - a = """x = [_f for _f in 'abc' if _f][0]""" - self.check(b, a) - - b = """x = len(filter(f, 'abc')[0])""" - a = """x = len(list(filter(f, 'abc'))[0])""" - self.check(b, a) - - b = """x = filter(lambda x: x%2 == 0, range(10))[0]""" - a = """x = [x for x in range(10) if x%2 == 0][0]""" - self.check(b, a) - - # Note the parens around x - b = """x = filter(lambda (x): x%2 == 0, range(10))[0]""" - a = """x = [x for x in range(10) if x%2 == 0][0]""" - self.check(b, a) - - def test_filter_nochange(self): - a = """b.join(filter(f, 'abc'))""" - self.unchanged(a) - a = """(a + foo(5)).join(filter(f, 'abc'))""" - self.unchanged(a) - a = """iter(filter(f, 'abc'))""" - self.unchanged(a) - a = """list(filter(f, 'abc'))""" - self.unchanged(a) - a = """list(filter(f, 'abc'))[0]""" - self.unchanged(a) - a = """set(filter(f, 'abc'))""" - self.unchanged(a) - a = """set(filter(f, 'abc')).pop()""" - self.unchanged(a) - a = """tuple(filter(f, 'abc'))""" - self.unchanged(a) - a = """any(filter(f, 'abc'))""" - self.unchanged(a) - a = """all(filter(f, 'abc'))""" - self.unchanged(a) - a = """sum(filter(f, 'abc'))""" - self.unchanged(a) - a = """sorted(filter(f, 'abc'))""" - self.unchanged(a) - a = """sorted(filter(f, 'abc'), key=blah)""" - self.unchanged(a) - a = """sorted(filter(f, 'abc'), key=blah)[0]""" - self.unchanged(a) - a = """enumerate(filter(f, 'abc'))""" - self.unchanged(a) - a = """enumerate(filter(f, 'abc'), start=1)""" - self.unchanged(a) - a = """for i in filter(f, 'abc'): pass""" - self.unchanged(a) - a = """[x for x in filter(f, 'abc')]""" - self.unchanged(a) - a = """(x for x in filter(f, 'abc'))""" - self.unchanged(a) - - def test_future_builtins(self): - a = "from future_builtins import spam, filter; filter(f, 'ham')" - self.unchanged(a) - - b = """from future_builtins import spam; x = filter(f, 'abc')""" - a = """from future_builtins import spam; x = list(filter(f, 'abc'))""" - self.check(b, a) - - a = "from future_builtins import *; filter(f, 'ham')" - self.unchanged(a) - -class Test_map(FixerTestCase): - fixer = "map" - - def check(self, b, a): - self.unchanged("from future_builtins import map; " + b, a) - super(Test_map, self).check(b, a) - - def test_prefix_preservation(self): - b = """x = map( f, 'abc' )""" - a = """x = list(map( f, 'abc' ))""" - self.check(b, a) - - def test_map_trailers(self): - b = """x = map(f, 'abc')[0]""" - a = """x = list(map(f, 'abc'))[0]""" - self.check(b, a) - - b = """x = map(None, l)[0]""" - a = """x = list(l)[0]""" - self.check(b, a) - - b = """x = map(lambda x:x, l)[0]""" - a = """x = [x for x in l][0]""" - self.check(b, a) - - b = """x = map(f, 'abc')[0][1]""" - a = """x = list(map(f, 'abc'))[0][1]""" - self.check(b, a) - - def test_trailing_comment(self): - b = """x = map(f, 'abc') # foo""" - a = """x = list(map(f, 'abc')) # foo""" - self.check(b, a) - - def test_None_with_multiple_arguments(self): - s = """x = map(None, a, b, c)""" - self.warns_unchanged(s, "cannot convert map(None, ...) with " - "multiple arguments") - - def test_map_basic(self): - b = """x = map(f, 'abc')""" - a = """x = list(map(f, 'abc'))""" - self.check(b, a) - - b = """x = len(map(f, 'abc', 'def'))""" - a = """x = len(list(map(f, 'abc', 'def')))""" - self.check(b, a) - - b = """x = map(None, 'abc')""" - a = """x = list('abc')""" - self.check(b, a) - - b = """x = map(lambda x: x+1, range(4))""" - a = """x = [x+1 for x in range(4)]""" - self.check(b, a) - - # Note the parens around x - b = """x = map(lambda (x): x+1, range(4))""" - a = """x = [x+1 for x in range(4)]""" - self.check(b, a) - - b = """ - foo() - # foo - map(f, x) - """ - a = """ - foo() - # foo - list(map(f, x)) - """ - self.warns(b, a, "You should use a for loop here") - - def test_map_nochange(self): - a = """b.join(map(f, 'abc'))""" - self.unchanged(a) - a = """(a + foo(5)).join(map(f, 'abc'))""" - self.unchanged(a) - a = """iter(map(f, 'abc'))""" - self.unchanged(a) - a = """list(map(f, 'abc'))""" - self.unchanged(a) - a = """list(map(f, 'abc'))[0]""" - self.unchanged(a) - a = """set(map(f, 'abc'))""" - self.unchanged(a) - a = """set(map(f, 'abc')).pop()""" - self.unchanged(a) - a = """tuple(map(f, 'abc'))""" - self.unchanged(a) - a = """any(map(f, 'abc'))""" - self.unchanged(a) - a = """all(map(f, 'abc'))""" - self.unchanged(a) - a = """sum(map(f, 'abc'))""" - self.unchanged(a) - a = """sorted(map(f, 'abc'))""" - self.unchanged(a) - a = """sorted(map(f, 'abc'), key=blah)""" - self.unchanged(a) - a = """sorted(map(f, 'abc'), key=blah)[0]""" - self.unchanged(a) - a = """enumerate(map(f, 'abc'))""" - self.unchanged(a) - a = """enumerate(map(f, 'abc'), start=1)""" - self.unchanged(a) - a = """for i in map(f, 'abc'): pass""" - self.unchanged(a) - a = """[x for x in map(f, 'abc')]""" - self.unchanged(a) - a = """(x for x in map(f, 'abc'))""" - self.unchanged(a) - - def test_future_builtins(self): - a = "from future_builtins import spam, map, eggs; map(f, 'ham')" - self.unchanged(a) - - b = """from future_builtins import spam, eggs; x = map(f, 'abc')""" - a = """from future_builtins import spam, eggs; x = list(map(f, 'abc'))""" - self.check(b, a) - - a = "from future_builtins import *; map(f, 'ham')" - self.unchanged(a) - -class Test_zip(FixerTestCase): - fixer = "zip" - - def check(self, b, a): - self.unchanged("from future_builtins import zip; " + b, a) - super(Test_zip, self).check(b, a) - - def test_zip_basic(self): - b = """x = zip()""" - a = """x = list(zip())""" - self.check(b, a) - - b = """x = zip(a, b, c)""" - a = """x = list(zip(a, b, c))""" - self.check(b, a) - - b = """x = len(zip(a, b))""" - a = """x = len(list(zip(a, b)))""" - self.check(b, a) - - def test_zip_trailers(self): - b = """x = zip(a, b, c)[0]""" - a = """x = list(zip(a, b, c))[0]""" - self.check(b, a) - - b = """x = zip(a, b, c)[0][1]""" - a = """x = list(zip(a, b, c))[0][1]""" - self.check(b, a) - - def test_zip_nochange(self): - a = """b.join(zip(a, b))""" - self.unchanged(a) - a = """(a + foo(5)).join(zip(a, b))""" - self.unchanged(a) - a = """iter(zip(a, b))""" - self.unchanged(a) - a = """list(zip(a, b))""" - self.unchanged(a) - a = """list(zip(a, b))[0]""" - self.unchanged(a) - a = """set(zip(a, b))""" - self.unchanged(a) - a = """set(zip(a, b)).pop()""" - self.unchanged(a) - a = """tuple(zip(a, b))""" - self.unchanged(a) - a = """any(zip(a, b))""" - self.unchanged(a) - a = """all(zip(a, b))""" - self.unchanged(a) - a = """sum(zip(a, b))""" - self.unchanged(a) - a = """sorted(zip(a, b))""" - self.unchanged(a) - a = """sorted(zip(a, b), key=blah)""" - self.unchanged(a) - a = """sorted(zip(a, b), key=blah)[0]""" - self.unchanged(a) - a = """enumerate(zip(a, b))""" - self.unchanged(a) - a = """enumerate(zip(a, b), start=1)""" - self.unchanged(a) - a = """for i in zip(a, b): pass""" - self.unchanged(a) - a = """[x for x in zip(a, b)]""" - self.unchanged(a) - a = """(x for x in zip(a, b))""" - self.unchanged(a) - - def test_future_builtins(self): - a = "from future_builtins import spam, zip, eggs; zip(a, b)" - self.unchanged(a) - - b = """from future_builtins import spam, eggs; x = zip(a, b)""" - a = """from future_builtins import spam, eggs; x = list(zip(a, b))""" - self.check(b, a) - - a = "from future_builtins import *; zip(a, b)" - self.unchanged(a) - -class Test_standarderror(FixerTestCase): - fixer = "standarderror" - - def test(self): - b = """x = StandardError()""" - a = """x = Exception()""" - self.check(b, a) - - b = """x = StandardError(a, b, c)""" - a = """x = Exception(a, b, c)""" - self.check(b, a) - - b = """f(2 + StandardError(a, b, c))""" - a = """f(2 + Exception(a, b, c))""" - self.check(b, a) - -class Test_types(FixerTestCase): - fixer = "types" - - def test_basic_types_convert(self): - b = """types.StringType""" - a = """bytes""" - self.check(b, a) - - b = """types.DictType""" - a = """dict""" - self.check(b, a) - - b = """types . IntType""" - a = """int""" - self.check(b, a) - - b = """types.ListType""" - a = """list""" - self.check(b, a) - - b = """types.LongType""" - a = """int""" - self.check(b, a) - - b = """types.NoneType""" - a = """type(None)""" - self.check(b, a) - - b = "types.StringTypes" - a = "(str,)" - self.check(b, a) - -class Test_idioms(FixerTestCase): - fixer = "idioms" - - def test_while(self): - b = """while 1: foo()""" - a = """while True: foo()""" - self.check(b, a) - - b = """while 1: foo()""" - a = """while True: foo()""" - self.check(b, a) - - b = """ - while 1: - foo() - """ - a = """ - while True: - foo() - """ - self.check(b, a) - - def test_while_unchanged(self): - s = """while 11: foo()""" - self.unchanged(s) - - s = """while 0: foo()""" - self.unchanged(s) - - s = """while foo(): foo()""" - self.unchanged(s) - - s = """while []: foo()""" - self.unchanged(s) - - def test_eq_simple(self): - b = """type(x) == T""" - a = """isinstance(x, T)""" - self.check(b, a) - - b = """if type(x) == T: pass""" - a = """if isinstance(x, T): pass""" - self.check(b, a) - - def test_eq_reverse(self): - b = """T == type(x)""" - a = """isinstance(x, T)""" - self.check(b, a) - - b = """if T == type(x): pass""" - a = """if isinstance(x, T): pass""" - self.check(b, a) - - def test_eq_expression(self): - b = """type(x+y) == d.get('T')""" - a = """isinstance(x+y, d.get('T'))""" - self.check(b, a) - - b = """type( x + y) == d.get('T')""" - a = """isinstance(x + y, d.get('T'))""" - self.check(b, a) - - def test_is_simple(self): - b = """type(x) is T""" - a = """isinstance(x, T)""" - self.check(b, a) - - b = """if type(x) is T: pass""" - a = """if isinstance(x, T): pass""" - self.check(b, a) - - def test_is_reverse(self): - b = """T is type(x)""" - a = """isinstance(x, T)""" - self.check(b, a) - - b = """if T is type(x): pass""" - a = """if isinstance(x, T): pass""" - self.check(b, a) - - def test_is_expression(self): - b = """type(x+y) is d.get('T')""" - a = """isinstance(x+y, d.get('T'))""" - self.check(b, a) - - b = """type( x + y) is d.get('T')""" - a = """isinstance(x + y, d.get('T'))""" - self.check(b, a) - - def test_is_not_simple(self): - b = """type(x) is not T""" - a = """not isinstance(x, T)""" - self.check(b, a) - - b = """if type(x) is not T: pass""" - a = """if not isinstance(x, T): pass""" - self.check(b, a) - - def test_is_not_reverse(self): - b = """T is not type(x)""" - a = """not isinstance(x, T)""" - self.check(b, a) - - b = """if T is not type(x): pass""" - a = """if not isinstance(x, T): pass""" - self.check(b, a) - - def test_is_not_expression(self): - b = """type(x+y) is not d.get('T')""" - a = """not isinstance(x+y, d.get('T'))""" - self.check(b, a) - - b = """type( x + y) is not d.get('T')""" - a = """not isinstance(x + y, d.get('T'))""" - self.check(b, a) - - def test_ne_simple(self): - b = """type(x) != T""" - a = """not isinstance(x, T)""" - self.check(b, a) - - b = """if type(x) != T: pass""" - a = """if not isinstance(x, T): pass""" - self.check(b, a) - - def test_ne_reverse(self): - b = """T != type(x)""" - a = """not isinstance(x, T)""" - self.check(b, a) - - b = """if T != type(x): pass""" - a = """if not isinstance(x, T): pass""" - self.check(b, a) - - def test_ne_expression(self): - b = """type(x+y) != d.get('T')""" - a = """not isinstance(x+y, d.get('T'))""" - self.check(b, a) - - b = """type( x + y) != d.get('T')""" - a = """not isinstance(x + y, d.get('T'))""" - self.check(b, a) - - def test_type_unchanged(self): - a = """type(x).__name__""" - self.unchanged(a) - - def test_sort_list_call(self): - b = """ - v = list(t) - v.sort() - foo(v) - """ - a = """ - v = sorted(t) - foo(v) - """ - self.check(b, a) - - b = """ - v = list(foo(b) + d) - v.sort() - foo(v) - """ - a = """ - v = sorted(foo(b) + d) - foo(v) - """ - self.check(b, a) - - b = """ - while x: - v = list(t) - v.sort() - foo(v) - """ - a = """ - while x: - v = sorted(t) - foo(v) - """ - self.check(b, a) - - b = """ - v = list(t) - # foo - v.sort() - foo(v) - """ - a = """ - v = sorted(t) - # foo - foo(v) - """ - self.check(b, a) - - b = r""" - v = list( t) - v.sort() - foo(v) - """ - a = r""" - v = sorted( t) - foo(v) - """ - self.check(b, a) - - b = r""" - try: - m = list(s) - m.sort() - except: pass - """ - - a = r""" - try: - m = sorted(s) - except: pass - """ - self.check(b, a) - - b = r""" - try: - m = list(s) - # foo - m.sort() - except: pass - """ - - a = r""" - try: - m = sorted(s) - # foo - except: pass - """ - self.check(b, a) - - b = r""" - m = list(s) - # more comments - m.sort()""" - - a = r""" - m = sorted(s) - # more comments""" - self.check(b, a) - - def test_sort_simple_expr(self): - b = """ - v = t - v.sort() - foo(v) - """ - a = """ - v = sorted(t) - foo(v) - """ - self.check(b, a) - - b = """ - v = foo(b) - v.sort() - foo(v) - """ - a = """ - v = sorted(foo(b)) - foo(v) - """ - self.check(b, a) - - b = """ - v = b.keys() - v.sort() - foo(v) - """ - a = """ - v = sorted(b.keys()) - foo(v) - """ - self.check(b, a) - - b = """ - v = foo(b) + d - v.sort() - foo(v) - """ - a = """ - v = sorted(foo(b) + d) - foo(v) - """ - self.check(b, a) - - b = """ - while x: - v = t - v.sort() - foo(v) - """ - a = """ - while x: - v = sorted(t) - foo(v) - """ - self.check(b, a) - - b = """ - v = t - # foo - v.sort() - foo(v) - """ - a = """ - v = sorted(t) - # foo - foo(v) - """ - self.check(b, a) - - b = r""" - v = t - v.sort() - foo(v) - """ - a = r""" - v = sorted(t) - foo(v) - """ - self.check(b, a) - - def test_sort_unchanged(self): - s = """ - v = list(t) - w.sort() - foo(w) - """ - self.unchanged(s) - - s = """ - v = list(t) - v.sort(u) - foo(v) - """ - self.unchanged(s) - -class Test_basestring(FixerTestCase): - fixer = "basestring" - - def test_basestring(self): - b = """isinstance(x, basestring)""" - a = """isinstance(x, str)""" - self.check(b, a) - -class Test_buffer(FixerTestCase): - fixer = "buffer" - - def test_buffer(self): - b = """x = buffer(y)""" - a = """x = memoryview(y)""" - self.check(b, a) - - def test_slicing(self): - b = """buffer(y)[4:5]""" - a = """memoryview(y)[4:5]""" - self.check(b, a) - -class Test_future(FixerTestCase): - fixer = "future" - - def test_future(self): - b = """from __future__ import braces""" - a = """""" - self.check(b, a) - - b = """# comment\nfrom __future__ import braces""" - a = """# comment\n""" - self.check(b, a) - - b = """from __future__ import braces\n# comment""" - a = """\n# comment""" - self.check(b, a) - - def test_run_order(self): - self.assert_runs_after('print') - -class Test_itertools(FixerTestCase): - fixer = "itertools" - - def checkall(self, before, after): - # Because we need to check with and without the itertools prefix - # and on each of the three functions, these loops make it all - # much easier - for i in ('itertools.', ''): - for f in ('map', 'filter', 'zip'): - b = before %(i+'i'+f) - a = after %(f) - self.check(b, a) - - def test_0(self): - # A simple example -- test_1 covers exactly the same thing, - # but it's not quite as clear. - b = "itertools.izip(a, b)" - a = "zip(a, b)" - self.check(b, a) - - def test_1(self): - b = """%s(f, a)""" - a = """%s(f, a)""" - self.checkall(b, a) - - def test_qualified(self): - b = """itertools.ifilterfalse(a, b)""" - a = """itertools.filterfalse(a, b)""" - self.check(b, a) - - b = """itertools.izip_longest(a, b)""" - a = """itertools.zip_longest(a, b)""" - self.check(b, a) - - def test_2(self): - b = """ifilterfalse(a, b)""" - a = """filterfalse(a, b)""" - self.check(b, a) - - b = """izip_longest(a, b)""" - a = """zip_longest(a, b)""" - self.check(b, a) - - def test_space_1(self): - b = """ %s(f, a)""" - a = """ %s(f, a)""" - self.checkall(b, a) - - def test_space_2(self): - b = """ itertools.ifilterfalse(a, b)""" - a = """ itertools.filterfalse(a, b)""" - self.check(b, a) - - b = """ itertools.izip_longest(a, b)""" - a = """ itertools.zip_longest(a, b)""" - self.check(b, a) - - def test_run_order(self): - self.assert_runs_after('map', 'zip', 'filter') - - -class Test_itertools_imports(FixerTestCase): - fixer = 'itertools_imports' - - def test_reduced(self): - b = "from itertools import imap, izip, foo" - a = "from itertools import foo" - self.check(b, a) - - b = "from itertools import bar, imap, izip, foo" - a = "from itertools import bar, foo" - self.check(b, a) - - b = "from itertools import chain, imap, izip" - a = "from itertools import chain" - self.check(b, a) - - def test_comments(self): - b = "#foo\nfrom itertools import imap, izip" - a = "#foo\n" - self.check(b, a) - - def test_none(self): - b = "from itertools import imap, izip" - a = "" - self.check(b, a) - - b = "from itertools import izip" - a = "" - self.check(b, a) - - def test_import_as(self): - b = "from itertools import izip, bar as bang, imap" - a = "from itertools import bar as bang" - self.check(b, a) - - b = "from itertools import izip as _zip, imap, bar" - a = "from itertools import bar" - self.check(b, a) - - b = "from itertools import imap as _map" - a = "" - self.check(b, a) - - b = "from itertools import imap as _map, izip as _zip" - a = "" - self.check(b, a) - - s = "from itertools import bar as bang" - self.unchanged(s) - - def test_ifilter_and_zip_longest(self): - for name in "filterfalse", "zip_longest": - b = "from itertools import i%s" % (name,) - a = "from itertools import %s" % (name,) - self.check(b, a) - - b = "from itertools import imap, i%s, foo" % (name,) - a = "from itertools import %s, foo" % (name,) - self.check(b, a) - - b = "from itertools import bar, i%s, foo" % (name,) - a = "from itertools import bar, %s, foo" % (name,) - self.check(b, a) - - def test_import_star(self): - s = "from itertools import *" - self.unchanged(s) - - - def test_unchanged(self): - s = "from itertools import foo" - self.unchanged(s) - - -class Test_import(FixerTestCase): - fixer = "import" - - def setUp(self): - super(Test_import, self).setUp() - # Need to replace fix_import's exists method - # so we can check that it's doing the right thing - self.files_checked = [] - self.present_files = set() - self.always_exists = True - def fake_exists(name): - self.files_checked.append(name) - return self.always_exists or (name in self.present_files) - - from lib2to3.fixes import fix_import - fix_import.exists = fake_exists - - def tearDown(self): - from lib2to3.fixes import fix_import - fix_import.exists = os.path.exists - - def check_both(self, b, a): - self.always_exists = True - super(Test_import, self).check(b, a) - self.always_exists = False - super(Test_import, self).unchanged(b) - - def test_files_checked(self): - def p(path): - # Takes a unix path and returns a path with correct separators - return os.path.pathsep.join(path.split("/")) - - self.always_exists = False - self.present_files = set(['__init__.py']) - expected_extensions = ('.py', os.path.sep, '.pyc', '.so', '.sl', '.pyd') - names_to_test = (p("/spam/eggs.py"), "ni.py", p("../../shrubbery.py")) - - for name in names_to_test: - self.files_checked = [] - self.filename = name - self.unchanged("import jam") - - if os.path.dirname(name): - name = os.path.dirname(name) + '/jam' - else: - name = 'jam' - expected_checks = set(name + ext for ext in expected_extensions) - expected_checks.add("__init__.py") - - self.assertEqual(set(self.files_checked), expected_checks) - - def test_not_in_package(self): - s = "import bar" - self.always_exists = False - self.present_files = set(["bar.py"]) - self.unchanged(s) - - def test_with_absolute_import_enabled(self): - s = "from __future__ import absolute_import\nimport bar" - self.always_exists = False - self.present_files = set(["__init__.py", "bar.py"]) - self.unchanged(s) - - def test_in_package(self): - b = "import bar" - a = "from . import bar" - self.always_exists = False - self.present_files = set(["__init__.py", "bar.py"]) - self.check(b, a) - - def test_import_from_package(self): - b = "import bar" - a = "from . import bar" - self.always_exists = False - self.present_files = set(["__init__.py", "bar" + os.path.sep]) - self.check(b, a) - - def test_already_relative_import(self): - s = "from . import bar" - self.unchanged(s) - - def test_comments_and_indent(self): - b = "import bar # Foo" - a = "from . import bar # Foo" - self.check(b, a) - - def test_from(self): - b = "from foo import bar, baz" - a = "from .foo import bar, baz" - self.check_both(b, a) - - b = "from foo import bar" - a = "from .foo import bar" - self.check_both(b, a) - - b = "from foo import (bar, baz)" - a = "from .foo import (bar, baz)" - self.check_both(b, a) - - def test_dotted_from(self): - b = "from green.eggs import ham" - a = "from .green.eggs import ham" - self.check_both(b, a) - - def test_from_as(self): - b = "from green.eggs import ham as spam" - a = "from .green.eggs import ham as spam" - self.check_both(b, a) - - def test_import(self): - b = "import foo" - a = "from . import foo" - self.check_both(b, a) - - b = "import foo, bar" - a = "from . import foo, bar" - self.check_both(b, a) - - b = "import foo, bar, x" - a = "from . import foo, bar, x" - self.check_both(b, a) - - b = "import x, y, z" - a = "from . import x, y, z" - self.check_both(b, a) - - def test_import_as(self): - b = "import foo as x" - a = "from . import foo as x" - self.check_both(b, a) - - b = "import a as b, b as c, c as d" - a = "from . import a as b, b as c, c as d" - self.check_both(b, a) - - def test_local_and_absolute(self): - self.always_exists = False - self.present_files = set(["foo.py", "__init__.py"]) - - s = "import foo, bar" - self.warns_unchanged(s, "absolute and local imports together") - - def test_dotted_import(self): - b = "import foo.bar" - a = "from . import foo.bar" - self.check_both(b, a) - - def test_dotted_import_as(self): - b = "import foo.bar as bang" - a = "from . import foo.bar as bang" - self.check_both(b, a) - - def test_prefix(self): - b = """ - # prefix - import foo.bar - """ - a = """ - # prefix - from . import foo.bar - """ - self.check_both(b, a) - - -class Test_set_literal(FixerTestCase): - - fixer = "set_literal" - - def test_basic(self): - b = """set([1, 2, 3])""" - a = """{1, 2, 3}""" - self.check(b, a) - - b = """set((1, 2, 3))""" - a = """{1, 2, 3}""" - self.check(b, a) - - b = """set((1,))""" - a = """{1}""" - self.check(b, a) - - b = """set([1])""" - self.check(b, a) - - b = """set((a, b))""" - a = """{a, b}""" - self.check(b, a) - - b = """set([a, b])""" - self.check(b, a) - - b = """set((a*234, f(args=23)))""" - a = """{a*234, f(args=23)}""" - self.check(b, a) - - b = """set([a*23, f(23)])""" - a = """{a*23, f(23)}""" - self.check(b, a) - - b = """set([a-234**23])""" - a = """{a-234**23}""" - self.check(b, a) - - def test_listcomps(self): - b = """set([x for x in y])""" - a = """{x for x in y}""" - self.check(b, a) - - b = """set([x for x in y if x == m])""" - a = """{x for x in y if x == m}""" - self.check(b, a) - - b = """set([x for x in y for a in b])""" - a = """{x for x in y for a in b}""" - self.check(b, a) - - b = """set([f(x) - 23 for x in y])""" - a = """{f(x) - 23 for x in y}""" - self.check(b, a) - - def test_whitespace(self): - b = """set( [1, 2])""" - a = """{1, 2}""" - self.check(b, a) - - b = """set([1 , 2])""" - a = """{1 , 2}""" - self.check(b, a) - - b = """set([ 1 ])""" - a = """{ 1 }""" - self.check(b, a) - - b = """set( [1] )""" - a = """{1}""" - self.check(b, a) - - b = """set([ 1, 2 ])""" - a = """{ 1, 2 }""" - self.check(b, a) - - b = """set([x for x in y ])""" - a = """{x for x in y }""" - self.check(b, a) - - b = """set( - [1, 2] - ) - """ - a = """{1, 2}\n""" - self.check(b, a) - - def test_comments(self): - b = """set((1, 2)) # Hi""" - a = """{1, 2} # Hi""" - self.check(b, a) - - # This isn't optimal behavior, but the fixer is optional. - b = """ - # Foo - set( # Bar - (1, 2) - ) - """ - a = """ - # Foo - {1, 2} - """ - self.check(b, a) - - def test_unchanged(self): - s = """set()""" - self.unchanged(s) - - s = """set(a)""" - self.unchanged(s) - - s = """set(a, b, c)""" - self.unchanged(s) - - # Don't transform generators because they might have to be lazy. - s = """set(x for x in y)""" - self.unchanged(s) - - s = """set(x for x in y if z)""" - self.unchanged(s) - - s = """set(a*823-23**2 + f(23))""" - self.unchanged(s) - - -class Test_sys_exc(FixerTestCase): - fixer = "sys_exc" - - def test_0(self): - b = "sys.exc_type" - a = "sys.exc_info()[0]" - self.check(b, a) - - def test_1(self): - b = "sys.exc_value" - a = "sys.exc_info()[1]" - self.check(b, a) - - def test_2(self): - b = "sys.exc_traceback" - a = "sys.exc_info()[2]" - self.check(b, a) - - def test_3(self): - b = "sys.exc_type # Foo" - a = "sys.exc_info()[0] # Foo" - self.check(b, a) - - def test_4(self): - b = "sys. exc_type" - a = "sys. exc_info()[0]" - self.check(b, a) - - def test_5(self): - b = "sys .exc_type" - a = "sys .exc_info()[0]" - self.check(b, a) - - -class Test_paren(FixerTestCase): - fixer = "paren" - - def test_0(self): - b = """[i for i in 1, 2 ]""" - a = """[i for i in (1, 2) ]""" - self.check(b, a) - - def test_1(self): - b = """[i for i in 1, 2, ]""" - a = """[i for i in (1, 2,) ]""" - self.check(b, a) - - def test_2(self): - b = """[i for i in 1, 2 ]""" - a = """[i for i in (1, 2) ]""" - self.check(b, a) - - def test_3(self): - b = """[i for i in 1, 2 if i]""" - a = """[i for i in (1, 2) if i]""" - self.check(b, a) - - def test_4(self): - b = """[i for i in 1, 2 ]""" - a = """[i for i in (1, 2) ]""" - self.check(b, a) - - def test_5(self): - b = """(i for i in 1, 2)""" - a = """(i for i in (1, 2))""" - self.check(b, a) - - def test_6(self): - b = """(i for i in 1 ,2 if i)""" - a = """(i for i in (1 ,2) if i)""" - self.check(b, a) - - def test_unchanged_0(self): - s = """[i for i in (1, 2)]""" - self.unchanged(s) - - def test_unchanged_1(self): - s = """[i for i in foo()]""" - self.unchanged(s) - - def test_unchanged_2(self): - s = """[i for i in (1, 2) if nothing]""" - self.unchanged(s) - - def test_unchanged_3(self): - s = """(i for i in (1, 2))""" - self.unchanged(s) - - def test_unchanged_4(self): - s = """[i for i in m]""" - self.unchanged(s) - -class Test_metaclass(FixerTestCase): - - fixer = 'metaclass' - - def test_unchanged(self): - self.unchanged("class X(): pass") - self.unchanged("class X(object): pass") - self.unchanged("class X(object1, object2): pass") - self.unchanged("class X(object1, object2, object3): pass") - self.unchanged("class X(metaclass=Meta): pass") - self.unchanged("class X(b, arg=23, metclass=Meta): pass") - self.unchanged("class X(b, arg=23, metaclass=Meta, other=42): pass") - - s = """ - class X: - def __metaclass__(self): pass - """ - self.unchanged(s) - - s = """ - class X: - a[23] = 74 - """ - self.unchanged(s) - - def test_comments(self): - b = """ - class X: - # hi - __metaclass__ = AppleMeta - """ - a = """ - class X(metaclass=AppleMeta): - # hi - pass - """ - self.check(b, a) - - b = """ - class X: - __metaclass__ = Meta - # Bedtime! - """ - a = """ - class X(metaclass=Meta): - pass - # Bedtime! - """ - self.check(b, a) - - def test_meta(self): - # no-parent class, odd body - b = """ - class X(): - __metaclass__ = Q - pass - """ - a = """ - class X(metaclass=Q): - pass - """ - self.check(b, a) - - # one parent class, no body - b = """class X(object): __metaclass__ = Q""" - a = """class X(object, metaclass=Q): pass""" - self.check(b, a) - - - # one parent, simple body - b = """ - class X(object): - __metaclass__ = Meta - bar = 7 - """ - a = """ - class X(object, metaclass=Meta): - bar = 7 - """ - self.check(b, a) - - b = """ - class X: - __metaclass__ = Meta; x = 4; g = 23 - """ - a = """ - class X(metaclass=Meta): - x = 4; g = 23 - """ - self.check(b, a) - - # one parent, simple body, __metaclass__ last - b = """ - class X(object): - bar = 7 - __metaclass__ = Meta - """ - a = """ - class X(object, metaclass=Meta): - bar = 7 - """ - self.check(b, a) - - # redefining __metaclass__ - b = """ - class X(): - __metaclass__ = A - __metaclass__ = B - bar = 7 - """ - a = """ - class X(metaclass=B): - bar = 7 - """ - self.check(b, a) - - # multiple inheritance, simple body - b = """ - class X(clsA, clsB): - __metaclass__ = Meta - bar = 7 - """ - a = """ - class X(clsA, clsB, metaclass=Meta): - bar = 7 - """ - self.check(b, a) - - # keywords in the class statement - b = """class m(a, arg=23): __metaclass__ = Meta""" - a = """class m(a, arg=23, metaclass=Meta): pass""" - self.check(b, a) - - b = """ - class X(expression(2 + 4)): - __metaclass__ = Meta - """ - a = """ - class X(expression(2 + 4), metaclass=Meta): - pass - """ - self.check(b, a) - - b = """ - class X(expression(2 + 4), x**4): - __metaclass__ = Meta - """ - a = """ - class X(expression(2 + 4), x**4, metaclass=Meta): - pass - """ - self.check(b, a) - - b = """ - class X: - __metaclass__ = Meta - save.py = 23 - """ - a = """ - class X(metaclass=Meta): - save.py = 23 - """ - self.check(b, a) - - -class Test_getcwdu(FixerTestCase): - - fixer = 'getcwdu' - - def test_basic(self): - b = """os.getcwdu""" - a = """os.getcwd""" - self.check(b, a) - - b = """os.getcwdu()""" - a = """os.getcwd()""" - self.check(b, a) - - b = """meth = os.getcwdu""" - a = """meth = os.getcwd""" - self.check(b, a) - - b = """os.getcwdu(args)""" - a = """os.getcwd(args)""" - self.check(b, a) - - def test_comment(self): - b = """os.getcwdu() # Foo""" - a = """os.getcwd() # Foo""" - self.check(b, a) - - def test_unchanged(self): - s = """os.getcwd()""" - self.unchanged(s) - - s = """getcwdu()""" - self.unchanged(s) - - s = """os.getcwdb()""" - self.unchanged(s) - - def test_indentation(self): - b = """ - if 1: - os.getcwdu() - """ - a = """ - if 1: - os.getcwd() - """ - self.check(b, a) - - def test_multilation(self): - b = """os .getcwdu()""" - a = """os .getcwd()""" - self.check(b, a) - - b = """os. getcwdu""" - a = """os. getcwd""" - self.check(b, a) - - b = """os.getcwdu ( )""" - a = """os.getcwd ( )""" - self.check(b, a) - - -class Test_operator(FixerTestCase): - - fixer = "operator" - - def test_operator_isCallable(self): - b = "operator.isCallable(x)" - a = "callable(x)" - self.check(b, a) - - def test_operator_sequenceIncludes(self): - b = "operator.sequenceIncludes(x, y)" - a = "operator.contains(x, y)" - self.check(b, a) - - b = "operator .sequenceIncludes(x, y)" - a = "operator .contains(x, y)" - self.check(b, a) - - b = "operator. sequenceIncludes(x, y)" - a = "operator. contains(x, y)" - self.check(b, a) - - def test_operator_isSequenceType(self): - b = "operator.isSequenceType(x)" - a = "import collections.abc\nisinstance(x, collections.abc.Sequence)" - self.check(b, a) - - def test_operator_isMappingType(self): - b = "operator.isMappingType(x)" - a = "import collections.abc\nisinstance(x, collections.abc.Mapping)" - self.check(b, a) - - def test_operator_isNumberType(self): - b = "operator.isNumberType(x)" - a = "import numbers\nisinstance(x, numbers.Number)" - self.check(b, a) - - def test_operator_repeat(self): - b = "operator.repeat(x, n)" - a = "operator.mul(x, n)" - self.check(b, a) - - b = "operator .repeat(x, n)" - a = "operator .mul(x, n)" - self.check(b, a) - - b = "operator. repeat(x, n)" - a = "operator. mul(x, n)" - self.check(b, a) - - def test_operator_irepeat(self): - b = "operator.irepeat(x, n)" - a = "operator.imul(x, n)" - self.check(b, a) - - b = "operator .irepeat(x, n)" - a = "operator .imul(x, n)" - self.check(b, a) - - b = "operator. irepeat(x, n)" - a = "operator. imul(x, n)" - self.check(b, a) - - def test_bare_isCallable(self): - s = "isCallable(x)" - t = "You should use 'callable(x)' here." - self.warns_unchanged(s, t) - - def test_bare_sequenceIncludes(self): - s = "sequenceIncludes(x, y)" - t = "You should use 'operator.contains(x, y)' here." - self.warns_unchanged(s, t) - - def test_bare_operator_isSequenceType(self): - s = "isSequenceType(z)" - t = "You should use 'isinstance(z, collections.abc.Sequence)' here." - self.warns_unchanged(s, t) - - def test_bare_operator_isMappingType(self): - s = "isMappingType(x)" - t = "You should use 'isinstance(x, collections.abc.Mapping)' here." - self.warns_unchanged(s, t) - - def test_bare_operator_isNumberType(self): - s = "isNumberType(y)" - t = "You should use 'isinstance(y, numbers.Number)' here." - self.warns_unchanged(s, t) - - def test_bare_operator_repeat(self): - s = "repeat(x, n)" - t = "You should use 'operator.mul(x, n)' here." - self.warns_unchanged(s, t) - - def test_bare_operator_irepeat(self): - s = "irepeat(y, 187)" - t = "You should use 'operator.imul(y, 187)' here." - self.warns_unchanged(s, t) - - -class Test_exitfunc(FixerTestCase): - - fixer = "exitfunc" - - def test_simple(self): - b = """ - import sys - sys.exitfunc = my_atexit - """ - a = """ - import sys - import atexit - atexit.register(my_atexit) - """ - self.check(b, a) - - def test_names_import(self): - b = """ - import sys, crumbs - sys.exitfunc = my_func - """ - a = """ - import sys, crumbs, atexit - atexit.register(my_func) - """ - self.check(b, a) - - def test_complex_expression(self): - b = """ - import sys - sys.exitfunc = do(d)/a()+complex(f=23, g=23)*expression - """ - a = """ - import sys - import atexit - atexit.register(do(d)/a()+complex(f=23, g=23)*expression) - """ - self.check(b, a) - - def test_comments(self): - b = """ - import sys # Foo - sys.exitfunc = f # Blah - """ - a = """ - import sys - import atexit # Foo - atexit.register(f) # Blah - """ - self.check(b, a) - - b = """ - import apples, sys, crumbs, larry # Pleasant comments - sys.exitfunc = func - """ - a = """ - import apples, sys, crumbs, larry, atexit # Pleasant comments - atexit.register(func) - """ - self.check(b, a) - - def test_in_a_function(self): - b = """ - import sys - def f(): - sys.exitfunc = func - """ - a = """ - import sys - import atexit - def f(): - atexit.register(func) - """ - self.check(b, a) - - def test_no_sys_import(self): - b = """sys.exitfunc = f""" - a = """atexit.register(f)""" - msg = ("Can't find sys import; Please add an atexit import at the " - "top of your file.") - self.warns(b, a, msg) - - - def test_unchanged(self): - s = """f(sys.exitfunc)""" - self.unchanged(s) - - -class Test_asserts(FixerTestCase): - - fixer = "asserts" - - def test_deprecated_names(self): - tests = [ - ('self.assert_(True)', 'self.assertTrue(True)'), - ('self.assertEquals(2, 2)', 'self.assertEqual(2, 2)'), - ('self.assertNotEquals(2, 3)', 'self.assertNotEqual(2, 3)'), - ('self.assertAlmostEquals(2, 3)', 'self.assertAlmostEqual(2, 3)'), - ('self.assertNotAlmostEquals(2, 8)', 'self.assertNotAlmostEqual(2, 8)'), - ('self.failUnlessEqual(2, 2)', 'self.assertEqual(2, 2)'), - ('self.failIfEqual(2, 3)', 'self.assertNotEqual(2, 3)'), - ('self.failUnlessAlmostEqual(2, 3)', 'self.assertAlmostEqual(2, 3)'), - ('self.failIfAlmostEqual(2, 8)', 'self.assertNotAlmostEqual(2, 8)'), - ('self.failUnless(True)', 'self.assertTrue(True)'), - ('self.failUnlessRaises(foo)', 'self.assertRaises(foo)'), - ('self.failIf(False)', 'self.assertFalse(False)'), - ] - for b, a in tests: - self.check(b, a) - - def test_variants(self): - b = 'eq = self.assertEquals' - a = 'eq = self.assertEqual' - self.check(b, a) - b = 'self.assertEquals(2, 3, msg="fail")' - a = 'self.assertEqual(2, 3, msg="fail")' - self.check(b, a) - b = 'self.assertEquals(2, 3, msg="fail") # foo' - a = 'self.assertEqual(2, 3, msg="fail") # foo' - self.check(b, a) - b = 'self.assertEquals (2, 3)' - a = 'self.assertEqual (2, 3)' - self.check(b, a) - b = ' self.assertEquals (2, 3)' - a = ' self.assertEqual (2, 3)' - self.check(b, a) - b = 'with self.failUnlessRaises(Explosion): explode()' - a = 'with self.assertRaises(Explosion): explode()' - self.check(b, a) - b = 'with self.failUnlessRaises(Explosion) as cm: explode()' - a = 'with self.assertRaises(Explosion) as cm: explode()' - self.check(b, a) - - def test_unchanged(self): - self.unchanged('self.assertEqualsOnSaturday') - self.unchanged('self.assertEqualsOnSaturday(3, 5)') diff --git a/Lib/test/test_lib2to3/test_main.py b/Lib/test/test_lib2to3/test_main.py deleted file mode 100644 index a33c45c50a0de..0000000000000 --- a/Lib/test/test_lib2to3/test_main.py +++ /dev/null @@ -1,139 +0,0 @@ -# -*- coding: utf-8 -*- -import codecs -import io -import logging -import os -import re -import shutil -import sys -import tempfile -import unittest - -from lib2to3 import main - - -TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") -PY2_TEST_MODULE = os.path.join(TEST_DATA_DIR, "py2_test_grammar.py") - - -class TestMain(unittest.TestCase): - - def setUp(self): - self.temp_dir = None # tearDown() will rmtree this directory if set. - - def tearDown(self): - # Clean up logging configuration down by main. - del logging.root.handlers[:] - if self.temp_dir: - shutil.rmtree(self.temp_dir) - - def run_2to3_capture(self, args, in_capture, out_capture, err_capture): - save_stdin = sys.stdin - save_stdout = sys.stdout - save_stderr = sys.stderr - sys.stdin = in_capture - sys.stdout = out_capture - sys.stderr = err_capture - try: - return main.main("lib2to3.fixes", args) - finally: - sys.stdin = save_stdin - sys.stdout = save_stdout - sys.stderr = save_stderr - - def test_unencodable_diff(self): - input_stream = io.StringIO("print 'nothing'\nprint u'?ber'\n") - out = io.BytesIO() - out_enc = codecs.getwriter("ascii")(out) - err = io.StringIO() - ret = self.run_2to3_capture(["-"], input_stream, out_enc, err) - self.assertEqual(ret, 0) - output = out.getvalue().decode("ascii") - self.assertIn("-print 'nothing'", output) - self.assertIn("WARNING: couldn't encode <stdin>'s diff for " - "your terminal", err.getvalue()) - - def setup_test_source_trees(self): - """Setup a test source tree and output destination tree.""" - self.temp_dir = tempfile.mkdtemp() # tearDown() cleans this up. - self.py2_src_dir = os.path.join(self.temp_dir, "python2_project") - self.py3_dest_dir = os.path.join(self.temp_dir, "python3_project") - os.mkdir(self.py2_src_dir) - os.mkdir(self.py3_dest_dir) - # Turn it into a package with a few files. - self.setup_files = [] - open(os.path.join(self.py2_src_dir, "__init__.py"), "w").close() - self.setup_files.append("__init__.py") - shutil.copy(PY2_TEST_MODULE, self.py2_src_dir) - self.setup_files.append(os.path.basename(PY2_TEST_MODULE)) - self.trivial_py2_file = os.path.join(self.py2_src_dir, "trivial.py") - self.init_py2_file = os.path.join(self.py2_src_dir, "__init__.py") - with open(self.trivial_py2_file, "w") as trivial: - trivial.write("print 'I need a simple conversion.'") - self.setup_files.append("trivial.py") - - def test_filename_changing_on_output_single_dir(self): - """2to3 a single directory with a new output dir and suffix.""" - self.setup_test_source_trees() - out = io.StringIO() - err = io.StringIO() - suffix = "TEST" - ret = self.run_2to3_capture( - ["-n", "--add-suffix", suffix, "--write-unchanged-files", - "--no-diffs", "--output-dir", - self.py3_dest_dir, self.py2_src_dir], - io.StringIO(""), out, err) - self.assertEqual(ret, 0) - stderr = err.getvalue() - self.assertIn(" implies -w.", stderr) - self.assertIn( - "Output in %r will mirror the input directory %r layout" % ( - self.py3_dest_dir, self.py2_src_dir), stderr) - self.assertEqual(set(name+suffix for name in self.setup_files), - set(os.listdir(self.py3_dest_dir))) - for name in self.setup_files: - self.assertIn("Writing converted %s to %s" % ( - os.path.join(self.py2_src_dir, name), - os.path.join(self.py3_dest_dir, name+suffix)), stderr) - sep = re.escape(os.sep) - self.assertRegex( - stderr, r"No changes to .*/__init__\.py".replace("/", sep)) - self.assertNotRegex( - stderr, r"No changes to .*/trivial\.py".replace("/", sep)) - - def test_filename_changing_on_output_two_files(self): - """2to3 two files in one directory with a new output dir.""" - self.setup_test_source_trees() - err = io.StringIO() - py2_files = [self.trivial_py2_file, self.init_py2_file] - expected_files = set(os.path.basename(name) for name in py2_files) - ret = self.run_2to3_capture( - ["-n", "-w", "--write-unchanged-files", - "--no-diffs", "--output-dir", self.py3_dest_dir] + py2_files, - io.StringIO(""), io.StringIO(), err) - self.assertEqual(ret, 0) - stderr = err.getvalue() - self.assertIn( - "Output in %r will mirror the input directory %r layout" % ( - self.py3_dest_dir, self.py2_src_dir), stderr) - self.assertEqual(expected_files, set(os.listdir(self.py3_dest_dir))) - - def test_filename_changing_on_output_single_file(self): - """2to3 a single file with a new output dir.""" - self.setup_test_source_trees() - err = io.StringIO() - ret = self.run_2to3_capture( - ["-n", "-w", "--no-diffs", "--output-dir", self.py3_dest_dir, - self.trivial_py2_file], - io.StringIO(""), io.StringIO(), err) - self.assertEqual(ret, 0) - stderr = err.getvalue() - self.assertIn( - "Output in %r will mirror the input directory %r layout" % ( - self.py3_dest_dir, self.py2_src_dir), stderr) - self.assertEqual(set([os.path.basename(self.trivial_py2_file)]), - set(os.listdir(self.py3_dest_dir))) - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_lib2to3/test_parser.py b/Lib/test/test_lib2to3/test_parser.py deleted file mode 100644 index 2c798b181fdbd..0000000000000 --- a/Lib/test/test_lib2to3/test_parser.py +++ /dev/null @@ -1,718 +0,0 @@ -"""Test suite for 2to3's parser and grammar files. - -This is the place to add tests for changes to 2to3's grammar, such as those -merging the grammars for Python 2 and 3. In addition to specific tests for -parts of the grammar we've changed, we also make sure we can parse the -test_grammar.py files from both Python 2 and Python 3. -""" - -# Testing imports -from . import support -from .support import driver, driver_no_print_statement - -# Python imports -import difflib -import importlib -import operator -import os -import pickle -import shutil -import subprocess -import sys -import tempfile -import test.support -import unittest - -# Local imports -from lib2to3.pgen2 import driver as pgen2_driver -from lib2to3.pgen2 import tokenize -from lib2to3.pgen2.parse import ParseError -from lib2to3.pygram import python_symbols as syms - - -class TestDriver(support.TestCase): - - def test_formfeed(self): - s = """print 1\n\x0Cprint 2\n""" - t = driver.parse_string(s) - self.assertEqual(t.children[0].children[0].type, syms.print_stmt) - self.assertEqual(t.children[1].children[0].type, syms.print_stmt) - - -class TestPgen2Caching(support.TestCase): - def test_load_grammar_from_txt_file(self): - pgen2_driver.load_grammar(support.grammar_path, save=False, force=True) - - def test_load_grammar_from_pickle(self): - # Make a copy of the grammar file in a temp directory we are - # guaranteed to be able to write to. - tmpdir = tempfile.mkdtemp() - try: - grammar_copy = os.path.join( - tmpdir, os.path.basename(support.grammar_path)) - shutil.copy(support.grammar_path, grammar_copy) - pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) - - pgen2_driver.load_grammar(grammar_copy, save=True, force=True) - self.assertTrue(os.path.exists(pickle_name)) - - os.unlink(grammar_copy) # Only the pickle remains... - pgen2_driver.load_grammar(grammar_copy, save=False, force=False) - finally: - shutil.rmtree(tmpdir) - - @unittest.skipIf(sys.executable is None, 'sys.executable required') - @unittest.skipIf( - sys.platform in {'emscripten', 'wasi'}, 'requires working subprocess' - ) - def test_load_grammar_from_subprocess(self): - tmpdir = tempfile.mkdtemp() - tmpsubdir = os.path.join(tmpdir, 'subdir') - try: - os.mkdir(tmpsubdir) - grammar_base = os.path.basename(support.grammar_path) - grammar_copy = os.path.join(tmpdir, grammar_base) - grammar_sub_copy = os.path.join(tmpsubdir, grammar_base) - shutil.copy(support.grammar_path, grammar_copy) - shutil.copy(support.grammar_path, grammar_sub_copy) - pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) - pickle_sub_name = pgen2_driver._generate_pickle_name( - grammar_sub_copy) - self.assertNotEqual(pickle_name, pickle_sub_name) - - # Generate a pickle file from this process. - pgen2_driver.load_grammar(grammar_copy, save=True, force=True) - self.assertTrue(os.path.exists(pickle_name)) - - # Generate a new pickle file in a subprocess with a most likely - # different hash randomization seed. - sub_env = dict(os.environ) - sub_env['PYTHONHASHSEED'] = 'random' - code = """ -from lib2to3.pgen2 import driver as pgen2_driver -pgen2_driver.load_grammar(%r, save=True, force=True) - """ % (grammar_sub_copy,) - cmd = [sys.executable, - '-Wignore:lib2to3:DeprecationWarning', - '-c', code] - subprocess.check_call( cmd, env=sub_env) - self.assertTrue(os.path.exists(pickle_sub_name)) - - with open(pickle_name, 'rb') as pickle_f_1, \ - open(pickle_sub_name, 'rb') as pickle_f_2: - self.assertEqual( - pickle_f_1.read(), pickle_f_2.read(), - msg='Grammar caches generated using different hash seeds' - ' were not identical.') - finally: - shutil.rmtree(tmpdir) - - def test_load_packaged_grammar(self): - modname = __name__ + '.load_test' - class MyLoader: - def get_data(self, where): - return pickle.dumps({'elephant': 19}) - class MyModule: - __file__ = 'parsertestmodule' - __spec__ = importlib.util.spec_from_loader(modname, MyLoader()) - sys.modules[modname] = MyModule() - self.addCleanup(operator.delitem, sys.modules, modname) - g = pgen2_driver.load_packaged_grammar(modname, 'Grammar.txt') - self.assertEqual(g.elephant, 19) - - -class GrammarTest(support.TestCase): - def validate(self, code): - support.parse_string(code) - - def invalid_syntax(self, code): - try: - self.validate(code) - except ParseError: - pass - else: - raise AssertionError("Syntax shouldn't have been valid") - - -class TestMatrixMultiplication(GrammarTest): - def test_matrix_multiplication_operator(self): - self.validate("a @ b") - self.validate("a @= b") - - -class TestYieldFrom(GrammarTest): - def test_yield_from(self): - self.validate("yield from x") - self.validate("(yield from x) + y") - self.invalid_syntax("yield from") - - -class TestAsyncAwait(GrammarTest): - def test_await_expr(self): - self.validate("""async def foo(): - await x - """) - - self.validate("""async def foo(): - [i async for i in b] - """) - - self.validate("""async def foo(): - {i for i in b - async for i in a if await i - for b in i} - """) - - self.validate("""async def foo(): - [await i for i in b if await c] - """) - - self.validate("""async def foo(): - [ i for i in b if c] - """) - - self.validate("""async def foo(): - - def foo(): pass - - def foo(): pass - - await x - """) - - self.validate("""async def foo(): return await a""") - - self.validate("""def foo(): - def foo(): pass - async def foo(): await x - """) - - self.invalid_syntax("await x") - self.invalid_syntax("""def foo(): - await x""") - - self.invalid_syntax("""def foo(): - def foo(): pass - async def foo(): pass - await x - """) - - def test_async_var(self): - self.validate("""async = 1""") - self.validate("""await = 1""") - self.validate("""def async(): pass""") - - def test_async_for(self): - self.validate("""async def foo(): - async for a in b: pass""") - - def test_async_with(self): - self.validate("""async def foo(): - async with a: pass""") - - self.invalid_syntax("""def foo(): - async with a: pass""") - - def test_async_generator(self): - self.validate( - """async def foo(): - return (i * 2 async for i in arange(42))""" - ) - self.validate( - """def foo(): - return (i * 2 async for i in arange(42))""" - ) - - -class TestRaiseChanges(GrammarTest): - def test_2x_style_1(self): - self.validate("raise") - - def test_2x_style_2(self): - self.validate("raise E, V") - - def test_2x_style_3(self): - self.validate("raise E, V, T") - - def test_2x_style_invalid_1(self): - self.invalid_syntax("raise E, V, T, Z") - - def test_3x_style(self): - self.validate("raise E1 from E2") - - def test_3x_style_invalid_1(self): - self.invalid_syntax("raise E, V from E1") - - def test_3x_style_invalid_2(self): - self.invalid_syntax("raise E from E1, E2") - - def test_3x_style_invalid_3(self): - self.invalid_syntax("raise from E1, E2") - - def test_3x_style_invalid_4(self): - self.invalid_syntax("raise E from") - - -# Modelled after Lib/test/test_grammar.py:TokenTests.test_funcdef issue2292 -# and Lib/test/text_parser.py test_list_displays, test_set_displays, -# test_dict_displays, test_argument_unpacking, ... changes. -class TestUnpackingGeneralizations(GrammarTest): - def test_mid_positional_star(self): - self.validate("""func(1, *(2, 3), 4)""") - - def test_double_star_dict_literal(self): - self.validate("""func(**{'eggs':'scrambled', 'spam':'fried'})""") - - def test_double_star_dict_literal_after_keywords(self): - self.validate("""func(spam='fried', **{'eggs':'scrambled'})""") - - def test_double_star_expression(self): - self.validate("""func(**{'a':2} or {})""") - self.validate("""func(**() or {})""") - - def test_star_expression(self): - self.validate("""func(*[] or [2])""") - - def test_list_display(self): - self.validate("""[*{2}, 3, *[4]]""") - - def test_set_display(self): - self.validate("""{*{2}, 3, *[4]}""") - - def test_dict_display_1(self): - self.validate("""{**{}}""") - - def test_dict_display_2(self): - self.validate("""{**{}, 3:4, **{5:6, 7:8}}""") - - def test_complex_star_expression(self): - self.validate("func(* [] or [1])") - - def test_complex_double_star_expression(self): - self.validate("func(**{1: 3} if False else {x: x for x in range(3)})") - - def test_argument_unpacking_1(self): - self.validate("""f(a, *b, *c, d)""") - - def test_argument_unpacking_2(self): - self.validate("""f(**a, **b)""") - - def test_argument_unpacking_3(self): - self.validate("""f(2, *a, *b, **b, **c, **d)""") - - def test_trailing_commas_1(self): - self.validate("def f(a, b): call(a, b)") - self.validate("def f(a, b,): call(a, b,)") - - def test_trailing_commas_2(self): - self.validate("def f(a, *b): call(a, *b)") - self.validate("def f(a, *b,): call(a, *b,)") - - def test_trailing_commas_3(self): - self.validate("def f(a, b=1): call(a, b=1)") - self.validate("def f(a, b=1,): call(a, b=1,)") - - def test_trailing_commas_4(self): - self.validate("def f(a, **b): call(a, **b)") - self.validate("def f(a, **b,): call(a, **b,)") - - def test_trailing_commas_5(self): - self.validate("def f(*a, b=1): call(*a, b=1)") - self.validate("def f(*a, b=1,): call(*a, b=1,)") - - def test_trailing_commas_6(self): - self.validate("def f(*a, **b): call(*a, **b)") - self.validate("def f(*a, **b,): call(*a, **b,)") - - def test_trailing_commas_7(self): - self.validate("def f(*, b=1): call(*b)") - self.validate("def f(*, b=1,): call(*b,)") - - def test_trailing_commas_8(self): - self.validate("def f(a=1, b=2): call(a=1, b=2)") - self.validate("def f(a=1, b=2,): call(a=1, b=2,)") - - def test_trailing_commas_9(self): - self.validate("def f(a=1, **b): call(a=1, **b)") - self.validate("def f(a=1, **b,): call(a=1, **b,)") - - def test_trailing_commas_lambda_1(self): - self.validate("f = lambda a, b: call(a, b)") - self.validate("f = lambda a, b,: call(a, b,)") - - def test_trailing_commas_lambda_2(self): - self.validate("f = lambda a, *b: call(a, *b)") - self.validate("f = lambda a, *b,: call(a, *b,)") - - def test_trailing_commas_lambda_3(self): - self.validate("f = lambda a, b=1: call(a, b=1)") - self.validate("f = lambda a, b=1,: call(a, b=1,)") - - def test_trailing_commas_lambda_4(self): - self.validate("f = lambda a, **b: call(a, **b)") - self.validate("f = lambda a, **b,: call(a, **b,)") - - def test_trailing_commas_lambda_5(self): - self.validate("f = lambda *a, b=1: call(*a, b=1)") - self.validate("f = lambda *a, b=1,: call(*a, b=1,)") - - def test_trailing_commas_lambda_6(self): - self.validate("f = lambda *a, **b: call(*a, **b)") - self.validate("f = lambda *a, **b,: call(*a, **b,)") - - def test_trailing_commas_lambda_7(self): - self.validate("f = lambda *, b=1: call(*b)") - self.validate("f = lambda *, b=1,: call(*b,)") - - def test_trailing_commas_lambda_8(self): - self.validate("f = lambda a=1, b=2: call(a=1, b=2)") - self.validate("f = lambda a=1, b=2,: call(a=1, b=2,)") - - def test_trailing_commas_lambda_9(self): - self.validate("f = lambda a=1, **b: call(a=1, **b)") - self.validate("f = lambda a=1, **b,: call(a=1, **b,)") - - -# Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef -class TestFunctionAnnotations(GrammarTest): - def test_1(self): - self.validate("""def f(x) -> list: pass""") - - def test_2(self): - self.validate("""def f(x:int): pass""") - - def test_3(self): - self.validate("""def f(*x:str): pass""") - - def test_4(self): - self.validate("""def f(**x:float): pass""") - - def test_5(self): - self.validate("""def f(x, y:1+2): pass""") - - def test_6(self): - self.validate("""def f(a, (b:1, c:2, d)): pass""") - - def test_7(self): - self.validate("""def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass""") - - def test_8(self): - s = """def f(a, (b:1, c:2, d), e:3=4, f=5, - *g:6, h:7, i=8, j:9=10, **k:11) -> 12: pass""" - self.validate(s) - - def test_9(self): - s = """def f( - a: str, - b: int, - *, - c: bool = False, - **kwargs, - ) -> None: - call(c=c, **kwargs,)""" - self.validate(s) - - def test_10(self): - s = """def f( - a: str, - ) -> None: - call(a,)""" - self.validate(s) - - def test_11(self): - s = """def f( - a: str = '', - ) -> None: - call(a=a,)""" - self.validate(s) - - def test_12(self): - s = """def f( - *args: str, - ) -> None: - call(*args,)""" - self.validate(s) - - def test_13(self): - self.validate("def f(a: str, b: int) -> None: call(a, b)") - self.validate("def f(a: str, b: int,) -> None: call(a, b,)") - - def test_14(self): - self.validate("def f(a: str, *b: int) -> None: call(a, *b)") - self.validate("def f(a: str, *b: int,) -> None: call(a, *b,)") - - def test_15(self): - self.validate("def f(a: str, b: int=1) -> None: call(a, b=1)") - self.validate("def f(a: str, b: int=1,) -> None: call(a, b=1,)") - - def test_16(self): - self.validate("def f(a: str, **b: int) -> None: call(a, **b)") - self.validate("def f(a: str, **b: int,) -> None: call(a, **b,)") - - def test_17(self): - self.validate("def f(*a: str, b: int=1) -> None: call(*a, b=1)") - self.validate("def f(*a: str, b: int=1,) -> None: call(*a, b=1,)") - - def test_18(self): - self.validate("def f(*a: str, **b: int) -> None: call(*a, **b)") - self.validate("def f(*a: str, **b: int,) -> None: call(*a, **b,)") - - def test_19(self): - self.validate("def f(*, b: int=1) -> None: call(*b)") - self.validate("def f(*, b: int=1,) -> None: call(*b,)") - - def test_20(self): - self.validate("def f(a: str='', b: int=2) -> None: call(a=a, b=2)") - self.validate("def f(a: str='', b: int=2,) -> None: call(a=a, b=2,)") - - def test_21(self): - self.validate("def f(a: str='', **b: int) -> None: call(a=a, **b)") - self.validate("def f(a: str='', **b: int,) -> None: call(a=a, **b,)") - - -# Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.test_var_annot -class TestVarAnnotations(GrammarTest): - def test_1(self): - self.validate("var1: int = 5") - - def test_2(self): - self.validate("var2: [int, str]") - - def test_3(self): - self.validate("def f():\n" - " st: str = 'Hello'\n" - " a.b: int = (1, 2)\n" - " return st\n") - - def test_4(self): - self.validate("def fbad():\n" - " x: int\n" - " print(x)\n") - - def test_5(self): - self.validate("class C:\n" - " x: int\n" - " s: str = 'attr'\n" - " z = 2\n" - " def __init__(self, x):\n" - " self.x: int = x\n") - - def test_6(self): - self.validate("lst: List[int] = []") - - -class TestExcept(GrammarTest): - def test_new(self): - s = """ - try: - x - except E as N: - y""" - self.validate(s) - - def test_old(self): - s = """ - try: - x - except E, N: - y""" - self.validate(s) - - -class TestStringLiterals(GrammarTest): - prefixes = ("'", '"', - "r'", 'r"', "R'", 'R"', - "u'", 'u"', "U'", 'U"', - "b'", 'b"', "B'", 'B"', - "f'", 'f"', "F'", 'F"', - "ur'", 'ur"', "Ur'", 'Ur"', - "uR'", 'uR"', "UR'", 'UR"', - "br'", 'br"', "Br'", 'Br"', - "bR'", 'bR"', "BR'", 'BR"', - "rb'", 'rb"', "Rb'", 'Rb"', - "rB'", 'rB"', "RB'", 'RB"',) - - def test_lit(self): - for pre in self.prefixes: - single = "{p}spamspamspam{s}".format(p=pre, s=pre[-1]) - self.validate(single) - triple = "{p}{s}{s}eggs{s}{s}{s}".format(p=pre, s=pre[-1]) - self.validate(triple) - - -# Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testAtoms -class TestSetLiteral(GrammarTest): - def test_1(self): - self.validate("""x = {'one'}""") - - def test_2(self): - self.validate("""x = {'one', 1,}""") - - def test_3(self): - self.validate("""x = {'one', 'two', 'three'}""") - - def test_4(self): - self.validate("""x = {2, 3, 4,}""") - - -# Adapted from Python 3's Lib/test/test_unicode_identifiers.py and -# Lib/test/test_tokenize.py:TokenizeTest.test_non_ascii_identifiers -class TestIdentifier(GrammarTest): - def test_non_ascii_identifiers(self): - self.validate("?rter = 'places'\ngr?n = 'green'") - self.validate("? = a? = ?? = 1") - self.validate("? = a? = ?? = 1") - self.validate("??????? = a_??????? = 1") - - -class TestNumericLiterals(GrammarTest): - def test_new_octal_notation(self): - self.validate("""0o7777777777777""") - self.invalid_syntax("""0o7324528887""") - - def test_new_binary_notation(self): - self.validate("""0b101010""") - self.invalid_syntax("""0b0101021""") - - -class TestClassDef(GrammarTest): - def test_new_syntax(self): - self.validate("class B(t=7): pass") - self.validate("class B(t, *args): pass") - self.validate("class B(t, **kwargs): pass") - self.validate("class B(t, *args, **kwargs): pass") - self.validate("class B(t, y=9, *args, **kwargs,): pass") - - -class TestParserIdempotency(support.TestCase): - - """A cut-down version of pytree_idempotency.py.""" - - def parse_file(self, filepath): - if test.support.verbose: - print(f"Parse file: {filepath}") - with open(filepath, "rb") as fp: - encoding = tokenize.detect_encoding(fp.readline)[0] - self.assertIsNotNone(encoding, - "can't detect encoding for %s" % filepath) - with open(filepath, "r", encoding=encoding) as fp: - source = fp.read() - try: - tree = driver.parse_string(source) - except ParseError: - try: - tree = driver_no_print_statement.parse_string(source) - except ParseError as err: - self.fail('ParseError on file %s (%s)' % (filepath, err)) - new = str(tree) - if new != source: - print(diff_texts(source, new, filepath)) - self.fail("Idempotency failed: %s" % filepath) - - def test_all_project_files(self): - for filepath in support.all_project_files(): - with self.subTest(filepath=filepath): - self.parse_file(filepath) - - def test_extended_unpacking(self): - driver.parse_string("a, *b, c = x\n") - driver.parse_string("[*a, b] = x\n") - driver.parse_string("(z, *y, w) = m\n") - driver.parse_string("for *z, m in d: pass\n") - - -class TestLiterals(GrammarTest): - - def validate(self, s): - driver.parse_string(support.dedent(s) + "\n\n") - - def test_multiline_bytes_literals(self): - s = """ - md5test(b"\xaa" * 80, - (b"Test Using Larger Than Block-Size Key " - b"and Larger Than One Block-Size Data"), - "6f630fad67cda0ee1fb1f562db3aa53e") - """ - self.validate(s) - - def test_multiline_bytes_tripquote_literals(self): - s = ''' - b""" - <?xml version="1.0" encoding="UTF-8"?> - <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"> - """ - ''' - self.validate(s) - - def test_multiline_str_literals(self): - s = """ - md5test("\xaa" * 80, - ("Test Using Larger Than Block-Size Key " - "and Larger Than One Block-Size Data"), - "6f630fad67cda0ee1fb1f562db3aa53e") - """ - self.validate(s) - - -class TestNamedAssignments(GrammarTest): - """Also known as the walrus operator.""" - - def test_named_assignment_if(self): - driver.parse_string("if f := x(): pass\n") - - def test_named_assignment_while(self): - driver.parse_string("while f := x(): pass\n") - - def test_named_assignment_generator(self): - driver.parse_string("any((lastNum := num) == 1 for num in [1, 2, 3])\n") - - def test_named_assignment_listcomp(self): - driver.parse_string("[(lastNum := num) == 1 for num in [1, 2, 3]]\n") - - -class TestPositionalOnlyArgs(GrammarTest): - - def test_one_pos_only_arg(self): - driver.parse_string("def one_pos_only_arg(a, /): pass\n") - - def test_all_markers(self): - driver.parse_string( - "def all_markers(a, b=2, /, c, d=4, *, e=5, f): pass\n") - - def test_all_with_args_and_kwargs(self): - driver.parse_string( - """def all_markers_with_args_and_kwargs( - aa, b, /, _cc, d, *args, e, f_f, **kwargs, - ): - pass\n""") - - def test_lambda_soup(self): - driver.parse_string( - "lambda a, b, /, c, d, *args, e, f, **kw: kw\n") - - def test_only_positional_or_keyword(self): - driver.parse_string("def func(a,b,/,*,g,e=3): pass\n") - - -class TestPickleableException(unittest.TestCase): - def test_ParseError(self): - err = ParseError('msg', 2, None, (1, 'context')) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - err2 = pickle.loads(pickle.dumps(err, protocol=proto)) - self.assertEqual(err.args, err2.args) - self.assertEqual(err.msg, err2.msg) - self.assertEqual(err.type, err2.type) - self.assertEqual(err.value, err2.value) - self.assertEqual(err.context, err2.context) - - -def diff_texts(a, b, filename): - a = a.splitlines() - b = b.splitlines() - return difflib.unified_diff(a, b, filename, filename, - "(original)", "(reserialized)", - lineterm="") - - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_lib2to3/test_pytree.py b/Lib/test/test_lib2to3/test_pytree.py deleted file mode 100644 index 177126d545291..0000000000000 --- a/Lib/test/test_lib2to3/test_pytree.py +++ /dev/null @@ -1,472 +0,0 @@ -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Unit tests for pytree.py. - -NOTE: Please *don't* add doc strings to individual test methods! -In verbose mode, printing of the module, class and method name is much -more helpful than printing of (the first line of) the docstring, -especially when debugging a test. -""" - -# Testing imports -from . import support - -from lib2to3 import pytree - -try: - sorted -except NameError: - def sorted(lst): - l = list(lst) - l.sort() - return l - -class TestNodes(support.TestCase): - - """Unit tests for nodes (Base, Leaf, Node).""" - - def test_instantiate_base(self): - if __debug__: - # Test that instantiating Base() raises an AssertionError - self.assertRaises(AssertionError, pytree.Base) - - def test_leaf(self): - l1 = pytree.Leaf(100, "foo") - self.assertEqual(l1.type, 100) - self.assertEqual(l1.value, "foo") - - def test_leaf_repr(self): - l1 = pytree.Leaf(100, "foo") - self.assertEqual(repr(l1), "Leaf(100, 'foo')") - - def test_leaf_str(self): - l1 = pytree.Leaf(100, "foo") - self.assertEqual(str(l1), "foo") - l2 = pytree.Leaf(100, "foo", context=(" ", (10, 1))) - self.assertEqual(str(l2), " foo") - - def test_leaf_str_numeric_value(self): - # Make sure that the Leaf's value is stringified. Failing to - # do this can cause a TypeError in certain situations. - l1 = pytree.Leaf(2, 5) - l1.prefix = "foo_" - self.assertEqual(str(l1), "foo_5") - - def test_leaf_equality(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "foo", context=(" ", (1, 0))) - self.assertEqual(l1, l2) - l3 = pytree.Leaf(101, "foo") - l4 = pytree.Leaf(100, "bar") - self.assertNotEqual(l1, l3) - self.assertNotEqual(l1, l4) - - def test_leaf_prefix(self): - l1 = pytree.Leaf(100, "foo") - self.assertEqual(l1.prefix, "") - self.assertFalse(l1.was_changed) - l1.prefix = " ##\n\n" - self.assertEqual(l1.prefix, " ##\n\n") - self.assertTrue(l1.was_changed) - - def test_node(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(200, "bar") - n1 = pytree.Node(1000, [l1, l2]) - self.assertEqual(n1.type, 1000) - self.assertEqual(n1.children, [l1, l2]) - - def test_node_repr(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar", context=(" ", (1, 0))) - n1 = pytree.Node(1000, [l1, l2]) - self.assertEqual(repr(n1), - "Node(1000, [%s, %s])" % (repr(l1), repr(l2))) - - def test_node_str(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar", context=(" ", (1, 0))) - n1 = pytree.Node(1000, [l1, l2]) - self.assertEqual(str(n1), "foo bar") - - def test_node_prefix(self): - l1 = pytree.Leaf(100, "foo") - self.assertEqual(l1.prefix, "") - n1 = pytree.Node(1000, [l1]) - self.assertEqual(n1.prefix, "") - n1.prefix = " " - self.assertEqual(n1.prefix, " ") - self.assertEqual(l1.prefix, " ") - - def test_get_suffix(self): - l1 = pytree.Leaf(100, "foo", prefix="a") - l2 = pytree.Leaf(100, "bar", prefix="b") - n1 = pytree.Node(1000, [l1, l2]) - - self.assertEqual(l1.get_suffix(), l2.prefix) - self.assertEqual(l2.get_suffix(), "") - self.assertEqual(n1.get_suffix(), "") - - l3 = pytree.Leaf(100, "bar", prefix="c") - n2 = pytree.Node(1000, [n1, l3]) - - self.assertEqual(n1.get_suffix(), l3.prefix) - self.assertEqual(l3.get_suffix(), "") - self.assertEqual(n2.get_suffix(), "") - - def test_node_equality(self): - n1 = pytree.Node(1000, ()) - n2 = pytree.Node(1000, [], context=(" ", (1, 0))) - self.assertEqual(n1, n2) - n3 = pytree.Node(1001, ()) - self.assertNotEqual(n1, n3) - - def test_node_recursive_equality(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "foo") - n1 = pytree.Node(1000, [l1]) - n2 = pytree.Node(1000, [l2]) - self.assertEqual(n1, n2) - l3 = pytree.Leaf(100, "bar") - n3 = pytree.Node(1000, [l3]) - self.assertNotEqual(n1, n3) - - def test_replace(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "+") - l3 = pytree.Leaf(100, "bar") - n1 = pytree.Node(1000, [l1, l2, l3]) - self.assertEqual(n1.children, [l1, l2, l3]) - self.assertIsInstance(n1.children, list) - self.assertFalse(n1.was_changed) - l2new = pytree.Leaf(100, "-") - l2.replace(l2new) - self.assertEqual(n1.children, [l1, l2new, l3]) - self.assertIsInstance(n1.children, list) - self.assertTrue(n1.was_changed) - - def test_replace_with_list(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "+") - l3 = pytree.Leaf(100, "bar") - n1 = pytree.Node(1000, [l1, l2, l3]) - - l2.replace([pytree.Leaf(100, "*"), pytree.Leaf(100, "*")]) - self.assertEqual(str(n1), "foo**bar") - self.assertIsInstance(n1.children, list) - - def test_leaves(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar") - l3 = pytree.Leaf(100, "fooey") - n2 = pytree.Node(1000, [l1, l2]) - n3 = pytree.Node(1000, [l3]) - n1 = pytree.Node(1000, [n2, n3]) - - self.assertEqual(list(n1.leaves()), [l1, l2, l3]) - - def test_depth(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar") - n2 = pytree.Node(1000, [l1, l2]) - n3 = pytree.Node(1000, []) - n1 = pytree.Node(1000, [n2, n3]) - - self.assertEqual(l1.depth(), 2) - self.assertEqual(n3.depth(), 1) - self.assertEqual(n1.depth(), 0) - - def test_post_order(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar") - l3 = pytree.Leaf(100, "fooey") - c1 = pytree.Node(1000, [l1, l2]) - n1 = pytree.Node(1000, [c1, l3]) - self.assertEqual(list(n1.post_order()), [l1, l2, c1, l3, n1]) - - def test_pre_order(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar") - l3 = pytree.Leaf(100, "fooey") - c1 = pytree.Node(1000, [l1, l2]) - n1 = pytree.Node(1000, [c1, l3]) - self.assertEqual(list(n1.pre_order()), [n1, c1, l1, l2, l3]) - - def test_changed(self): - l1 = pytree.Leaf(100, "f") - self.assertFalse(l1.was_changed) - l1.changed() - self.assertTrue(l1.was_changed) - - l1 = pytree.Leaf(100, "f") - n1 = pytree.Node(1000, [l1]) - self.assertFalse(n1.was_changed) - n1.changed() - self.assertTrue(n1.was_changed) - - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "+") - l3 = pytree.Leaf(100, "bar") - n1 = pytree.Node(1000, [l1, l2, l3]) - n2 = pytree.Node(1000, [n1]) - self.assertFalse(l1.was_changed) - self.assertFalse(n1.was_changed) - self.assertFalse(n2.was_changed) - - n1.changed() - self.assertTrue(n1.was_changed) - self.assertTrue(n2.was_changed) - self.assertFalse(l1.was_changed) - - def test_leaf_constructor_prefix(self): - for prefix in ("xyz_", ""): - l1 = pytree.Leaf(100, "self", prefix=prefix) - self.assertTrue(str(l1), prefix + "self") - self.assertEqual(l1.prefix, prefix) - - def test_node_constructor_prefix(self): - for prefix in ("xyz_", ""): - l1 = pytree.Leaf(100, "self") - l2 = pytree.Leaf(100, "foo", prefix="_") - n1 = pytree.Node(1000, [l1, l2], prefix=prefix) - self.assertTrue(str(n1), prefix + "self_foo") - self.assertEqual(n1.prefix, prefix) - self.assertEqual(l1.prefix, prefix) - self.assertEqual(l2.prefix, "_") - - def test_remove(self): - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "foo") - n1 = pytree.Node(1000, [l1, l2]) - n2 = pytree.Node(1000, [n1]) - - self.assertEqual(n1.remove(), 0) - self.assertEqual(n2.children, []) - self.assertEqual(l1.parent, n1) - self.assertEqual(n1.parent, None) - self.assertEqual(n2.parent, None) - self.assertFalse(n1.was_changed) - self.assertTrue(n2.was_changed) - - self.assertEqual(l2.remove(), 1) - self.assertEqual(l1.remove(), 0) - self.assertEqual(n1.children, []) - self.assertEqual(l1.parent, None) - self.assertEqual(n1.parent, None) - self.assertEqual(n2.parent, None) - self.assertTrue(n1.was_changed) - self.assertTrue(n2.was_changed) - - def test_remove_parentless(self): - n1 = pytree.Node(1000, []) - n1.remove() - self.assertEqual(n1.parent, None) - - l1 = pytree.Leaf(100, "foo") - l1.remove() - self.assertEqual(l1.parent, None) - - def test_node_set_child(self): - l1 = pytree.Leaf(100, "foo") - n1 = pytree.Node(1000, [l1]) - - l2 = pytree.Leaf(100, "bar") - n1.set_child(0, l2) - self.assertEqual(l1.parent, None) - self.assertEqual(l2.parent, n1) - self.assertEqual(n1.children, [l2]) - - n2 = pytree.Node(1000, [l1]) - n2.set_child(0, n1) - self.assertEqual(l1.parent, None) - self.assertEqual(n1.parent, n2) - self.assertEqual(n2.parent, None) - self.assertEqual(n2.children, [n1]) - - self.assertRaises(IndexError, n1.set_child, 4, l2) - # I don't care what it raises, so long as it's an exception - self.assertRaises(Exception, n1.set_child, 0, list) - - def test_node_insert_child(self): - l1 = pytree.Leaf(100, "foo") - n1 = pytree.Node(1000, [l1]) - - l2 = pytree.Leaf(100, "bar") - n1.insert_child(0, l2) - self.assertEqual(l2.parent, n1) - self.assertEqual(n1.children, [l2, l1]) - - l3 = pytree.Leaf(100, "abc") - n1.insert_child(2, l3) - self.assertEqual(n1.children, [l2, l1, l3]) - - # I don't care what it raises, so long as it's an exception - self.assertRaises(Exception, n1.insert_child, 0, list) - - def test_node_append_child(self): - n1 = pytree.Node(1000, []) - - l1 = pytree.Leaf(100, "foo") - n1.append_child(l1) - self.assertEqual(l1.parent, n1) - self.assertEqual(n1.children, [l1]) - - l2 = pytree.Leaf(100, "bar") - n1.append_child(l2) - self.assertEqual(l2.parent, n1) - self.assertEqual(n1.children, [l1, l2]) - - # I don't care what it raises, so long as it's an exception - self.assertRaises(Exception, n1.append_child, list) - - def test_node_next_sibling(self): - n1 = pytree.Node(1000, []) - n2 = pytree.Node(1000, []) - p1 = pytree.Node(1000, [n1, n2]) - - self.assertIs(n1.next_sibling, n2) - self.assertEqual(n2.next_sibling, None) - self.assertEqual(p1.next_sibling, None) - - def test_leaf_next_sibling(self): - l1 = pytree.Leaf(100, "a") - l2 = pytree.Leaf(100, "b") - p1 = pytree.Node(1000, [l1, l2]) - - self.assertIs(l1.next_sibling, l2) - self.assertEqual(l2.next_sibling, None) - self.assertEqual(p1.next_sibling, None) - - def test_node_prev_sibling(self): - n1 = pytree.Node(1000, []) - n2 = pytree.Node(1000, []) - p1 = pytree.Node(1000, [n1, n2]) - - self.assertIs(n2.prev_sibling, n1) - self.assertEqual(n1.prev_sibling, None) - self.assertEqual(p1.prev_sibling, None) - - def test_leaf_prev_sibling(self): - l1 = pytree.Leaf(100, "a") - l2 = pytree.Leaf(100, "b") - p1 = pytree.Node(1000, [l1, l2]) - - self.assertIs(l2.prev_sibling, l1) - self.assertEqual(l1.prev_sibling, None) - self.assertEqual(p1.prev_sibling, None) - - -class TestPatterns(support.TestCase): - - """Unit tests for tree matching patterns.""" - - def test_basic_patterns(self): - # Build a tree - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar") - l3 = pytree.Leaf(100, "foo") - n1 = pytree.Node(1000, [l1, l2]) - n2 = pytree.Node(1000, [l3]) - root = pytree.Node(1000, [n1, n2]) - # Build a pattern matching a leaf - pl = pytree.LeafPattern(100, "foo", name="pl") - r = {} - self.assertFalse(pl.match(root, results=r)) - self.assertEqual(r, {}) - self.assertFalse(pl.match(n1, results=r)) - self.assertEqual(r, {}) - self.assertFalse(pl.match(n2, results=r)) - self.assertEqual(r, {}) - self.assertTrue(pl.match(l1, results=r)) - self.assertEqual(r, {"pl": l1}) - r = {} - self.assertFalse(pl.match(l2, results=r)) - self.assertEqual(r, {}) - # Build a pattern matching a node - pn = pytree.NodePattern(1000, [pl], name="pn") - self.assertFalse(pn.match(root, results=r)) - self.assertEqual(r, {}) - self.assertFalse(pn.match(n1, results=r)) - self.assertEqual(r, {}) - self.assertTrue(pn.match(n2, results=r)) - self.assertEqual(r, {"pn": n2, "pl": l3}) - r = {} - self.assertFalse(pn.match(l1, results=r)) - self.assertEqual(r, {}) - self.assertFalse(pn.match(l2, results=r)) - self.assertEqual(r, {}) - - def test_wildcard(self): - # Build a tree for testing - l1 = pytree.Leaf(100, "foo") - l2 = pytree.Leaf(100, "bar") - l3 = pytree.Leaf(100, "foo") - n1 = pytree.Node(1000, [l1, l2]) - n2 = pytree.Node(1000, [l3]) - root = pytree.Node(1000, [n1, n2]) - # Build a pattern - pl = pytree.LeafPattern(100, "foo", name="pl") - pn = pytree.NodePattern(1000, [pl], name="pn") - pw = pytree.WildcardPattern([[pn], [pl, pl]], name="pw") - r = {} - self.assertFalse(pw.match_seq([root], r)) - self.assertEqual(r, {}) - self.assertFalse(pw.match_seq([n1], r)) - self.assertEqual(r, {}) - self.assertTrue(pw.match_seq([n2], r)) - # These are easier to debug - self.assertEqual(sorted(r.keys()), ["pl", "pn", "pw"]) - self.assertEqual(r["pl"], l1) - self.assertEqual(r["pn"], n2) - self.assertEqual(r["pw"], [n2]) - # But this is equivalent - self.assertEqual(r, {"pl": l1, "pn": n2, "pw": [n2]}) - r = {} - self.assertTrue(pw.match_seq([l1, l3], r)) - self.assertEqual(r, {"pl": l3, "pw": [l1, l3]}) - self.assertIs(r["pl"], l3) - r = {} - - def test_generate_matches(self): - la = pytree.Leaf(1, "a") - lb = pytree.Leaf(1, "b") - lc = pytree.Leaf(1, "c") - ld = pytree.Leaf(1, "d") - le = pytree.Leaf(1, "e") - lf = pytree.Leaf(1, "f") - leaves = [la, lb, lc, ld, le, lf] - root = pytree.Node(1000, leaves) - pa = pytree.LeafPattern(1, "a", "pa") - pb = pytree.LeafPattern(1, "b", "pb") - pc = pytree.LeafPattern(1, "c", "pc") - pd = pytree.LeafPattern(1, "d", "pd") - pe = pytree.LeafPattern(1, "e", "pe") - pf = pytree.LeafPattern(1, "f", "pf") - pw = pytree.WildcardPattern([[pa, pb, pc], [pd, pe], - [pa, pb], [pc, pd], [pe, pf]], - min=1, max=4, name="pw") - self.assertEqual([x[0] for x in pw.generate_matches(leaves)], - [3, 5, 2, 4, 6]) - pr = pytree.NodePattern(type=1000, content=[pw], name="pr") - matches = list(pytree.generate_matches([pr], [root])) - self.assertEqual(len(matches), 1) - c, r = matches[0] - self.assertEqual(c, 1) - self.assertEqual(str(r["pr"]), "abcdef") - self.assertEqual(r["pw"], [la, lb, lc, ld, le, lf]) - for c in "abcdef": - self.assertEqual(r["p" + c], pytree.Leaf(1, c)) - - def test_has_key_example(self): - pattern = pytree.NodePattern(331, - (pytree.LeafPattern(7), - pytree.WildcardPattern(name="args"), - pytree.LeafPattern(8))) - l1 = pytree.Leaf(7, "(") - l2 = pytree.Leaf(3, "x") - l3 = pytree.Leaf(8, ")") - node = pytree.Node(331, [l1, l2, l3]) - r = {} - self.assertTrue(pattern.match(node, r)) - self.assertEqual(r["args"], [l2]) diff --git a/Lib/test/test_lib2to3/test_refactor.py b/Lib/test/test_lib2to3/test_refactor.py deleted file mode 100644 index be705679f06db..0000000000000 --- a/Lib/test/test_lib2to3/test_refactor.py +++ /dev/null @@ -1,337 +0,0 @@ -""" -Unit tests for refactor.py. -""" - -import sys -import os -import codecs -import io -import re -import tempfile -import shutil -import unittest - -from lib2to3 import refactor, pygram, fixer_base -from lib2to3.pgen2 import token - - -TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") -FIXER_DIR = os.path.join(TEST_DATA_DIR, "fixers") - -sys.path.append(FIXER_DIR) -try: - _DEFAULT_FIXERS = refactor.get_fixers_from_package("myfixes") -finally: - sys.path.pop() - -_2TO3_FIXERS = refactor.get_fixers_from_package("lib2to3.fixes") - -class TestRefactoringTool(unittest.TestCase): - - def setUp(self): - sys.path.append(FIXER_DIR) - - def tearDown(self): - sys.path.pop() - - def check_instances(self, instances, classes): - for inst, cls in zip(instances, classes): - if not isinstance(inst, cls): - self.fail("%s are not instances of %s" % instances, classes) - - def rt(self, options=None, fixers=_DEFAULT_FIXERS, explicit=None): - return refactor.RefactoringTool(fixers, options, explicit) - - def test_print_function_option(self): - rt = self.rt({"print_function" : True}) - self.assertNotIn("print", rt.grammar.keywords) - self.assertNotIn("print", rt.driver.grammar.keywords) - - def test_exec_function_option(self): - rt = self.rt({"exec_function" : True}) - self.assertNotIn("exec", rt.grammar.keywords) - self.assertNotIn("exec", rt.driver.grammar.keywords) - - def test_write_unchanged_files_option(self): - rt = self.rt() - self.assertFalse(rt.write_unchanged_files) - rt = self.rt({"write_unchanged_files" : True}) - self.assertTrue(rt.write_unchanged_files) - - def test_fixer_loading_helpers(self): - contents = ["explicit", "first", "last", "parrot", "preorder"] - non_prefixed = refactor.get_all_fix_names("myfixes") - prefixed = refactor.get_all_fix_names("myfixes", False) - full_names = refactor.get_fixers_from_package("myfixes") - self.assertEqual(prefixed, ["fix_" + name for name in contents]) - self.assertEqual(non_prefixed, contents) - self.assertEqual(full_names, - ["myfixes.fix_" + name for name in contents]) - - def test_detect_future_features(self): - run = refactor._detect_future_features - fs = frozenset - empty = fs() - self.assertEqual(run(""), empty) - self.assertEqual(run("from __future__ import print_function"), - fs(("print_function",))) - self.assertEqual(run("from __future__ import generators"), - fs(("generators",))) - self.assertEqual(run("from __future__ import generators, feature"), - fs(("generators", "feature"))) - inp = "from __future__ import generators, print_function" - self.assertEqual(run(inp), fs(("generators", "print_function"))) - inp ="from __future__ import print_function, generators" - self.assertEqual(run(inp), fs(("print_function", "generators"))) - inp = "from __future__ import (print_function,)" - self.assertEqual(run(inp), fs(("print_function",))) - inp = "from __future__ import (generators, print_function)" - self.assertEqual(run(inp), fs(("generators", "print_function"))) - inp = "from __future__ import (generators, nested_scopes)" - self.assertEqual(run(inp), fs(("generators", "nested_scopes"))) - inp = """from __future__ import generators -from __future__ import print_function""" - self.assertEqual(run(inp), fs(("generators", "print_function"))) - invalid = ("from", - "from 4", - "from x", - "from x 5", - "from x im", - "from x import", - "from x import 4", - ) - for inp in invalid: - self.assertEqual(run(inp), empty) - inp = "'docstring'\nfrom __future__ import print_function" - self.assertEqual(run(inp), fs(("print_function",))) - inp = "'docstring'\n'somng'\nfrom __future__ import print_function" - self.assertEqual(run(inp), empty) - inp = "# comment\nfrom __future__ import print_function" - self.assertEqual(run(inp), fs(("print_function",))) - inp = "# comment\n'doc'\nfrom __future__ import print_function" - self.assertEqual(run(inp), fs(("print_function",))) - inp = "class x: pass\nfrom __future__ import print_function" - self.assertEqual(run(inp), empty) - - def test_get_headnode_dict(self): - class NoneFix(fixer_base.BaseFix): - pass - - class FileInputFix(fixer_base.BaseFix): - PATTERN = "file_input< any * >" - - class SimpleFix(fixer_base.BaseFix): - PATTERN = "'name'" - - no_head = NoneFix({}, []) - with_head = FileInputFix({}, []) - simple = SimpleFix({}, []) - d = refactor._get_headnode_dict([no_head, with_head, simple]) - top_fixes = d.pop(pygram.python_symbols.file_input) - self.assertEqual(top_fixes, [with_head, no_head]) - name_fixes = d.pop(token.NAME) - self.assertEqual(name_fixes, [simple, no_head]) - for fixes in d.values(): - self.assertEqual(fixes, [no_head]) - - def test_fixer_loading(self): - from myfixes.fix_first import FixFirst - from myfixes.fix_last import FixLast - from myfixes.fix_parrot import FixParrot - from myfixes.fix_preorder import FixPreorder - - rt = self.rt() - pre, post = rt.get_fixers() - - self.check_instances(pre, [FixPreorder]) - self.check_instances(post, [FixFirst, FixParrot, FixLast]) - - def test_naughty_fixers(self): - self.assertRaises(ImportError, self.rt, fixers=["not_here"]) - self.assertRaises(refactor.FixerError, self.rt, fixers=["no_fixer_cls"]) - self.assertRaises(refactor.FixerError, self.rt, fixers=["bad_order"]) - - def test_refactor_string(self): - rt = self.rt() - input = "def parrot(): pass\n\n" - tree = rt.refactor_string(input, "<test>") - self.assertNotEqual(str(tree), input) - - input = "def f(): pass\n\n" - tree = rt.refactor_string(input, "<test>") - self.assertEqual(str(tree), input) - - def test_refactor_stdin(self): - - class MyRT(refactor.RefactoringTool): - - def print_output(self, old_text, new_text, filename, equal): - results.extend([old_text, new_text, filename, equal]) - - results = [] - rt = MyRT(_DEFAULT_FIXERS) - save = sys.stdin - sys.stdin = io.StringIO("def parrot(): pass\n\n") - try: - rt.refactor_stdin() - finally: - sys.stdin = save - expected = ["def parrot(): pass\n\n", - "def cheese(): pass\n\n", - "<stdin>", False] - self.assertEqual(results, expected) - - def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS, - options=None, mock_log_debug=None, - actually_write=True): - test_file = self.init_test_file(test_file) - old_contents = self.read_file(test_file) - rt = self.rt(fixers=fixers, options=options) - if mock_log_debug: - rt.log_debug = mock_log_debug - - rt.refactor_file(test_file) - self.assertEqual(old_contents, self.read_file(test_file)) - - if not actually_write: - return - rt.refactor_file(test_file, True) - new_contents = self.read_file(test_file) - self.assertNotEqual(old_contents, new_contents) - return new_contents - - def init_test_file(self, test_file): - tmpdir = tempfile.mkdtemp(prefix="2to3-test_refactor") - self.addCleanup(shutil.rmtree, tmpdir) - shutil.copy(test_file, tmpdir) - test_file = os.path.join(tmpdir, os.path.basename(test_file)) - os.chmod(test_file, 0o644) - return test_file - - def read_file(self, test_file): - with open(test_file, "rb") as fp: - return fp.read() - - def refactor_file(self, test_file, fixers=_2TO3_FIXERS): - test_file = self.init_test_file(test_file) - old_contents = self.read_file(test_file) - rt = self.rt(fixers=fixers) - rt.refactor_file(test_file, True) - new_contents = self.read_file(test_file) - return old_contents, new_contents - - def test_refactor_file(self): - test_file = os.path.join(FIXER_DIR, "parrot_example.py") - self.check_file_refactoring(test_file, _DEFAULT_FIXERS) - - def test_refactor_file_write_unchanged_file(self): - test_file = os.path.join(FIXER_DIR, "parrot_example.py") - debug_messages = [] - def recording_log_debug(msg, *args): - debug_messages.append(msg % args) - self.check_file_refactoring(test_file, fixers=(), - options={"write_unchanged_files": True}, - mock_log_debug=recording_log_debug, - actually_write=False) - # Testing that it logged this message when write=False was passed is - # sufficient to see that it did not bail early after "No changes". - message_regex = r"Not writing changes to .*%s" % \ - re.escape(os.sep + os.path.basename(test_file)) - for message in debug_messages: - if "Not writing changes" in message: - self.assertRegex(message, message_regex) - break - else: - self.fail("%r not matched in %r" % (message_regex, debug_messages)) - - def test_refactor_dir(self): - def check(structure, expected): - def mock_refactor_file(self, f, *args): - got.append(f) - save_func = refactor.RefactoringTool.refactor_file - refactor.RefactoringTool.refactor_file = mock_refactor_file - rt = self.rt() - got = [] - dir = tempfile.mkdtemp(prefix="2to3-test_refactor") - try: - os.mkdir(os.path.join(dir, "a_dir")) - for fn in structure: - open(os.path.join(dir, fn), "wb").close() - rt.refactor_dir(dir) - finally: - refactor.RefactoringTool.refactor_file = save_func - shutil.rmtree(dir) - self.assertEqual(got, - [os.path.join(dir, path) for path in expected]) - check([], []) - tree = ["nothing", - "hi.py", - ".dumb", - ".after.py", - "notpy.npy", - "sappy"] - expected = ["hi.py"] - check(tree, expected) - tree = ["hi.py", - os.path.join("a_dir", "stuff.py")] - check(tree, tree) - - def test_file_encoding(self): - fn = os.path.join(TEST_DATA_DIR, "different_encoding.py") - self.check_file_refactoring(fn) - - def test_false_file_encoding(self): - fn = os.path.join(TEST_DATA_DIR, "false_encoding.py") - data = self.check_file_refactoring(fn) - - def test_bom(self): - fn = os.path.join(TEST_DATA_DIR, "bom.py") - data = self.check_file_refactoring(fn) - self.assertTrue(data.startswith(codecs.BOM_UTF8)) - - def test_crlf_newlines(self): - old_sep = os.linesep - os.linesep = "\r\n" - try: - fn = os.path.join(TEST_DATA_DIR, "crlf.py") - fixes = refactor.get_fixers_from_package("lib2to3.fixes") - self.check_file_refactoring(fn, fixes) - finally: - os.linesep = old_sep - - def test_crlf_unchanged(self): - fn = os.path.join(TEST_DATA_DIR, "crlf.py") - old, new = self.refactor_file(fn) - self.assertIn(b"\r\n", old) - self.assertIn(b"\r\n", new) - self.assertNotIn(b"\r\r\n", new) - - def test_refactor_docstring(self): - rt = self.rt() - - doc = """ ->>> example() -42 -""" - out = rt.refactor_docstring(doc, "<test>") - self.assertEqual(out, doc) - - doc = """ ->>> def parrot(): -... return 43 -""" - out = rt.refactor_docstring(doc, "<test>") - self.assertNotEqual(out, doc) - - def test_explicit(self): - from myfixes.fix_explicit import FixExplicit - - rt = self.rt(fixers=["myfixes.fix_explicit"]) - self.assertEqual(len(rt.post_order), 0) - - rt = self.rt(explicit=["myfixes.fix_explicit"]) - for fix in rt.post_order: - if isinstance(fix, FixExplicit): - break - else: - self.fail("explicit fixer not loaded") diff --git a/Lib/test/test_lib2to3/test_util.py b/Lib/test/test_lib2to3/test_util.py deleted file mode 100644 index c6c613972dac7..0000000000000 --- a/Lib/test/test_lib2to3/test_util.py +++ /dev/null @@ -1,591 +0,0 @@ -""" Test suite for the code in fixer_util """ - -# Testing imports -from . import support - -# Local imports -from lib2to3.pytree import Node, Leaf -from lib2to3 import fixer_util -from lib2to3.fixer_util import Attr, Name, Call, Comma -from lib2to3.pgen2 import token - -def parse(code, strip_levels=0): - # The topmost node is file_input, which we don't care about. - # The next-topmost node is a *_stmt node, which we also don't care about - tree = support.parse_string(code) - for i in range(strip_levels): - tree = tree.children[0] - tree.parent = None - return tree - -class MacroTestCase(support.TestCase): - def assertStr(self, node, string): - if isinstance(node, (tuple, list)): - node = Node(fixer_util.syms.simple_stmt, node) - self.assertEqual(str(node), string) - - -class Test_is_tuple(support.TestCase): - def is_tuple(self, string): - return fixer_util.is_tuple(parse(string, strip_levels=2)) - - def test_valid(self): - self.assertTrue(self.is_tuple("(a, b)")) - self.assertTrue(self.is_tuple("(a, (b, c))")) - self.assertTrue(self.is_tuple("((a, (b, c)),)")) - self.assertTrue(self.is_tuple("(a,)")) - self.assertTrue(self.is_tuple("()")) - - def test_invalid(self): - self.assertFalse(self.is_tuple("(a)")) - self.assertFalse(self.is_tuple("('foo') % (b, c)")) - - -class Test_is_list(support.TestCase): - def is_list(self, string): - return fixer_util.is_list(parse(string, strip_levels=2)) - - def test_valid(self): - self.assertTrue(self.is_list("[]")) - self.assertTrue(self.is_list("[a]")) - self.assertTrue(self.is_list("[a, b]")) - self.assertTrue(self.is_list("[a, [b, c]]")) - self.assertTrue(self.is_list("[[a, [b, c]],]")) - - def test_invalid(self): - self.assertFalse(self.is_list("[]+[]")) - - -class Test_Attr(MacroTestCase): - def test(self): - call = parse("foo()", strip_levels=2) - - self.assertStr(Attr(Name("a"), Name("b")), "a.b") - self.assertStr(Attr(call, Name("b")), "foo().b") - - def test_returns(self): - attr = Attr(Name("a"), Name("b")) - self.assertEqual(type(attr), list) - - -class Test_Name(MacroTestCase): - def test(self): - self.assertStr(Name("a"), "a") - self.assertStr(Name("foo.foo().bar"), "foo.foo().bar") - self.assertStr(Name("a", prefix="b"), "ba") - - -class Test_Call(MacroTestCase): - def _Call(self, name, args=None, prefix=None): - """Help the next test""" - children = [] - if isinstance(args, list): - for arg in args: - children.append(arg) - children.append(Comma()) - children.pop() - return Call(Name(name), children, prefix) - - def test(self): - kids = [None, - [Leaf(token.NUMBER, 1), Leaf(token.NUMBER, 2), - Leaf(token.NUMBER, 3)], - [Leaf(token.NUMBER, 1), Leaf(token.NUMBER, 3), - Leaf(token.NUMBER, 2), Leaf(token.NUMBER, 4)], - [Leaf(token.STRING, "b"), Leaf(token.STRING, "j", prefix=" ")] - ] - self.assertStr(self._Call("A"), "A()") - self.assertStr(self._Call("b", kids[1]), "b(1,2,3)") - self.assertStr(self._Call("a.b().c", kids[2]), "a.b().c(1,3,2,4)") - self.assertStr(self._Call("d", kids[3], prefix=" "), " d(b, j)") - - -class Test_does_tree_import(support.TestCase): - def _find_bind_rec(self, name, node): - # Search a tree for a binding -- used to find the starting - # point for these tests. - c = fixer_util.find_binding(name, node) - if c: return c - for child in node.children: - c = self._find_bind_rec(name, child) - if c: return c - - def does_tree_import(self, package, name, string): - node = parse(string) - # Find the binding of start -- that's what we'll go from - node = self._find_bind_rec('start', node) - return fixer_util.does_tree_import(package, name, node) - - def try_with(self, string): - failing_tests = (("a", "a", "from a import b"), - ("a.d", "a", "from a.d import b"), - ("d.a", "a", "from d.a import b"), - (None, "a", "import b"), - (None, "a", "import b, c, d")) - for package, name, import_ in failing_tests: - n = self.does_tree_import(package, name, import_ + "\n" + string) - self.assertFalse(n) - n = self.does_tree_import(package, name, string + "\n" + import_) - self.assertFalse(n) - - passing_tests = (("a", "a", "from a import a"), - ("x", "a", "from x import a"), - ("x", "a", "from x import b, c, a, d"), - ("x.b", "a", "from x.b import a"), - ("x.b", "a", "from x.b import b, c, a, d"), - (None, "a", "import a"), - (None, "a", "import b, c, a, d")) - for package, name, import_ in passing_tests: - n = self.does_tree_import(package, name, import_ + "\n" + string) - self.assertTrue(n) - n = self.does_tree_import(package, name, string + "\n" + import_) - self.assertTrue(n) - - def test_in_function(self): - self.try_with("def foo():\n\tbar.baz()\n\tstart=3") - -class Test_find_binding(support.TestCase): - def find_binding(self, name, string, package=None): - return fixer_util.find_binding(name, parse(string), package) - - def test_simple_assignment(self): - self.assertTrue(self.find_binding("a", "a = b")) - self.assertTrue(self.find_binding("a", "a = [b, c, d]")) - self.assertTrue(self.find_binding("a", "a = foo()")) - self.assertTrue(self.find_binding("a", "a = foo().foo.foo[6][foo]")) - self.assertFalse(self.find_binding("a", "foo = a")) - self.assertFalse(self.find_binding("a", "foo = (a, b, c)")) - - def test_tuple_assignment(self): - self.assertTrue(self.find_binding("a", "(a,) = b")) - self.assertTrue(self.find_binding("a", "(a, b, c) = [b, c, d]")) - self.assertTrue(self.find_binding("a", "(c, (d, a), b) = foo()")) - self.assertTrue(self.find_binding("a", "(a, b) = foo().foo[6][foo]")) - self.assertFalse(self.find_binding("a", "(foo, b) = (b, a)")) - self.assertFalse(self.find_binding("a", "(foo, (b, c)) = (a, b, c)")) - - def test_list_assignment(self): - self.assertTrue(self.find_binding("a", "[a] = b")) - self.assertTrue(self.find_binding("a", "[a, b, c] = [b, c, d]")) - self.assertTrue(self.find_binding("a", "[c, [d, a], b] = foo()")) - self.assertTrue(self.find_binding("a", "[a, b] = foo().foo[a][foo]")) - self.assertFalse(self.find_binding("a", "[foo, b] = (b, a)")) - self.assertFalse(self.find_binding("a", "[foo, [b, c]] = (a, b, c)")) - - def test_invalid_assignments(self): - self.assertFalse(self.find_binding("a", "foo.a = 5")) - self.assertFalse(self.find_binding("a", "foo[a] = 5")) - self.assertFalse(self.find_binding("a", "foo(a) = 5")) - self.assertFalse(self.find_binding("a", "foo(a, b) = 5")) - - def test_simple_import(self): - self.assertTrue(self.find_binding("a", "import a")) - self.assertTrue(self.find_binding("a", "import b, c, a, d")) - self.assertFalse(self.find_binding("a", "import b")) - self.assertFalse(self.find_binding("a", "import b, c, d")) - - def test_from_import(self): - self.assertTrue(self.find_binding("a", "from x import a")) - self.assertTrue(self.find_binding("a", "from a import a")) - self.assertTrue(self.find_binding("a", "from x import b, c, a, d")) - self.assertTrue(self.find_binding("a", "from x.b import a")) - self.assertTrue(self.find_binding("a", "from x.b import b, c, a, d")) - self.assertFalse(self.find_binding("a", "from a import b")) - self.assertFalse(self.find_binding("a", "from a.d import b")) - self.assertFalse(self.find_binding("a", "from d.a import b")) - - def test_import_as(self): - self.assertTrue(self.find_binding("a", "import b as a")) - self.assertTrue(self.find_binding("a", "import b as a, c, a as f, d")) - self.assertFalse(self.find_binding("a", "import a as f")) - self.assertFalse(self.find_binding("a", "import b, c as f, d as e")) - - def test_from_import_as(self): - self.assertTrue(self.find_binding("a", "from x import b as a")) - self.assertTrue(self.find_binding("a", "from x import g as a, d as b")) - self.assertTrue(self.find_binding("a", "from x.b import t as a")) - self.assertTrue(self.find_binding("a", "from x.b import g as a, d")) - self.assertFalse(self.find_binding("a", "from a import b as t")) - self.assertFalse(self.find_binding("a", "from a.d import b as t")) - self.assertFalse(self.find_binding("a", "from d.a import b as t")) - - def test_simple_import_with_package(self): - self.assertTrue(self.find_binding("b", "import b")) - self.assertTrue(self.find_binding("b", "import b, c, d")) - self.assertFalse(self.find_binding("b", "import b", "b")) - self.assertFalse(self.find_binding("b", "import b, c, d", "c")) - - def test_from_import_with_package(self): - self.assertTrue(self.find_binding("a", "from x import a", "x")) - self.assertTrue(self.find_binding("a", "from a import a", "a")) - self.assertTrue(self.find_binding("a", "from x import *", "x")) - self.assertTrue(self.find_binding("a", "from x import b, c, a, d", "x")) - self.assertTrue(self.find_binding("a", "from x.b import a", "x.b")) - self.assertTrue(self.find_binding("a", "from x.b import *", "x.b")) - self.assertTrue(self.find_binding("a", "from x.b import b, c, a, d", "x.b")) - self.assertFalse(self.find_binding("a", "from a import b", "a")) - self.assertFalse(self.find_binding("a", "from a.d import b", "a.d")) - self.assertFalse(self.find_binding("a", "from d.a import b", "a.d")) - self.assertFalse(self.find_binding("a", "from x.y import *", "a.b")) - - def test_import_as_with_package(self): - self.assertFalse(self.find_binding("a", "import b.c as a", "b.c")) - self.assertFalse(self.find_binding("a", "import a as f", "f")) - self.assertFalse(self.find_binding("a", "import a as f", "a")) - - def test_from_import_as_with_package(self): - # Because it would take a lot of special-case code in the fixers - # to deal with from foo import bar as baz, we'll simply always - # fail if there is an "from ... import ... as ..." - self.assertFalse(self.find_binding("a", "from x import b as a", "x")) - self.assertFalse(self.find_binding("a", "from x import g as a, d as b", "x")) - self.assertFalse(self.find_binding("a", "from x.b import t as a", "x.b")) - self.assertFalse(self.find_binding("a", "from x.b import g as a, d", "x.b")) - self.assertFalse(self.find_binding("a", "from a import b as t", "a")) - self.assertFalse(self.find_binding("a", "from a import b as t", "b")) - self.assertFalse(self.find_binding("a", "from a import b as t", "t")) - - def test_function_def(self): - self.assertTrue(self.find_binding("a", "def a(): pass")) - self.assertTrue(self.find_binding("a", "def a(b, c, d): pass")) - self.assertTrue(self.find_binding("a", "def a(): b = 7")) - self.assertFalse(self.find_binding("a", "def d(b, (c, a), e): pass")) - self.assertFalse(self.find_binding("a", "def d(a=7): pass")) - self.assertFalse(self.find_binding("a", "def d(a): pass")) - self.assertFalse(self.find_binding("a", "def d(): a = 7")) - - s = """ - def d(): - def a(): - pass""" - self.assertFalse(self.find_binding("a", s)) - - def test_class_def(self): - self.assertTrue(self.find_binding("a", "class a: pass")) - self.assertTrue(self.find_binding("a", "class a(): pass")) - self.assertTrue(self.find_binding("a", "class a(b): pass")) - self.assertTrue(self.find_binding("a", "class a(b, c=8): pass")) - self.assertFalse(self.find_binding("a", "class d: pass")) - self.assertFalse(self.find_binding("a", "class d(a): pass")) - self.assertFalse(self.find_binding("a", "class d(b, a=7): pass")) - self.assertFalse(self.find_binding("a", "class d(b, *a): pass")) - self.assertFalse(self.find_binding("a", "class d(b, **a): pass")) - self.assertFalse(self.find_binding("a", "class d: a = 7")) - - s = """ - class d(): - class a(): - pass""" - self.assertFalse(self.find_binding("a", s)) - - def test_for(self): - self.assertTrue(self.find_binding("a", "for a in r: pass")) - self.assertTrue(self.find_binding("a", "for a, b in r: pass")) - self.assertTrue(self.find_binding("a", "for (a, b) in r: pass")) - self.assertTrue(self.find_binding("a", "for c, (a,) in r: pass")) - self.assertTrue(self.find_binding("a", "for c, (a, b) in r: pass")) - self.assertTrue(self.find_binding("a", "for c in r: a = c")) - self.assertFalse(self.find_binding("a", "for c in a: pass")) - - def test_for_nested(self): - s = """ - for b in r: - for a in b: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - for b in r: - for a, c in b: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - for b in r: - for (a, c) in b: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - for b in r: - for (a,) in b: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - for b in r: - for c, (a, d) in b: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - for b in r: - for c in b: - a = 7""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - for b in r: - for c in b: - d = a""" - self.assertFalse(self.find_binding("a", s)) - - s = """ - for b in r: - for c in a: - d = 7""" - self.assertFalse(self.find_binding("a", s)) - - def test_if(self): - self.assertTrue(self.find_binding("a", "if b in r: a = c")) - self.assertFalse(self.find_binding("a", "if a in r: d = e")) - - def test_if_nested(self): - s = """ - if b in r: - if c in d: - a = c""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - if b in r: - if c in d: - c = a""" - self.assertFalse(self.find_binding("a", s)) - - def test_while(self): - self.assertTrue(self.find_binding("a", "while b in r: a = c")) - self.assertFalse(self.find_binding("a", "while a in r: d = e")) - - def test_while_nested(self): - s = """ - while b in r: - while c in d: - a = c""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - while b in r: - while c in d: - c = a""" - self.assertFalse(self.find_binding("a", s)) - - def test_try_except(self): - s = """ - try: - a = 6 - except: - b = 8""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except: - a = 6""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except KeyError: - pass - except: - a = 6""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except: - b = 6""" - self.assertFalse(self.find_binding("a", s)) - - def test_try_except_nested(self): - s = """ - try: - try: - a = 6 - except: - pass - except: - b = 8""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except: - try: - a = 6 - except: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except: - try: - pass - except: - a = 6""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - try: - b = 8 - except KeyError: - pass - except: - a = 6 - except: - pass""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - pass - except: - try: - b = 8 - except KeyError: - pass - except: - a = 6""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except: - b = 6""" - self.assertFalse(self.find_binding("a", s)) - - s = """ - try: - try: - b = 8 - except: - c = d - except: - try: - b = 6 - except: - t = 8 - except: - o = y""" - self.assertFalse(self.find_binding("a", s)) - - def test_try_except_finally(self): - s = """ - try: - c = 6 - except: - b = 8 - finally: - a = 9""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - finally: - a = 6""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - finally: - b = 6""" - self.assertFalse(self.find_binding("a", s)) - - s = """ - try: - b = 8 - except: - b = 9 - finally: - b = 6""" - self.assertFalse(self.find_binding("a", s)) - - def test_try_except_finally_nested(self): - s = """ - try: - c = 6 - except: - b = 8 - finally: - try: - a = 9 - except: - b = 9 - finally: - c = 9""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - finally: - try: - pass - finally: - a = 6""" - self.assertTrue(self.find_binding("a", s)) - - s = """ - try: - b = 8 - finally: - try: - b = 6 - finally: - b = 7""" - self.assertFalse(self.find_binding("a", s)) - -class Test_touch_import(support.TestCase): - - def test_after_docstring(self): - node = parse('"""foo"""\nbar()') - fixer_util.touch_import(None, "foo", node) - self.assertEqual(str(node), '"""foo"""\nimport foo\nbar()\n\n') - - def test_after_imports(self): - node = parse('"""foo"""\nimport bar\nbar()') - fixer_util.touch_import(None, "foo", node) - self.assertEqual(str(node), '"""foo"""\nimport bar\nimport foo\nbar()\n\n') - - def test_beginning(self): - node = parse('bar()') - fixer_util.touch_import(None, "foo", node) - self.assertEqual(str(node), 'import foo\nbar()\n\n') - - def test_from_import(self): - node = parse('bar()') - fixer_util.touch_import("html", "escape", node) - self.assertEqual(str(node), 'from html import escape\nbar()\n\n') - - def test_name_import(self): - node = parse('bar()') - fixer_util.touch_import(None, "cgi", node) - self.assertEqual(str(node), 'import cgi\nbar()\n\n') - -class Test_find_indentation(support.TestCase): - - def test_nothing(self): - fi = fixer_util.find_indentation - node = parse("node()") - self.assertEqual(fi(node), "") - node = parse("") - self.assertEqual(fi(node), "") - - def test_simple(self): - fi = fixer_util.find_indentation - node = parse("def f():\n x()") - self.assertEqual(fi(node), "") - self.assertEqual(fi(node.children[0].children[4].children[2]), " ") - node = parse("def f():\n x()\n y()") - self.assertEqual(fi(node.children[0].children[4].children[4]), " ") diff --git a/Lib/test/test_tools/test_sundry.py b/Lib/test/test_tools/test_sundry.py index 3177fafb84a65..2f8ba272164d3 100644 --- a/Lib/test/test_tools/test_sundry.py +++ b/Lib/test/test_tools/test_sundry.py @@ -14,11 +14,6 @@ skip_if_missing() class TestSundryScripts(unittest.TestCase): - # At least make sure the rest don't have syntax errors. When tests are - # added for a script it should be added to the allowlist below. - - skiplist = ['2to3'] - # import logging registers "atfork" functions which keep indirectly the # logging module dictionary alive. Mock the function to be able to unload # cleanly the logging module. @@ -31,9 +26,6 @@ def test_sundry(self, mock_os): continue name = fn[:-3] - if name in self.skiplist: - continue - import_tool(name) finally: # Unload all modules loaded in this test diff --git a/Mac/BuildScript/scripts/postflight.framework b/Mac/BuildScript/scripts/postflight.framework index a63909358f171..411fda13b8955 100755 --- a/Mac/BuildScript/scripts/postflight.framework +++ b/Mac/BuildScript/scripts/postflight.framework @@ -8,12 +8,12 @@ FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@" "${FWK}/bin/python at PYVER@" -E -s -Wi \ "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ - -f -x 'bad_coding|badsyntax|site-packages|test/test_lib2to3/data' \ + -f -x 'bad_coding|badsyntax|site-packages' \ "${FWK}/lib/python${PYVER}" "${FWK}/bin/python at PYVER@" -E -s -Wi -O \ "${FWK}/lib/python${PYVER}/compileall.py" -q -j0 \ - -f -x 'bad_coding|badsyntax|site-packages|test/test_lib2to3/data' \ + -f -x 'bad_coding|badsyntax|site-packages' \ "${FWK}/lib/python${PYVER}" "${FWK}/bin/python at PYVER@" -E -s -Wi \ diff --git a/Mac/Makefile.in b/Mac/Makefile.in index 69ab419898857..78b4499cca986 100644 --- a/Mac/Makefile.in +++ b/Mac/Makefile.in @@ -63,7 +63,6 @@ installunixtools: fi cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \ for fn in \ - 2to3 \ idle3 \ pydoc3 \ python3 \ @@ -123,7 +122,6 @@ altinstallunixtools: fi cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \ for fn in \ - 2to3-$(VERSION) \ idle$(VERSION) \ pydoc$(VERSION) \ python$(VERSION) \ diff --git a/Makefile.pre.in b/Makefile.pre.in index eb79c9c4ca180..091df3e4c0b81 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1869,7 +1869,7 @@ hostrunnertest: all pythoninfo: all $(RUNSHARED) $(HOSTRUNNER) ./$(BUILDPYTHON) -m test.pythoninfo -QUICKTESTOPTS= $(TESTOPTS) -x test_subprocess test_io test_lib2to3 \ +QUICKTESTOPTS= $(TESTOPTS) -x test_subprocess test_io \ test_multibytecodec test_urllib2_localnet test_itertools \ test_multiprocessing_fork test_multiprocessing_spawn \ test_multiprocessing_forkserver \ @@ -2042,8 +2042,6 @@ bininstall: altbininstall (cd $(DESTDIR)$(BINDIR); $(LN) -s idle$(VERSION) idle3) -rm -f $(DESTDIR)$(BINDIR)/pydoc3 (cd $(DESTDIR)$(BINDIR); $(LN) -s pydoc$(VERSION) pydoc3) - -rm -f $(DESTDIR)$(BINDIR)/2to3 - (cd $(DESTDIR)$(BINDIR); $(LN) -s 2to3-$(VERSION) 2to3) if test "x$(LIPO_32BIT_FLAGS)" != "x" ; then \ rm -f $(DESTDIR)$(BINDIR)/python3-32$(EXE); \ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)-32$(EXE) python3-32$(EXE)) \ @@ -2090,7 +2088,6 @@ LIBSUBDIRS= asyncio \ idlelib idlelib/Icons \ importlib importlib/resources importlib/metadata \ json \ - lib2to3 lib2to3/fixes lib2to3/pgen2 \ logging \ multiprocessing multiprocessing/dummy \ pydoc_data \ @@ -2184,10 +2181,6 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_importlib/resources/zipdata02 \ test/test_importlib/source \ test/test_json \ - test/test_lib2to3 \ - test/test_lib2to3/data \ - test/test_lib2to3/data/fixers \ - test/test_lib2to3/data/fixers/myfixes \ test/test_peg_generator \ test/test_sqlite3 \ test/test_tkinter \ @@ -2301,16 +2294,12 @@ libinstall: all $(srcdir)/Modules/xxmodule.c -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ $(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \ -o 0 -o 1 -o 2 $(COMPILEALL_OPTS) -d $(LIBDEST) -f \ - -x 'bad_coding|badsyntax|site-packages|test/test_lib2to3/data' \ + -x 'bad_coding|badsyntax|site-packages' \ $(DESTDIR)$(LIBDEST) -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ $(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \ -o 0 -o 1 -o 2 $(COMPILEALL_OPTS) -d $(LIBDEST)/site-packages -f \ -x badsyntax $(DESTDIR)$(LIBDEST)/site-packages - -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ - $(PYTHON_FOR_BUILD) -m lib2to3.pgen2.driver $(DESTDIR)$(LIBDEST)/lib2to3/Grammar.txt - -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ - $(PYTHON_FOR_BUILD) -m lib2to3.pgen2.driver $(DESTDIR)$(LIBDEST)/lib2to3/PatternGrammar.txt # bpo-21536: Misc/python-config.sh is generated in the build directory # from $(srcdir)Misc/python-config.sh.in. @@ -2330,15 +2319,9 @@ python-config: $(srcdir)/Misc/python-config.in Misc/python-config.sh # macOS' make seems to ignore a dependency on a # "$(BUILD_SCRIPTS_DIR): $(MKDIR_P) $@" rule. BUILD_SCRIPTS_DIR=build/scripts-$(VERSION) -SCRIPT_2TO3=$(BUILD_SCRIPTS_DIR)/2to3-$(VERSION) SCRIPT_IDLE=$(BUILD_SCRIPTS_DIR)/idle$(VERSION) SCRIPT_PYDOC=$(BUILD_SCRIPTS_DIR)/pydoc$(VERSION) -$(SCRIPT_2TO3): $(srcdir)/Tools/scripts/2to3 - @$(MKDIR_P) $(BUILD_SCRIPTS_DIR) - sed -e "s,/usr/bin/env python3,$(EXENAME)," < $(srcdir)/Tools/scripts/2to3 > $@ - @chmod +x $@ - $(SCRIPT_IDLE): $(srcdir)/Tools/scripts/idle3 @$(MKDIR_P) $(BUILD_SCRIPTS_DIR) sed -e "s,/usr/bin/env python3,$(EXENAME)," < $(srcdir)/Tools/scripts/idle3 > $@ @@ -2350,7 +2333,7 @@ $(SCRIPT_PYDOC): $(srcdir)/Tools/scripts/pydoc3 @chmod +x $@ .PHONY: scripts -scripts: $(SCRIPT_2TO3) $(SCRIPT_IDLE) $(SCRIPT_PYDOC) python-config +scripts: $(SCRIPT_IDLE) $(SCRIPT_PYDOC) python-config # Install the include files INCLDIRSTOMAKE=$(INCLUDEDIR) $(CONFINCLUDEDIR) $(INCLUDEPY) $(CONFINCLUDEPY) @@ -2436,7 +2419,6 @@ libainstall: all scripts $(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh $(INSTALL_SCRIPT) python-config.py $(DESTDIR)$(LIBPL)/python-config.py $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(LDVERSION)-config - $(INSTALL_SCRIPT) $(SCRIPT_2TO3) $(DESTDIR)$(BINDIR)/2to3-$(VERSION) $(INSTALL_SCRIPT) $(SCRIPT_IDLE) $(DESTDIR)$(BINDIR)/idle$(VERSION) $(INSTALL_SCRIPT) $(SCRIPT_PYDOC) $(DESTDIR)$(BINDIR)/pydoc$(VERSION) @if [ -s Modules/python.exp -a \ @@ -2637,7 +2619,6 @@ clean-retain-profile: pycremoval find build -name '*.py' -exec rm -f {} ';' || true find build -name '*.py[co]' -exec rm -f {} ';' || true -rm -f pybuilddir.txt - -rm -f Lib/lib2to3/*Grammar*.pickle -rm -f _bootstrap_python -rm -f python.html python*.js python.data python*.symbols python*.map -rm -f $(WASM_STDLIB) diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst index 7670e482ede5b..10e123e325c86 100644 --- a/Misc/NEWS.d/3.11.0a1.rst +++ b/Misc/NEWS.d/3.11.0a1.rst @@ -1825,7 +1825,7 @@ Patch by Victor Stinner. .. nonce: 9nmMtB .. section: Library -The :mod:`lib2to3` package is now deprecated and may not be able to parse +The :mod:`!lib2to3` package is now deprecated and may not be able to parse Python 3.10 or newer. See the :pep:`617` (New PEG parser for CPython). Patch by Victor Stinner. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index 854458f2d1a99..2564167cdf089 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -2747,7 +2747,7 @@ smaller file). Also, change the default compression level to 6 (tradeoff). .. nonce: xo5LAr .. section: Library -The :term:`2to3` :2to3fixer:`execfile` fixer now opens the file with mode +The 2to3 ``execfile`` fixer now opens the file with mode ``'rb'``. Patch by Zackery Spytz. .. @@ -3817,7 +3817,7 @@ user. .. nonce: w6g7tn .. section: Library -The :2to3fixer:`reload` fixer now uses :func:`importlib.reload` instead of +The ``reload`` fixer now uses :func:`importlib.reload` instead of deprecated :func:`!imp.reload`. .. diff --git a/Misc/NEWS.d/3.9.0a3.rst b/Misc/NEWS.d/3.9.0a3.rst index 54b61ca3b7785..b05b4c3d7204c 100644 --- a/Misc/NEWS.d/3.9.0a3.rst +++ b/Misc/NEWS.d/3.9.0a3.rst @@ -571,7 +571,7 @@ new task spawning before exception raising. .. section: Library Correctly parenthesize filter-based statements that contain lambda -expressions in mod:`lib2to3`. Patch by Dong-hee Na. +expressions in mod:`!lib2to3`. Patch by Dong-hee Na. .. diff --git a/Misc/NEWS.d/3.9.0a6.rst b/Misc/NEWS.d/3.9.0a6.rst index af2cc7c3e9788..9594964917f39 100644 --- a/Misc/NEWS.d/3.9.0a6.rst +++ b/Misc/NEWS.d/3.9.0a6.rst @@ -343,7 +343,7 @@ https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=242274 .. nonce: Er8sv- .. section: Library -The :mod:`lib2to3` module is pending deprecation due to :pep:`617`. +The :mod:`!lib2to3` module is pending deprecation due to :pep:`617`. .. diff --git a/Misc/NEWS.d/next/Library/2023-05-23-03-36-47.gh-issue-104780.P4e3Yf.rst b/Misc/NEWS.d/next/Library/2023-05-23-03-36-47.gh-issue-104780.P4e3Yf.rst new file mode 100644 index 0000000000000..acdca53b4bb7d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-03-36-47.gh-issue-104780.P4e3Yf.rst @@ -0,0 +1,2 @@ +Remove the ``2to3`` program and the :mod:`!lib2to3` module, deprecated in +Python 3.11. Patch by Victor Stinner. diff --git a/PC/layout/main.py b/PC/layout/main.py index c9246007d47d1..cb2e4878da26b 100644 --- a/PC/layout/main.py +++ b/PC/layout/main.py @@ -49,8 +49,6 @@ REQUIRED_DLLS = FileStemSet("libcrypto*", "libssl*", "libffi*") -LIB2TO3_GRAMMAR_FILES = FileNameSet("Grammar.txt", "PatternGrammar.txt") - PY_FILES = FileSuffixSet(".py") PYC_FILES = FileSuffixSet(".pyc") CAT_FILES = FileSuffixSet(".cat") @@ -298,27 +296,6 @@ def _write_to_zip(zf, dest, src, ns, checked=True): log_exception("Failed to delete {}", pyc) return - if src in LIB2TO3_GRAMMAR_FILES: - from lib2to3.pgen2.driver import load_grammar - - tmp = ns.temp / src.name - try: - shutil.copy(src, tmp) - load_grammar(str(tmp)) - for f in ns.temp.glob(src.stem + "*.pickle"): - zf.write(str(f), str(dest.parent / f.name)) - try: - f.unlink() - except: - log_exception("Failed to delete {}", f) - except: - log_exception("Failed to compile {}", src) - finally: - try: - tmp.unlink() - except: - log_exception("Failed to delete {}", tmp) - zf.write(str(src), str(dest)) diff --git a/PC/layout/support/props.py b/PC/layout/support/props.py index c7a7a0ce777a6..f751a4b3f1e43 100644 --- a/PC/layout/support/props.py +++ b/PC/layout/support/props.py @@ -36,7 +36,6 @@ <PythonVersion>{PYTHON_VERSION}</PythonVersion> <IncludePythonExe Condition="$(IncludePythonExe) == ''">true</IncludePythonExe> - <IncludeLib2To3 Condition="$(IncludeLib2To3) == ''">false</IncludeLib2To3> <IncludeVEnv Condition="$(IncludeVEnv) == ''">false</IncludeVEnv> <GetPythonRuntimeFilesDependsOn>{PYTHON_TARGET};$(GetPythonRuntimeFilesDependsOn)</GetPythonRuntimeFilesDependsOn> @@ -67,7 +66,6 @@ <Link>DLLs\%(Filename)%(Extension)</Link> </_PythonRuntimeDlls> <_PythonRuntimeLib Include="$(PythonHome)\Lib\**\*" Exclude="$(PythonHome)\Lib\**\*.pyc;$(PythonHome)\Lib\site-packages\**\*" /> - <_PythonRuntimeLib Remove="$(PythonHome)\Lib\lib2to3\**\*" Condition="$(IncludeLib2To3) != 'true'" /> <_PythonRuntimeLib Remove="$(PythonHome)\Lib\ensurepip\**\*" Condition="$(IncludeVEnv) != 'true'" /> <_PythonRuntimeLib Remove="$(PythonHome)\Lib\venv\**\*" Condition="$(IncludeVEnv) != 'true'" /> <_PythonRuntimeLib> diff --git a/PC/layout/support/python.props b/PC/layout/support/python.props index e46891aafcb9f..c48ecb2f9c1b5 100644 --- a/PC/layout/support/python.props +++ b/PC/layout/support/python.props @@ -8,7 +8,6 @@ <PythonVersion>$$PYTHON_VERSION$$</PythonVersion> <IncludePythonExe Condition="$(IncludePythonExe) == ''">true</IncludePythonExe> - <IncludeLib2To3 Condition="$(IncludeLib2To3) == ''">false</IncludeLib2To3> <IncludeVEnv Condition="$(IncludeVEnv) == ''">false</IncludeVEnv> <GetPythonRuntimeFilesDependsOn>$$PYTHON_TARGET$$;$(GetPythonRuntimeFilesDependsOn)</GetPythonRuntimeFilesDependsOn> @@ -40,7 +39,6 @@ <Link>DLLs\%(Filename)%(Extension)</Link> </_PythonRuntimeDlls> <_PythonRuntimeLib Include="$(PythonHome)\Lib\**\*" Exclude="$(PythonHome)\Lib\**\*.pyc;$(PythonHome)\Lib\site-packages\**\*" /> - <_PythonRuntimeLib Remove="$(PythonHome)\Lib\lib2to3\**\*" Condition="$(IncludeLib2To3) != 'true'" /> <_PythonRuntimeLib Remove="$(PythonHome)\Lib\ensurepip\**\*" Condition="$(IncludeVEnv) != 'true'" /> <_PythonRuntimeLib Remove="$(PythonHome)\Lib\venv\**\*" Condition="$(IncludeVEnv) != 'true'" /> <_PythonRuntimeLib> diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 4b0580557fb7a..b926caf4a5790 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -172,7 +172,6 @@ static const char* _Py_stdlib_module_names[] = { "itertools", "json", "keyword", -"lib2to3", "linecache", "locale", "logging", diff --git a/Tools/README b/Tools/README index e51624f453c5b..9c4b6d86e990b 100644 --- a/Tools/README +++ b/Tools/README @@ -39,10 +39,8 @@ patchcheck Tools for checking and applying patches to the Python source cod peg_generator PEG-based parser generator (pegen) used for new parser. -scripts A number of useful single-file programs, e.g. tabnanny.py - by Tim Peters, which checks for inconsistent mixing of - tabs and spaces, and 2to3, which converts Python 2 code - to Python 3 code. +scripts A number of useful single-file programs, e.g. run_tests.py + which runs the Python test suite. ssl Scripts to generate ssl_data.h from OpenSSL sources, and run tests against multiple installations of OpenSSL and LibreSSL. diff --git a/Tools/msi/bundle/packagegroups/postinstall.wxs b/Tools/msi/bundle/packagegroups/postinstall.wxs index 64f42dd30e8ba..24c72e6357ab0 100644 --- a/Tools/msi/bundle/packagegroups/postinstall.wxs +++ b/Tools/msi/bundle/packagegroups/postinstall.wxs @@ -42,7 +42,7 @@ - <?define CompileAllCommand=-E -s -Wi "[TargetDir]\Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|lib2to3\\tests|venv\\scripts" "[TargetDir]\Lib"?> + <?define CompileAllCommand=-E -s -Wi "[TargetDir]\Lib\compileall.py" -f -x "bad_coding|badsyntax|site-packages|py2_|venv\\scripts" "[TargetDir]\Lib"?> <ExePackage Id="compileall_AllUsers" SourceFile="py.exe" Compressed="yes" diff --git a/Tools/msi/lib/lib_files.wxs b/Tools/msi/lib/lib_files.wxs index 73c0231352f35..3e6761b6bd5b7 100644 --- a/Tools/msi/lib/lib_files.wxs +++ b/Tools/msi/lib/lib_files.wxs @@ -116,10 +116,6 @@ <RegistryValue Key="PythonPath" Type="string" Value="[Lib];[DLLs]" /> </RegistryKey> </Component> - <Component Id="Lib2to3_pickle_remove" Directory="Lib_lib2to3" Guid="$(var.RemoveLib2to3PickleComponentGuid)"> - <RemoveFile Id="Lib2to3_pickle_remove_files" Name="*.pickle" On="uninstall" /> - <RemoveFolder Id="Lib2to3_pickle_remove_folder" On="uninstall" /> - </Component> </ComponentGroup> </Fragment> <Fragment> diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props index 06aa0b8bbca27..cfb3ca9e76e24 100644 --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -156,9 +156,6 @@ <_Uuid Include="PythonwExeComponentGuid"> <Uri>pythonw.exe</Uri> </_Uuid> - <_Uuid Include="RemoveLib2to3PickleComponentGuid"> - <Uri>lib2to3/pickles</Uri> - </_Uuid> <_Uuid Include="CommonPythonRegComponentGuid"> <Uri>registry</Uri> </_Uuid> @@ -187,4 +184,4 @@ <DefineConstants>$(DefineConstants);@(_UuidValue,';');</DefineConstants> </PropertyGroup> </Target> -</Project> \ No newline at end of file +</Project> diff --git a/Tools/peg_generator/Makefile b/Tools/peg_generator/Makefile index 084da154919e3..eef2d807e5c5c 100644 --- a/Tools/peg_generator/Makefile +++ b/Tools/peg_generator/Makefile @@ -87,8 +87,7 @@ time_stdlib: $(CPYTHON) venv $(VENVPYTHON) scripts/test_parse_directory.py \ -d $(CPYTHON) \ $(TESTFLAGS) \ - --exclude "*/bad*" \ - --exclude "*/test/test_lib2to3/data/*" + --exclude "*/bad*" mypy: regen-metaparser $(MYPY) # For list of files, see mypy.ini diff --git a/Tools/peg_generator/scripts/benchmark.py b/Tools/peg_generator/scripts/benchmark.py index 053f8ef06d42c..6354e1a17167a 100644 --- a/Tools/peg_generator/scripts/benchmark.py +++ b/Tools/peg_generator/scripts/benchmark.py @@ -78,7 +78,6 @@ def run_benchmark_stdlib(subcommand): verbose=False, excluded_files=[ "*/bad*", - "*/test/test_lib2to3/data/*", ], short=True, mode=modes[subcommand], diff --git a/Tools/scripts/2to3 b/Tools/scripts/2to3 deleted file mode 100755 index f27d18ecf6708..0000000000000 --- a/Tools/scripts/2to3 +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python3 -import sys -from lib2to3.main import main - -sys.exit(main("lib2to3.fixes")) diff --git a/Tools/scripts/README b/Tools/scripts/README index 9dbb89a8dae63..a078bfbf662a3 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -1,7 +1,6 @@ This directory contains a collection of executable Python scripts that are useful while building, extending or managing Python. -2to3 Main script for running the 2to3 conversion tool checkpip.py Checks the version of the projects bundled in ensurepip are the latest available combinerefs.py A helper for analyzing PYTHONDUMPREFS output diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py index 22bf9eabdcd6b..fcd99405ee0d8 100755 --- a/Tools/wasm/wasm_assets.py +++ b/Tools/wasm/wasm_assets.py @@ -41,8 +41,6 @@ # package management "ensurepip/", "venv/", - # build system - "lib2to3/", # deprecated "uu.py", "xdrlib.py", From webhook-mailer at python.org Tue May 23 14:12:07 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 23 May 2023 18:12:07 -0000 Subject: [Python-checkins] [3.12] gh-104271: Fix auto() fallback in case of mixed type Enum (GH-104279) Message-ID: <mailman.20.1684865529.17421.python-checkins@python.org> https://github.com/python/cpython/commit/f4e2049f14d40c1b893c68530eec5e341cf3d929 commit: f4e2049f14d40c1b893c68530eec5e341cf3d929 branch: 3.12 author: Itamar Ostricher <itamarost at gmail.com> committer: ethanfurman <ethan at stoneleaf.us> date: 2023-05-23T11:11:35-07:00 summary: [3.12] gh-104271: Fix auto() fallback in case of mixed type Enum (GH-104279) gh-104271: Fix auto() fallback in case of mixed type Enum files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 6e497f7ef6a7..bb71c84bd463 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1185,7 +1185,7 @@ def _generate_next_value_(name, start, count, last_values): DeprecationWarning, stacklevel=3, ) - for v in last_values: + for v in reversed(last_values): try: return v + 1 except TypeError: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index fb7a016c9007..98010d18c0ad 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4254,11 +4254,14 @@ class Color(Enum): red = 'red' blue = 2 green = auto() + yellow = auto() - self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(list(Color), + [Color.red, Color.blue, Color.green, Color.yellow]) self.assertEqual(Color.red.value, 'red') self.assertEqual(Color.blue.value, 2) self.assertEqual(Color.green.value, 3) + self.assertEqual(Color.yellow.value, 4) @unittest.skipIf( python_version < (3, 13), From webhook-mailer at python.org Tue May 23 15:48:28 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 23 May 2023 19:48:28 -0000 Subject: [Python-checkins] [3.11] gh-104271: Fix auto() fallback in case of mixed type Enum (GH-104809) Message-ID: <mailman.21.1684871309.17421.python-checkins@python.org> https://github.com/python/cpython/commit/582aadc80e566fe8ab9b15d4d221e1ea84d03c6a commit: 582aadc80e566fe8ab9b15d4d221e1ea84d03c6a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ethanfurman <ethan at stoneleaf.us> date: 2023-05-23T12:48:20-07:00 summary: [3.11] gh-104271: Fix auto() fallback in case of mixed type Enum (GH-104809) [3.12] gh-104271: Fix auto() fallback in case of mixed type Enum (GH-104279) (cherry picked from commit f4e2049f14d40c1b893c68530eec5e341cf3d929) Co-authored-by: Itamar Ostricher <itamarost at gmail.com> files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 26e5c50bf856..45e3cd0b95d9 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1170,7 +1170,7 @@ def _generate_next_value_(name, start, count, last_values): DeprecationWarning, stacklevel=3, ) - for v in last_values: + for v in reversed(last_values): try: return v + 1 except TypeError: diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 188e1a174756..f5cefa2f3520 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4176,11 +4176,14 @@ class Color(Enum): red = 'red' blue = 2 green = auto() + yellow = auto() - self.assertEqual(list(Color), [Color.red, Color.blue, Color.green]) + self.assertEqual(list(Color), + [Color.red, Color.blue, Color.green, Color.yellow]) self.assertEqual(Color.red.value, 'red') self.assertEqual(Color.blue.value, 2) self.assertEqual(Color.green.value, 3) + self.assertEqual(Color.yellow.value, 4) @unittest.skipIf( python_version < (3, 13), From webhook-mailer at python.org Tue May 23 16:01:24 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 23 May 2023 20:01:24 -0000 Subject: [Python-checkins] Fix missing/incomplete NULL checks in multiple source files (#104564) Message-ID: <mailman.22.1684872086.17421.python-checkins@python.org> https://github.com/python/cpython/commit/13b5d79090cdca138ca340de88f57e02279faf6d commit: 13b5d79090cdca138ca340de88f57e02279faf6d branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: carljm <carl at oddbird.net> date: 2023-05-23T14:01:17-06:00 summary: Fix missing/incomplete NULL checks in multiple source files (#104564) Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: M Modules/_zoneinfo.c M Modules/errnomodule.c M Modules/posixmodule.c M Modules/sha1module.c M Modules/zlibmodule.c diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index c8c791b6d7c0..0dcdb4da47d5 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -2381,7 +2381,12 @@ get_local_timestamp(PyObject *dt, int64_t *local_ts) ///// // Functions for cache handling -/* Constructor for StrongCacheNode */ +/* Constructor for StrongCacheNode + * + * This function doesn't set MemoryError if PyMem_Malloc fails, + * as the cache intentionally doesn't propagate exceptions + * and fails silently if error occurs. + */ static StrongCacheNode * strong_cache_node_new(PyObject *key, PyObject *zone) { @@ -2572,6 +2577,9 @@ update_strong_cache(zoneinfo_state *state, const PyTypeObject *const type, } StrongCacheNode *new_node = strong_cache_node_new(key, zone); + if (new_node == NULL) { + return; + } StrongCacheNode **root = &(state->ZONEINFO_STRONG_CACHE); move_strong_cache_node_to_front(state, root, new_node); diff --git a/Modules/errnomodule.c b/Modules/errnomodule.c index fddde960a5fe..3d0c2d7ae945 100644 --- a/Modules/errnomodule.c +++ b/Modules/errnomodule.c @@ -84,6 +84,7 @@ errno_exec(PyObject *module) PyObject *module_dict = PyModule_GetDict(module); PyObject *error_dict = PyDict_New(); if (!module_dict || !error_dict) { + Py_XDECREF(error_dict); return -1; } if (PyDict_SetItemString(module_dict, "errorcode", error_dict) < 0) { diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 531f26ba8bc8..2fe9973ef5bf 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9023,6 +9023,10 @@ os_setgroups(PyObject *module, PyObject *groups) } gid_t *grouplist = PyMem_New(gid_t, len); + if (grouplist == NULL) { + PyErr_NoMemory(); + return NULL; + } for (Py_ssize_t i = 0; i < len; i++) { PyObject *elem; elem = PySequence_GetItem(groups, i); diff --git a/Modules/sha1module.c b/Modules/sha1module.c index c66269b5f5cd..ef8e067dd337 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -73,6 +73,9 @@ static SHA1object * newSHA1object(SHA1State *st) { SHA1object *sha = (SHA1object *)PyObject_GC_New(SHA1object, st->sha1_type); + if (sha == NULL) { + return NULL; + } sha->lock = NULL; PyObject_GC_Track(sha); return sha; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index b67844a67c31..534d065765f0 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1722,6 +1722,9 @@ ZlibDecompressor__new__(PyTypeObject *cls, return NULL; } ZlibDecompressor *self = PyObject_New(ZlibDecompressor, cls); + if (self == NULL) { + return NULL; + } self->eof = 0; self->needs_input = 1; self->avail_in_real = 0; From webhook-mailer at python.org Tue May 23 16:03:20 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 23 May 2023 20:03:20 -0000 Subject: [Python-checkins] Remove gh-103207 changelog item as it was never part of any release. (GH-104814) Message-ID: <mailman.23.1684872200.17421.python-checkins@python.org> https://github.com/python/cpython/commit/08b4eb83aadcbdb389b5970b51cac9be95146c2a commit: 08b4eb83aadcbdb389b5970b51cac9be95146c2a branch: main author: Ned Deily <nad at python.org> committer: ned-deily <nad at python.org> date: 2023-05-23T16:03:13-04:00 summary: Remove gh-103207 changelog item as it was never part of any release. (GH-104814) files: M Misc/NEWS.d/3.12.0b1.rst diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index eb42b45726f5..a1ea082b3a21 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -2236,16 +2236,6 @@ update curses textbox to additionally handle backspace using the .. -.. 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-03-24-11-20-47 .. gh-issue: 102997 .. nonce: ZgQkbq From webhook-mailer at python.org Tue May 23 16:04:51 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 23 May 2023 20:04:51 -0000 Subject: [Python-checkins] [3.12] Remove gh-103207 changelog item as it was never part of any release. (GH-104815) Message-ID: <mailman.24.1684872293.17421.python-checkins@python.org> https://github.com/python/cpython/commit/5c8418c5cc6737cd40df448eff80d2297f68e1a5 commit: 5c8418c5cc6737cd40df448eff80d2297f68e1a5 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily <nad at python.org> date: 2023-05-23T16:04:44-04:00 summary: [3.12] Remove gh-103207 changelog item as it was never part of any release. (GH-104815) (cherry picked from commit 08b4eb83aadcbdb389b5970b51cac9be95146c2a) Co-authored-by: Ned Deily <nad at python.org> files: M Misc/NEWS.d/3.12.0b1.rst diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index eb42b45726f5..a1ea082b3a21 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -2236,16 +2236,6 @@ update curses textbox to additionally handle backspace using the .. -.. 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-03-24-11-20-47 .. gh-issue: 102997 .. nonce: ZgQkbq From webhook-mailer at python.org Tue May 23 16:29:37 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 23 May 2023 20:29:37 -0000 Subject: [Python-checkins] gh-104341: Add a Separate "Running" Lock for Each Thread (gh-104754) Message-ID: <mailman.25.1684873778.17421.python-checkins@python.org> https://github.com/python/cpython/commit/097b7830cd67f039ff36ba4fa285d82d26e25e84 commit: 097b7830cd67f039ff36ba4fa285d82d26e25e84 branch: main author: Eric Snow <ericsnowcurrently at gmail.com> committer: ericsnowcurrently <ericsnowcurrently at gmail.com> date: 2023-05-23T14:29:30-06:00 summary: gh-104341: Add a Separate "Running" Lock for Each Thread (gh-104754) Having a separate lock means Thread.join() doesn't need to wait for the thread to be cleaned up first. It can wait for the thread's Python target to finish running. This gives us some flexibility in how we clean up threads. (This is a minor cleanup as part of a fix for gh-104341.) files: M Lib/test/test_threading.py M Lib/threading.py diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 97165264b34b..648533923dcd 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -747,7 +747,7 @@ def f(): rc, out, err = assert_python_ok("-c", code) self.assertEqual(err, b"") - def test_tstate_lock(self): + def test_running_lock(self): # Test an implementation detail of Thread objects. started = _thread.allocate_lock() finish = _thread.allocate_lock() @@ -757,29 +757,29 @@ def f(): started.release() finish.acquire() time.sleep(0.01) - # The tstate lock is None until the thread is started + # The running lock is None until the thread is started t = threading.Thread(target=f) - self.assertIs(t._tstate_lock, None) + self.assertIs(t._running_lock, None) t.start() started.acquire() self.assertTrue(t.is_alive()) - # The tstate lock can't be acquired when the thread is running + # The running lock can't be acquired when the thread is running # (or suspended). - tstate_lock = t._tstate_lock - self.assertFalse(tstate_lock.acquire(timeout=0), False) + running_lock = t._running_lock + self.assertFalse(running_lock.acquire(timeout=0), False) finish.release() # When the thread ends, the state_lock can be successfully # acquired. - self.assertTrue(tstate_lock.acquire(timeout=support.SHORT_TIMEOUT), False) - # But is_alive() is still True: we hold _tstate_lock now, which - # prevents is_alive() from knowing the thread's end-of-life C code + self.assertTrue(running_lock.acquire(timeout=support.SHORT_TIMEOUT), False) + # But is_alive() is still True: we hold _running_lock now, which + # prevents is_alive() from knowing the thread's Python code # is done. self.assertTrue(t.is_alive()) # Let is_alive() find out the C code is done. - tstate_lock.release() + running_lock.release() self.assertFalse(t.is_alive()) - # And verify the thread disposed of _tstate_lock. - self.assertIsNone(t._tstate_lock) + # And verify the thread disposed of _running_lock. + self.assertIsNone(t._running_lock) t.join() def test_repr_stopped(self): diff --git a/Lib/threading.py b/Lib/threading.py index df273870fa42..69b4f54c050a 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -908,6 +908,7 @@ class is implemented. self._ident = None if _HAVE_THREAD_NATIVE_ID: self._native_id = None + self._running_lock = None self._tstate_lock = None self._started = Event() self._is_stopped = False @@ -926,6 +927,9 @@ def _reset_internal_locks(self, is_alive): # bpo-42350: If the fork happens when the thread is already stopped # (ex: after threading._shutdown() has been called), _tstate_lock # is None. Do nothing in this case. + if self._running_lock is not None: + self._running_lock._at_fork_reinit() + self._running_lock.acquire() if self._tstate_lock is not None: self._tstate_lock._at_fork_reinit() self._tstate_lock.acquire() @@ -933,6 +937,7 @@ def _reset_internal_locks(self, is_alive): # The thread isn't alive after fork: it doesn't have a tstate # anymore. self._is_stopped = True + self._running_lock = None self._tstate_lock = None def __repr__(self): @@ -1019,6 +1024,14 @@ def _set_ident(self): def _set_native_id(self): self._native_id = get_native_id() + def _set_running_lock(self): + """ + Set a lock object which will be released by the interpreter when + the target func has finished running. + """ + self._running_lock = _allocate_lock() + self._running_lock.acquire() + def _set_tstate_lock(self): """ Set a lock object which will be released by the interpreter when @@ -1035,6 +1048,7 @@ def _set_tstate_lock(self): def _bootstrap_inner(self): try: self._set_ident() + self._set_running_lock() self._set_tstate_lock() if _HAVE_THREAD_NATIVE_ID: self._set_native_id() @@ -1054,29 +1068,29 @@ def _bootstrap_inner(self): self._invoke_excepthook(self) finally: self._delete() + self._running_lock.release() def _stop(self): # After calling ._stop(), .is_alive() returns False and .join() returns - # immediately. ._tstate_lock must be released before calling ._stop(). + # immediately. ._running_lock must be released before calling ._stop(). # - # Normal case: C code at the end of the thread's life - # (release_sentinel in _threadmodule.c) releases ._tstate_lock, and - # that's detected by our ._wait_for_tstate_lock(), called by .join() + # Normal case: ._bootstrap_inner() releases ._running_lock, and + # that's detected by our ._wait_for_running_lock(), called by .join() # and .is_alive(). Any number of threads _may_ call ._stop() # simultaneously (for example, if multiple threads are blocked in # .join() calls), and they're not serialized. That's harmless - # they'll just make redundant rebindings of ._is_stopped and - # ._tstate_lock. Obscure: we rebind ._tstate_lock last so that the - # "assert self._is_stopped" in ._wait_for_tstate_lock() always works - # (the assert is executed only if ._tstate_lock is None). + # ._running_lock. Obscure: we rebind ._running_lock last so that the + # "assert self._is_stopped" in ._wait_for_running_lock() always works + # (the assert is executed only if ._running_lock is None). # - # Special case: _main_thread releases ._tstate_lock via this + # Special case: _main_thread releases ._running_lock via this # module's _shutdown() function. - lock = self._tstate_lock + lock = self._running_lock if lock is not None: assert not lock.locked() self._is_stopped = True - self._tstate_lock = None + self._running_lock = None if not self.daemon: with _shutdown_locks_lock: # Remove our lock and other released locks from _shutdown_locks @@ -1123,20 +1137,17 @@ def join(self, timeout=None): raise RuntimeError("cannot join current thread") if timeout is None: - self._wait_for_tstate_lock() + self._wait_for_running_lock() else: # the behavior of a negative timeout isn't documented, but # historically .join(timeout=x) for x<0 has acted as if timeout=0 - self._wait_for_tstate_lock(timeout=max(timeout, 0)) - - def _wait_for_tstate_lock(self, block=True, timeout=-1): - # Issue #18808: wait for the thread state to be gone. - # At the end of the thread's life, after all knowledge of the thread - # is removed from C data structures, C code releases our _tstate_lock. - # This method passes its arguments to _tstate_lock.acquire(). - # If the lock is acquired, the C code is done, and self._stop() is - # called. That sets ._is_stopped to True, and ._tstate_lock to None. - lock = self._tstate_lock + self._wait_for_running_lock(timeout=max(timeout, 0)) + + def _wait_for_running_lock(self, block=True, timeout=-1): + # This method passes its arguments to _running_lock.acquire(). + # If the lock is acquired, the python code is done, and self._stop() is + # called. That sets ._is_stopped to True, and ._running_lock to None. + lock = self._running_lock if lock is None: # already determined that the C code is done assert self._is_stopped @@ -1207,7 +1218,7 @@ def is_alive(self): assert self._initialized, "Thread.__init__() not called" if self._is_stopped or not self._started.is_set(): return False - self._wait_for_tstate_lock(False) + self._wait_for_running_lock(False) return not self._is_stopped @property @@ -1417,7 +1428,7 @@ class _MainThread(Thread): def __init__(self): Thread.__init__(self, name="MainThread", daemon=False) - self._set_tstate_lock() + self._set_running_lock() self._started.set() self._set_ident() if _HAVE_THREAD_NATIVE_ID: @@ -1558,7 +1569,7 @@ def _shutdown(): # dubious, but some code does it. We can't wait for C code to release # the main thread's tstate_lock - that won't happen until the interpreter # is nearly dead. So we release it here. Note that just calling _stop() - # isn't enough: other threads may already be waiting on _tstate_lock. + # isn't enough: other threads may already be waiting on _running_lock. if _main_thread._is_stopped: # _shutdown() was already called return @@ -1573,12 +1584,13 @@ def _shutdown(): # Main thread if _main_thread.ident == get_ident(): - tlock = _main_thread._tstate_lock - # The main thread isn't finished yet, so its thread state lock can't + assert _main_thread._tstate_lock is None + running_lock = _main_thread._running_lock + # The main thread isn't finished yet, so its running lock can't # have been released. - assert tlock is not None - assert tlock.locked() - tlock.release() + assert running_lock is not None + assert running_lock.locked() + running_lock.release() _main_thread._stop() else: # bpo-1596321: _shutdown() must be called in the main thread. From webhook-mailer at python.org Tue May 23 16:44:48 2023 From: webhook-mailer at python.org (ethanfurman) Date: Tue, 23 May 2023 20:44:48 -0000 Subject: [Python-checkins] gh-102120: [TarFile] Add an iter function that doesn't cache (GH-102128) Message-ID: <mailman.26.1684874689.17421.python-checkins@python.org> https://github.com/python/cpython/commit/50fce89d123b25e53fa8a0303a169e8887154a0e commit: 50fce89d123b25e53fa8a0303a169e8887154a0e branch: main author: Robert O'Shea <PurityLake at users.noreply.github.com> committer: ethanfurman <ethan at stoneleaf.us> date: 2023-05-23T13:44:40-07:00 summary: gh-102120: [TarFile] Add an iter function that doesn't cache (GH-102128) files: A Misc/NEWS.d/next/Library/2023-03-08-19-30-53.gh-issue-102120.xkQ5Wr.rst M Doc/library/tarfile.rst M Lib/tarfile.py M Lib/test/test_tarfile.py diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 891af1bcf7ed..2f330f018a48 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -318,7 +318,7 @@ be finalized; only the internally used file object will be closed. See the .. versionadded:: 3.2 Added support for the context management protocol. -.. class:: TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=ENCODING, errors='surrogateescape', pax_headers=None, debug=0, errorlevel=1) +.. class:: TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=ENCODING, errors='surrogateescape', pax_headers=None, debug=0, errorlevel=1, stream=False) All following arguments are optional and can be accessed as instance attributes as well. @@ -369,6 +369,9 @@ be finalized; only the internally used file object will be closed. See the The *pax_headers* argument is an optional dictionary of strings which will be added as a pax global header if *format* is :const:`PAX_FORMAT`. + If *stream* is set to :const:`True` then while reading the archive info about files + in the archive are not cached, saving memory. + .. versionchanged:: 3.2 Use ``'surrogateescape'`` as the default for the *errors* argument. @@ -378,6 +381,8 @@ be finalized; only the internally used file object will be closed. See the .. versionchanged:: 3.6 The *name* parameter accepts a :term:`path-like object`. + .. versionchanged:: 3.13 + Add the *stream* parameter. .. classmethod:: TarFile.open(...) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 7781a430839e..df4e41f7a0d2 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -1633,7 +1633,7 @@ class TarFile(object): def __init__(self, name=None, mode="r", fileobj=None, format=None, tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, errors="surrogateescape", pax_headers=None, debug=None, - errorlevel=None, copybufsize=None): + errorlevel=None, copybufsize=None, stream=False): """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to read from an existing archive, 'a' to append data to an existing file or 'w' to create a new file overwriting an existing one. `mode' @@ -1665,6 +1665,8 @@ def __init__(self, name=None, mode="r", fileobj=None, format=None, self.name = os.path.abspath(name) if name else None self.fileobj = fileobj + self.stream = stream + # Init attributes. if format is not None: self.format = format @@ -2631,7 +2633,9 @@ def next(self): break if tarinfo is not None: - self.members.append(tarinfo) + # if streaming the file we do not want to cache the tarinfo + if not self.stream: + self.members.append(tarinfo) else: self._loaded = True @@ -2682,11 +2686,12 @@ def _getmember(self, name, tarinfo=None, normalize=False): def _load(self): """Read through the entire archive file and look for readable - members. + members. This should not run if the file is set to stream. """ - while self.next() is not None: - pass - self._loaded = True + if not self.stream: + while self.next() is not None: + pass + self._loaded = True def _check(self, mode=None): """Check if TarFile is still open, and if the operation's mode diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index e8d322d20a5a..2eda7fc4ceac 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -100,6 +100,14 @@ def setUp(self): def tearDown(self): self.tar.close() +class StreamModeTest(ReadTest): + + # Only needs to change how the tarfile is opened to set + # stream mode + def setUp(self): + self.tar = tarfile.open(self.tarname, mode=self.mode, + encoding="iso8859-1", + stream=True) class UstarReadTest(ReadTest, unittest.TestCase): @@ -852,6 +860,21 @@ class Bz2StreamReadTest(Bz2Test, StreamReadTest): class LzmaStreamReadTest(LzmaTest, StreamReadTest): pass +class TarStreamModeReadTest(StreamModeTest, unittest.TestCase): + + def test_stream_mode_no_cache(self): + for _ in self.tar: + pass + self.assertEqual(self.tar.members, []) + +class GzipStreamModeReadTest(GzipTest, TarStreamModeReadTest): + pass + +class Bz2StreamModeReadTest(Bz2Test, TarStreamModeReadTest): + pass + +class LzmaStreamModeReadTest(LzmaTest, TarStreamModeReadTest): + pass class DetectReadTest(TarTest, unittest.TestCase): def _testfunc_file(self, name, mode): diff --git a/Misc/NEWS.d/next/Library/2023-03-08-19-30-53.gh-issue-102120.xkQ5Wr.rst b/Misc/NEWS.d/next/Library/2023-03-08-19-30-53.gh-issue-102120.xkQ5Wr.rst new file mode 100644 index 000000000000..ca50242fdbe2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-08-19-30-53.gh-issue-102120.xkQ5Wr.rst @@ -0,0 +1,2 @@ +Added a stream mode to ``tarfile`` that allows for reading +archives without caching info about the inner files. From webhook-mailer at python.org Tue May 23 16:52:03 2023 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 23 May 2023 20:52:03 -0000 Subject: [Python-checkins] gh-104770: Let generator.close() return value (#104771) Message-ID: <mailman.27.1684875124.17421.python-checkins@python.org> https://github.com/python/cpython/commit/d56c933992c86986bd58eb3880aed0ed1b0cadc9 commit: d56c933992c86986bd58eb3880aed0ed1b0cadc9 branch: main author: Nicolas Tessore <n.tessore at ucl.ac.uk> committer: gvanrossum <gvanrossum at gmail.com> date: 2023-05-23T13:51:56-07:00 summary: gh-104770: Let generator.close() return value (#104771) Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> files: A Misc/NEWS.d/next/Core and Builtins/2023-05-23-00-36-02.gh-issue-104770.poSkyY.rst M Doc/reference/expressions.rst M Lib/test/test_generators.py M Objects/genobject.c diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index b97a08f25d92..0c700f908d68 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -595,12 +595,19 @@ is already executing raises a :exc:`ValueError` exception. .. method:: generator.close() Raises a :exc:`GeneratorExit` at the point where the generator function was - paused. If the generator function then exits gracefully, is already closed, - or raises :exc:`GeneratorExit` (by not catching the exception), close - returns to its caller. If the generator yields a value, a - :exc:`RuntimeError` is raised. If the generator raises any other exception, - it is propagated to the caller. :meth:`close` does nothing if the generator - has already exited due to an exception or normal exit. + paused. If the generator function catches the exception and returns a + value, this value is returned from :meth:`close`. If the generator function + is already closed, or raises :exc:`GeneratorExit` (by not catching the + exception), :meth:`close` returns :const:`None`. If the generator yields a + value, a :exc:`RuntimeError` is raised. If the generator raises any other + exception, it is propagated to the caller. If the generator has already + exited due to an exception or normal exit, :meth:`close` returns + :const:`None` and has no other effect. + + .. versionchanged:: 3.13 + + If a generator returns a value upon being closed, the value is returned + by :meth:`close`. .. index:: single: yield; examples diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 31680b5a92e0..a8a344ab8de4 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -451,6 +451,88 @@ def g(): self.assertEqual(cm.exception.value.value, 2) +class GeneratorCloseTest(unittest.TestCase): + + def test_close_no_return_value(self): + def f(): + yield + + gen = f() + gen.send(None) + self.assertIsNone(gen.close()) + + def test_close_return_value(self): + def f(): + try: + yield + # close() raises GeneratorExit here, which is caught + except GeneratorExit: + return 0 + + gen = f() + gen.send(None) + self.assertEqual(gen.close(), 0) + + def test_close_not_catching_exit(self): + def f(): + yield + # close() raises GeneratorExit here, which isn't caught and + # therefore propagates -- no return value + return 0 + + gen = f() + gen.send(None) + self.assertIsNone(gen.close()) + + def test_close_not_started(self): + def f(): + try: + yield + except GeneratorExit: + return 0 + + gen = f() + self.assertIsNone(gen.close()) + + def test_close_exhausted(self): + def f(): + try: + yield + except GeneratorExit: + return 0 + + gen = f() + next(gen) + with self.assertRaises(StopIteration): + next(gen) + self.assertIsNone(gen.close()) + + def test_close_closed(self): + def f(): + try: + yield + except GeneratorExit: + return 0 + + gen = f() + gen.send(None) + self.assertEqual(gen.close(), 0) + self.assertIsNone(gen.close()) + + def test_close_raises(self): + def f(): + try: + yield + except GeneratorExit: + pass + raise RuntimeError + + gen = f() + gen.send(None) + with self.assertRaises(RuntimeError): + gen.close() + + class GeneratorThrowTest(unittest.TestCase): def test_exception_context_with_yield(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-23-00-36-02.gh-issue-104770.poSkyY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-23-00-36-02.gh-issue-104770.poSkyY.rst new file mode 100644 index 000000000000..2103fb7d61c2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-23-00-36-02.gh-issue-104770.poSkyY.rst @@ -0,0 +1,2 @@ +If a generator returns a value upon being closed, the value is now returned +by :meth:`generator.close`. diff --git a/Objects/genobject.c b/Objects/genobject.c index 9252c6549345..1abfc83ab678 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -408,11 +408,16 @@ gen_close(PyGenObject *gen, PyObject *args) PyErr_SetString(PyExc_RuntimeError, msg); return NULL; } - if (PyErr_ExceptionMatches(PyExc_StopIteration) - || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { - PyErr_Clear(); /* ignore these errors */ + assert(PyErr_Occurred()); + if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) { + PyErr_Clear(); /* ignore this error */ Py_RETURN_NONE; } + /* if the generator returned a value while closing, StopIteration was + * raised in gen_send_ex() above; retrieve and return the value here */ + if (_PyGen_FetchStopIterationValue(&retval) == 0) { + return retval; + } return NULL; } From webhook-mailer at python.org Tue May 23 18:04:52 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 23 May 2023 22:04:52 -0000 Subject: [Python-checkins] gh-103295: fix stack overwrite on 32-bit in perf map test harness (#104811) Message-ID: <mailman.28.1684879494.17421.python-checkins@python.org> https://github.com/python/cpython/commit/e0b3078705b271ff278dfbc788c2b061c92a9aa3 commit: e0b3078705b271ff278dfbc788c2b061c92a9aa3 branch: main author: Carl Meyer <carl at oddbird.net> committer: carljm <carl at oddbird.net> date: 2023-05-23T16:04:31-06:00 summary: gh-103295: fix stack overwrite on 32-bit in perf map test harness (#104811) files: M Modules/_testinternalcapi.c diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b91f7b620fdb..8267dbf67790 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -762,19 +762,24 @@ clear_extension(PyObject *self, PyObject *args) static PyObject * write_perf_map_entry(PyObject *self, PyObject *args) { + PyObject *code_addr_v; const void *code_addr; unsigned int code_size; const char *entry_name; - if (!PyArg_ParseTuple(args, "KIs", &code_addr, &code_size, &entry_name)) + if (!PyArg_ParseTuple(args, "OIs", &code_addr_v, &code_size, &entry_name)) return NULL; + code_addr = PyLong_AsVoidPtr(code_addr_v); + if (code_addr == NULL) { + return NULL; + } int ret = PyUnstable_WritePerfMapEntry(code_addr, code_size, entry_name); - if (ret == -1) { - PyErr_SetString(PyExc_OSError, "Failed to write performance map entry"); + if (ret < 0) { + PyErr_SetFromErrno(PyExc_OSError); return NULL; } - return Py_BuildValue("i", ret); + return PyLong_FromLong(ret); } static PyObject * From webhook-mailer at python.org Tue May 23 18:32:06 2023 From: webhook-mailer at python.org (barneygale) Date: Tue, 23 May 2023 22:32:06 -0000 Subject: [Python-checkins] GH-83863: Drop support for using `pathlib.Path` objects as context managers (GH-104807) Message-ID: <mailman.29.1684881127.17421.python-checkins@python.org> https://github.com/python/cpython/commit/6b1510cf11c16c8e4381810c15ceeda6f89e79f4 commit: 6b1510cf11c16c8e4381810c15ceeda6f89e79f4 branch: main author: Barney Gale <barney.gale at gmail.com> committer: barneygale <barney.gale at gmail.com> date: 2023-05-23T22:31:59Z summary: GH-83863: Drop support for using `pathlib.Path` objects as context managers (GH-104807) In Python 3.8 and prior, `pathlib.Path.__exit__()` marked a path as closed; some subsequent attempts to perform I/O would raise an IOError. This functionality was never documented, and had the effect of making `Path` objects mutable, contrary to PEP 428. In Python 3.9 we made `__exit__()` a no-op, and in 3.11 `__enter__()` began raising deprecation warnings. Here we remove both methods. files: A Misc/NEWS.d/next/Library/2023-05-23-19-53-18.gh-issue-83863.eRI5JG.rst M Doc/whatsnew/3.13.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index e0c3c2a3592e..309f26ea27db 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -115,6 +115,9 @@ Removed are now removed. The items in those namespaces can be imported directly from :mod:`typing`. (Contributed by Sebastian Rittau in :gh:`92871`.) +* Remove support for using :class:`pathlib.Path` objects as context managers. + This functionality was deprecated and made a no-op in Python 3.9. + Porting to Python 3.13 ====================== diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 3d68c161603d..3a7a1241ba77 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1080,25 +1080,6 @@ def __new__(cls, *args, **kwargs): cls = WindowsPath if os.name == 'nt' else PosixPath return object.__new__(cls) - def __enter__(self): - # In previous versions of pathlib, __exit__() marked this path as - # closed; subsequent attempts to perform I/O would raise an IOError. - # This functionality was never documented, and had the effect of - # making Path objects mutable, contrary to PEP 428. - # In Python 3.9 __exit__() was made a no-op. - # In Python 3.11 __enter__() began emitting DeprecationWarning. - # In Python 3.13 __enter__() and __exit__() should be removed. - warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled " - "for removal in Python 3.13; Path objects as a context " - "manager is a no-op", - DeprecationWarning, stacklevel=2) - return self - - def __exit__(self, t, v, tb): - pass - - # Public API - @classmethod def cwd(cls): """Return a new path pointing to the current working directory.""" diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index ab2c2b232a04..8b68cdc9b7d0 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2080,26 +2080,6 @@ def test_resolve_nonexist_relative_issue38671(self): finally: os.chdir(old_cwd) - def test_with(self): - p = self.cls(BASE) - it = p.iterdir() - it2 = p.iterdir() - next(it2) - # bpo-46556: path context managers are deprecated in Python 3.11. - with self.assertWarns(DeprecationWarning): - with p: - pass - # Using a path as a context manager is a no-op, thus the following - # operations should still succeed after the context manage exits. - next(it) - next(it2) - p.exists() - p.resolve() - p.absolute() - with self.assertWarns(DeprecationWarning): - with p: - pass - @os_helper.skip_unless_working_chmod def test_chmod(self): p = self.cls(BASE) / 'fileA' diff --git a/Misc/NEWS.d/next/Library/2023-05-23-19-53-18.gh-issue-83863.eRI5JG.rst b/Misc/NEWS.d/next/Library/2023-05-23-19-53-18.gh-issue-83863.eRI5JG.rst new file mode 100644 index 000000000000..7a073aa37dd6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-19-53-18.gh-issue-83863.eRI5JG.rst @@ -0,0 +1,4 @@ +Support for using :class:`pathlib.Path` objects as context managers has been +removed. Before Python 3.9, exiting the context manager marked a path as +"closed", which caused some (but not all!) methods to raise when called. +Since Python 3.9, using a path as a context manager does nothing. From webhook-mailer at python.org Tue May 23 18:34:57 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 23 May 2023 22:34:57 -0000 Subject: [Python-checkins] [3.12] gh-103295: fix stack overwrite on 32-bit in perf map test harness (GH-104811) (#104823) Message-ID: <mailman.30.1684881299.17421.python-checkins@python.org> https://github.com/python/cpython/commit/22c45c49bbdc480ce221fc11ddf488b41c0d9c60 commit: 22c45c49bbdc480ce221fc11ddf488b41c0d9c60 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm <carl at oddbird.net> date: 2023-05-23T22:34:50Z summary: [3.12] gh-103295: fix stack overwrite on 32-bit in perf map test harness (GH-104811) (#104823) gh-103295: fix stack overwrite on 32-bit in perf map test harness (GH-104811) (cherry picked from commit e0b3078705b271ff278dfbc788c2b061c92a9aa3) Co-authored-by: Carl Meyer <carl at oddbird.net> files: M Modules/_testinternalcapi.c diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b91f7b620fdb..8267dbf67790 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -762,19 +762,24 @@ clear_extension(PyObject *self, PyObject *args) static PyObject * write_perf_map_entry(PyObject *self, PyObject *args) { + PyObject *code_addr_v; const void *code_addr; unsigned int code_size; const char *entry_name; - if (!PyArg_ParseTuple(args, "KIs", &code_addr, &code_size, &entry_name)) + if (!PyArg_ParseTuple(args, "OIs", &code_addr_v, &code_size, &entry_name)) return NULL; + code_addr = PyLong_AsVoidPtr(code_addr_v); + if (code_addr == NULL) { + return NULL; + } int ret = PyUnstable_WritePerfMapEntry(code_addr, code_size, entry_name); - if (ret == -1) { - PyErr_SetString(PyExc_OSError, "Failed to write performance map entry"); + if (ret < 0) { + PyErr_SetFromErrno(PyExc_OSError); return NULL; } - return Py_BuildValue("i", ret); + return PyLong_FromLong(ret); } static PyObject * From webhook-mailer at python.org Tue May 23 19:10:41 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 23 May 2023 23:10:41 -0000 Subject: [Python-checkins] gh-85934: Use getattr_static when adding mock spec (#22209) Message-ID: <mailman.31.1684883443.17421.python-checkins@python.org> https://github.com/python/cpython/commit/2e0931046dcc200fd6abb2cdfaf57d8b99117c57 commit: 2e0931046dcc200fd6abb2cdfaf57d8b99117c57 branch: main author: melanie witt <melwittt at gmail.com> committer: carljm <carl at oddbird.net> date: 2023-05-23T17:10:34-06:00 summary: gh-85934: Use getattr_static when adding mock spec (#22209) Co-authored-by: Terry Jan Reedy <tjreedy at udel.edu> Co-authored-by: Oleg Iarygin <oleg at arhadthedev.net> files: A Misc/NEWS.d/next/Library/2020-09-16-16-53-06.bpo-41768.8_fWkC.rst M Lib/test/test_unittest/testmock/testmock.py M Lib/unittest/mock.py diff --git a/Lib/test/test_unittest/testmock/testmock.py b/Lib/test/test_unittest/testmock/testmock.py index d1cae47a40ee..c7895e73ad9a 100644 --- a/Lib/test/test_unittest/testmock/testmock.py +++ b/Lib/test/test_unittest/testmock/testmock.py @@ -38,6 +38,17 @@ def cmeth(cls, a, b, c, d=None): pass def smeth(a, b, c, d=None): pass +class SomethingElse(object): + def __init__(self): + self._instance = None + + @property + def instance(self): + if not self._instance: + self._instance = 'object' + return self._instance + + class Typos(): autospect = None auto_spec = None @@ -2293,6 +2304,26 @@ class Foo(): f'{__name__}.Typos', autospect=True, set_spec=True, auto_spec=True): pass + def test_property_not_called_with_spec_mock(self): + obj = SomethingElse() + self.assertIsNone(obj._instance, msg='before mock') + mock = Mock(spec=obj) + self.assertIsNone(obj._instance, msg='after mock') + self.assertEqual('object', obj.instance) + + def test_decorated_async_methods_with_spec_mock(self): + class Foo(): + @classmethod + async def class_method(cls): + pass + @staticmethod + async def static_method(): + pass + async def method(self): + pass + mock = Mock(spec=Foo) + for m in (mock.method, mock.class_method, mock.static_method): + self.assertIsInstance(m, AsyncMock) if __name__ == '__main__': unittest.main() diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 7ca085760650..22f81e55b567 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -526,7 +526,13 @@ def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False, spec_list = dir(spec) for attr in spec_list: - if iscoroutinefunction(getattr(spec, attr, None)): + static_attr = inspect.getattr_static(spec, attr, None) + unwrapped_attr = static_attr + try: + unwrapped_attr = inspect.unwrap(unwrapped_attr) + except ValueError: + pass + if iscoroutinefunction(unwrapped_attr): _spec_asyncs.append(attr) spec = spec_list diff --git a/Misc/NEWS.d/next/Library/2020-09-16-16-53-06.bpo-41768.8_fWkC.rst b/Misc/NEWS.d/next/Library/2020-09-16-16-53-06.bpo-41768.8_fWkC.rst new file mode 100644 index 000000000000..bfd3a294d44e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-09-16-16-53-06.bpo-41768.8_fWkC.rst @@ -0,0 +1,2 @@ +:mod:`unittest.mock` speccing no longer calls class properties. +Patch by Melanie Witt. From webhook-mailer at python.org Tue May 23 23:43:02 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 24 May 2023 03:43:02 -0000 Subject: [Python-checkins] [3.11] gh-104372: Cleanup _posixsubprocess make_inheritable for async signal safety gh-104518 (#104785) Message-ID: <mailman.32.1684899783.17421.python-checkins@python.org> https://github.com/python/cpython/commit/6d00ae3c28b254feeb3c1a81e38db92109180c47 commit: 6d00ae3c28b254feeb3c1a81e38db92109180c47 branch: 3.11 author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-23T20:42:25-07:00 summary: [3.11] gh-104372: Cleanup _posixsubprocess make_inheritable for async signal safety gh-104518 (#104785) Move all of the Python C API calls into the parent process up front instead of doing PyLong_AsLong and PyErr_Occurred and PyTuple_GET from the post-fork/vfork child process. Much of this was long overdue. We shouldn't have been using PyTuple and PyLong APIs within all of these low level functions anyways. This is a backport of c649df6 for #104518 and the tiny adjustment in d1732fe #104697. Backporting this allows backporting of the real bug fix that requires it. Co-authored-by: Gregory P. Smith [Google] <greg at krypto.org> files: A Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst M Modules/_posixsubprocess.c diff --git a/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst b/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst new file mode 100644 index 000000000000..c228f503aab4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-17-08-01-36.gh-issue-104372.jpoWs6.rst @@ -0,0 +1 @@ +Refactored the ``_posixsubprocess`` internals to avoid Python C API usage between fork and exec when marking ``pass_fds=`` file descriptors inheritable. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 9132f13e8166..ad9daaede430 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -138,16 +138,17 @@ _sanity_check_python_fd_sequence(PyObject *fd_sequence) /* Is fd found in the sorted Python Sequence? */ static int -_is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence) +_is_fd_in_sorted_fd_sequence(int fd, int *fd_sequence, + Py_ssize_t fd_sequence_len) { /* Binary search. */ Py_ssize_t search_min = 0; - Py_ssize_t search_max = PyTuple_GET_SIZE(fd_sequence) - 1; + Py_ssize_t search_max = fd_sequence_len - 1; if (search_max < 0) return 0; do { long middle = (search_min + search_max) / 2; - long middle_fd = PyLong_AsLong(PyTuple_GET_ITEM(fd_sequence, middle)); + long middle_fd = fd_sequence[middle]; if (fd == middle_fd) return 1; if (fd > middle_fd) @@ -158,8 +159,18 @@ _is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence) return 0; } +/* + * Do all the Python C API calls in the parent process to turn the pass_fds + * "py_fds_to_keep" tuple into a C array. The caller owns allocation and + * freeing of the array. + * + * On error an unknown number of array elements may have been filled in. + * A Python exception has been set when an error is returned. + * + * Returns: -1 on error, 0 on success. + */ static int -make_inheritable(PyObject *py_fds_to_keep, int errpipe_write) +convert_fds_to_keep_to_c(PyObject *py_fds_to_keep, int *c_fds_to_keep) { Py_ssize_t i, len; @@ -167,15 +178,37 @@ make_inheritable(PyObject *py_fds_to_keep, int errpipe_write) for (i = 0; i < len; ++i) { PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i); long fd = PyLong_AsLong(fdobj); - assert(!PyErr_Occurred()); - assert(0 <= fd && fd <= INT_MAX); + if (fd == -1 && PyErr_Occurred()) { + return -1; + } + if (fd < 0 || fd > INT_MAX) { + PyErr_SetString(PyExc_ValueError, + "fd out of range in fds_to_keep."); + return -1; + } + c_fds_to_keep[i] = (int)fd; + } + return 0; +} + + +/* This function must be async-signal-safe as it is called from child_exec() + * after fork() or vfork(). + */ +static int +make_inheritable(int *c_fds_to_keep, Py_ssize_t len, int errpipe_write) +{ + Py_ssize_t i; + + for (i = 0; i < len; ++i) { + int fd = c_fds_to_keep[i]; if (fd == errpipe_write) { - /* errpipe_write is part of py_fds_to_keep. It must be closed at + /* errpipe_write is part of fds_to_keep. It must be closed at exec(), but kept open in the child process until exec() is called. */ continue; } - if (_Py_set_inheritable_async_safe((int)fd, 1, NULL) < 0) + if (_Py_set_inheritable_async_safe(fd, 1, NULL) < 0) return -1; } return 0; @@ -211,7 +244,7 @@ safe_get_max_fd(void) /* Close all file descriptors in the given range except for those in - * py_fds_to_keep by invoking closer on each subrange. + * fds_to_keep by invoking closer on each subrange. * * If end_fd == -1, it's guessed via safe_get_max_fd(), but it isn't * possible to know for sure what the max fd to go up to is for @@ -221,19 +254,18 @@ safe_get_max_fd(void) static int _close_range_except(int start_fd, int end_fd, - PyObject *py_fds_to_keep, + int *fds_to_keep, + Py_ssize_t fds_to_keep_len, int (*closer)(int, int)) { if (end_fd == -1) { end_fd = Py_MIN(safe_get_max_fd(), INT_MAX); } - Py_ssize_t num_fds_to_keep = PyTuple_GET_SIZE(py_fds_to_keep); Py_ssize_t keep_seq_idx; - /* As py_fds_to_keep is sorted we can loop through the list closing + /* As fds_to_keep is sorted we can loop through the list closing * fds in between any in the keep list falling within our range. */ - for (keep_seq_idx = 0; keep_seq_idx < num_fds_to_keep; ++keep_seq_idx) { - PyObject* py_keep_fd = PyTuple_GET_ITEM(py_fds_to_keep, keep_seq_idx); - int keep_fd = PyLong_AsLong(py_keep_fd); + for (keep_seq_idx = 0; keep_seq_idx < fds_to_keep_len; ++keep_seq_idx) { + int keep_fd = fds_to_keep[keep_seq_idx]; if (keep_fd < start_fd) continue; if (closer(start_fd, keep_fd - 1) != 0) @@ -273,7 +305,7 @@ _brute_force_closer(int first, int last) } /* Close all open file descriptors in the range from start_fd and higher - * Do not close any in the sorted py_fds_to_keep list. + * Do not close any in the sorted fds_to_keep list. * * This version is async signal safe as it does not make any unsafe C library * calls, malloc calls or handle any locks. It is _unfortunate_ to be forced @@ -288,14 +320,16 @@ _brute_force_closer(int first, int last) * it with some cpp #define magic to work on other OSes as well if you want. */ static void -_close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep) +_close_open_fds_safe(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len) { int fd_dir_fd; fd_dir_fd = _Py_open_noraise(FD_DIR, O_RDONLY); if (fd_dir_fd == -1) { /* No way to get a list of open fds. */ - _close_range_except(start_fd, -1, py_fds_to_keep, _brute_force_closer); + _close_range_except(start_fd, -1, + fds_to_keep, fds_to_keep_len, + _brute_force_closer); return; } else { char buffer[sizeof(struct linux_dirent64)]; @@ -314,7 +348,8 @@ _close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep) if ((fd = _pos_int_from_ascii(entry->d_name)) < 0) continue; /* Not a number. */ if (fd != fd_dir_fd && fd >= start_fd && - !_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) { + !_is_fd_in_sorted_fd_sequence(fd, fds_to_keep, + fds_to_keep_len)) { close(fd); } } @@ -335,7 +370,7 @@ _unsafe_closer(int first, int last) } /* Close all open file descriptors from start_fd and higher. - * Do not close any in the sorted py_fds_to_keep tuple. + * Do not close any in the sorted fds_to_keep tuple. * * This function violates the strict use of async signal safe functions. :( * It calls opendir(), readdir() and closedir(). Of these, the one most @@ -348,11 +383,13 @@ _unsafe_closer(int first, int last) * http://womble.decadent.org.uk/readdir_r-advisory.html */ static void -_close_open_fds_maybe_unsafe(int start_fd, PyObject* py_fds_to_keep) +_close_open_fds_maybe_unsafe(int start_fd, int *fds_to_keep, + Py_ssize_t fds_to_keep_len) { DIR *proc_fd_dir; #ifndef HAVE_DIRFD - while (_is_fd_in_sorted_fd_sequence(start_fd, py_fds_to_keep)) { + while (_is_fd_in_sorted_fd_sequence(start_fd, fds_to_keep, + fds_to_keep_len)) { ++start_fd; } /* Close our lowest fd before we call opendir so that it is likely to @@ -371,7 +408,8 @@ _close_open_fds_maybe_unsafe(int start_fd, PyObject* py_fds_to_keep) proc_fd_dir = opendir(FD_DIR); if (!proc_fd_dir) { /* No way to get a list of open fds. */ - _close_range_except(start_fd, -1, py_fds_to_keep, _unsafe_closer); + _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len, + _unsafe_closer); } else { struct dirent *dir_entry; #ifdef HAVE_DIRFD @@ -385,14 +423,16 @@ _close_open_fds_maybe_unsafe(int start_fd, PyObject* py_fds_to_keep) if ((fd = _pos_int_from_ascii(dir_entry->d_name)) < 0) continue; /* Not a number. */ if (fd != fd_used_by_opendir && fd >= start_fd && - !_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) { + !_is_fd_in_sorted_fd_sequence(fd, fds_to_keep, + fds_to_keep_len)) { close(fd); } errno = 0; } if (errno) { /* readdir error, revert behavior. Highly Unlikely. */ - _close_range_except(start_fd, -1, py_fds_to_keep, _unsafe_closer); + _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len, + _unsafe_closer); } closedir(proc_fd_dir); } @@ -420,16 +460,16 @@ _close_range_closer(int first, int last) #endif static void -_close_open_fds(int start_fd, PyObject* py_fds_to_keep) +_close_open_fds(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len) { #ifdef HAVE_ASYNC_SAFE_CLOSE_RANGE if (_close_range_except( - start_fd, INT_MAX, py_fds_to_keep, + start_fd, INT_MAX, fds_to_keep, fds_to_keep_len, _close_range_closer) == 0) { return; } #endif - _close_open_fds_fallback(start_fd, py_fds_to_keep); + _close_open_fds_fallback(start_fd, fds_to_keep, fds_to_keep_len); } #ifdef VFORK_USABLE @@ -522,7 +562,7 @@ child_exec(char *const exec_array[], int call_setgroups, size_t groups_size, const gid_t *groups, int call_setuid, uid_t uid, int child_umask, const void *child_sigmask, - PyObject *py_fds_to_keep, + int *fds_to_keep, Py_ssize_t fds_to_keep_len, PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { @@ -532,7 +572,7 @@ child_exec(char *const exec_array[], /* Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1]; - if (make_inheritable(py_fds_to_keep, errpipe_write) < 0) + if (make_inheritable(fds_to_keep, fds_to_keep_len, errpipe_write) < 0) goto error; /* Close parent's pipe ends. */ @@ -652,7 +692,7 @@ child_exec(char *const exec_array[], /* close FDs after executing preexec_fn, which might open FDs */ if (close_fds) { /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */ - _close_open_fds(3, py_fds_to_keep); + _close_open_fds(3, fds_to_keep, fds_to_keep_len); } /* This loop matches the Lib/os.py _execvpe()'s PATH search when */ @@ -726,7 +766,7 @@ do_fork_exec(char *const exec_array[], int call_setgroups, size_t groups_size, const gid_t *groups, int call_setuid, uid_t uid, int child_umask, const void *child_sigmask, - PyObject *py_fds_to_keep, + int *fds_to_keep, Py_ssize_t fds_to_keep_len, PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { @@ -777,7 +817,8 @@ do_fork_exec(char *const exec_array[], close_fds, restore_signals, call_setsid, pgid_to_set, call_setgid, gid, call_setgroups, groups_size, groups, call_setuid, uid, child_umask, child_sigmask, - py_fds_to_keep, preexec_fn, preexec_fn_args_tuple); + fds_to_keep, fds_to_keep_len, + preexec_fn, preexec_fn_args_tuple); _exit(255); return 0; /* Dead code to avoid a potential compiler warning. */ } @@ -810,6 +851,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args) int need_after_fork = 0; int saved_errno = 0; int allow_vfork; + int *c_fds_to_keep = NULL; if (!PyArg_ParseTuple( args, "OOpO!OOiiiiiiiiii" _Py_PARSE_PID "OOOiOp:fork_exec", @@ -983,6 +1025,16 @@ subprocess_fork_exec(PyObject *module, PyObject *args) #endif /* HAVE_SETREUID */ } + Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep); + c_fds_to_keep = PyMem_Malloc(fds_to_keep_len * sizeof(int)); + if (c_fds_to_keep == NULL) { + PyErr_SetString(PyExc_MemoryError, "failed to malloc c_fds_to_keep"); + goto cleanup; + } + if (convert_fds_to_keep_to_c(py_fds_to_keep, c_fds_to_keep) < 0) { + goto cleanup; + } + /* This must be the last thing done before fork() because we do not * want to call PyOS_BeforeFork() if there is any chance of another * error leading to the cleanup: code without calling fork(). */ @@ -1025,7 +1077,8 @@ subprocess_fork_exec(PyObject *module, PyObject *args) close_fds, restore_signals, call_setsid, pgid_to_set, call_setgid, gid, call_setgroups, num_groups, groups, call_setuid, uid, child_umask, old_sigmask, - py_fds_to_keep, preexec_fn, preexec_fn_args_tuple); + c_fds_to_keep, fds_to_keep_len, + preexec_fn, preexec_fn_args_tuple); /* Parent (original) process */ if (pid == -1) { @@ -1055,6 +1108,10 @@ subprocess_fork_exec(PyObject *module, PyObject *args) PyOS_AfterFork_Parent(); cleanup: + if (c_fds_to_keep != NULL) { + PyMem_Free(c_fds_to_keep); + } + if (saved_errno != 0) { errno = saved_errno; /* We can't call this above as PyOS_AfterFork_Parent() calls back From webhook-mailer at python.org Wed May 24 00:16:23 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 24 May 2023 04:16:23 -0000 Subject: [Python-checkins] gh-104372: use == -1 before PyErr_Occurred (#104831) Message-ID: <mailman.33.1684901784.17421.python-checkins@python.org> https://github.com/python/cpython/commit/7f963bfc79a515dc9822ebddbfb1b5927d2dda09 commit: 7f963bfc79a515dc9822ebddbfb1b5927d2dda09 branch: main author: Gregory P. Smith <greg at krypto.org> committer: gpshead <greg at krypto.org> date: 2023-05-24T04:15:49Z summary: gh-104372: use == -1 before PyErr_Occurred (#104831) The ideal pattern for this. (already in the 3.11 backport) files: M Modules/_posixsubprocess.c diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 1b7fe71186a1..63403795569a 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -200,7 +200,7 @@ convert_fds_to_keep_to_c(PyObject *py_fds_to_keep, int *c_fds_to_keep) for (i = 0; i < len; ++i) { PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i); long fd = PyLong_AsLong(fdobj); - if (PyErr_Occurred()) { + if (fd == -1 && PyErr_Occurred()) { return -1; } if (fd < 0 || fd > INT_MAX) { From webhook-mailer at python.org Wed May 24 00:40:38 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 24 May 2023 04:40:38 -0000 Subject: [Python-checkins] [3.12] gh-104372: use == -1 before PyErr_Occurred (GH-104831) (#104833) Message-ID: <mailman.34.1684903240.17421.python-checkins@python.org> https://github.com/python/cpython/commit/b719dd8725a820a1af4b76c30ae87c23d8db68c0 commit: b719dd8725a820a1af4b76c30ae87c23d8db68c0 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gpshead <greg at krypto.org> date: 2023-05-24T04:40:21Z summary: [3.12] gh-104372: use == -1 before PyErr_Occurred (GH-104831) (#104833) gh-104372: use == -1 before PyErr_Occurred (GH-104831) The ideal pattern for this. (already in the 3.11 backport) (cherry picked from commit 7f963bfc79a515dc9822ebddbfb1b5927d2dda09) Co-authored-by: Gregory P. Smith <greg at krypto.org> files: M Modules/_posixsubprocess.c diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 1b7fe71186a1..63403795569a 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -200,7 +200,7 @@ convert_fds_to_keep_to_c(PyObject *py_fds_to_keep, int *c_fds_to_keep) for (i = 0; i < len; ++i) { PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i); long fd = PyLong_AsLong(fdobj); - if (PyErr_Occurred()) { + if (fd == -1 && PyErr_Occurred()) { return -1; } if (fd < 0 || fd > INT_MAX) { From webhook-mailer at python.org Wed May 24 04:01:05 2023 From: webhook-mailer at python.org (gpshead) Date: Wed, 24 May 2023 08:01:05 -0000 Subject: [Python-checkins] gh-104837: Revert "gh-104341: Add a Separate "Running" Lock for Each Thread (gh-104754) (#104838) Message-ID: <mailman.35.1684915266.17421.python-checkins@python.org> https://github.com/python/cpython/commit/4b56e56c495de58425ae3db5f4d8183127ee990b commit: 4b56e56c495de58425ae3db5f4d8183127ee990b branch: main author: Gregory P. Smith <gps at python.org> committer: gpshead <greg at krypto.org> date: 2023-05-24T01:00:57-07:00 summary: gh-104837: Revert "gh-104341: Add a Separate "Running" Lock for Each Thread (gh-104754) (#104838) gh-104837: Revert "gh-104341: Add a Separate "Running" Lock for Each Thread (gh-104754)" This reverts commit 097b7830cd67f039ff36ba4fa285d82d26e25e84. files: M Lib/test/test_threading.py M Lib/threading.py diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 648533923dcd..97165264b34b 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -747,7 +747,7 @@ def f(): rc, out, err = assert_python_ok("-c", code) self.assertEqual(err, b"") - def test_running_lock(self): + def test_tstate_lock(self): # Test an implementation detail of Thread objects. started = _thread.allocate_lock() finish = _thread.allocate_lock() @@ -757,29 +757,29 @@ def f(): started.release() finish.acquire() time.sleep(0.01) - # The running lock is None until the thread is started + # The tstate lock is None until the thread is started t = threading.Thread(target=f) - self.assertIs(t._running_lock, None) + self.assertIs(t._tstate_lock, None) t.start() started.acquire() self.assertTrue(t.is_alive()) - # The running lock can't be acquired when the thread is running + # The tstate lock can't be acquired when the thread is running # (or suspended). - running_lock = t._running_lock - self.assertFalse(running_lock.acquire(timeout=0), False) + tstate_lock = t._tstate_lock + self.assertFalse(tstate_lock.acquire(timeout=0), False) finish.release() # When the thread ends, the state_lock can be successfully # acquired. - self.assertTrue(running_lock.acquire(timeout=support.SHORT_TIMEOUT), False) - # But is_alive() is still True: we hold _running_lock now, which - # prevents is_alive() from knowing the thread's Python code + self.assertTrue(tstate_lock.acquire(timeout=support.SHORT_TIMEOUT), False) + # But is_alive() is still True: we hold _tstate_lock now, which + # prevents is_alive() from knowing the thread's end-of-life C code # is done. self.assertTrue(t.is_alive()) # Let is_alive() find out the C code is done. - running_lock.release() + tstate_lock.release() self.assertFalse(t.is_alive()) - # And verify the thread disposed of _running_lock. - self.assertIsNone(t._running_lock) + # And verify the thread disposed of _tstate_lock. + self.assertIsNone(t._tstate_lock) t.join() def test_repr_stopped(self): diff --git a/Lib/threading.py b/Lib/threading.py index 69b4f54c050a..df273870fa42 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -908,7 +908,6 @@ class is implemented. self._ident = None if _HAVE_THREAD_NATIVE_ID: self._native_id = None - self._running_lock = None self._tstate_lock = None self._started = Event() self._is_stopped = False @@ -927,9 +926,6 @@ def _reset_internal_locks(self, is_alive): # bpo-42350: If the fork happens when the thread is already stopped # (ex: after threading._shutdown() has been called), _tstate_lock # is None. Do nothing in this case. - if self._running_lock is not None: - self._running_lock._at_fork_reinit() - self._running_lock.acquire() if self._tstate_lock is not None: self._tstate_lock._at_fork_reinit() self._tstate_lock.acquire() @@ -937,7 +933,6 @@ def _reset_internal_locks(self, is_alive): # The thread isn't alive after fork: it doesn't have a tstate # anymore. self._is_stopped = True - self._running_lock = None self._tstate_lock = None def __repr__(self): @@ -1024,14 +1019,6 @@ def _set_ident(self): def _set_native_id(self): self._native_id = get_native_id() - def _set_running_lock(self): - """ - Set a lock object which will be released by the interpreter when - the target func has finished running. - """ - self._running_lock = _allocate_lock() - self._running_lock.acquire() - def _set_tstate_lock(self): """ Set a lock object which will be released by the interpreter when @@ -1048,7 +1035,6 @@ def _set_tstate_lock(self): def _bootstrap_inner(self): try: self._set_ident() - self._set_running_lock() self._set_tstate_lock() if _HAVE_THREAD_NATIVE_ID: self._set_native_id() @@ -1068,29 +1054,29 @@ def _bootstrap_inner(self): self._invoke_excepthook(self) finally: self._delete() - self._running_lock.release() def _stop(self): # After calling ._stop(), .is_alive() returns False and .join() returns - # immediately. ._running_lock must be released before calling ._stop(). + # immediately. ._tstate_lock must be released before calling ._stop(). # - # Normal case: ._bootstrap_inner() releases ._running_lock, and - # that's detected by our ._wait_for_running_lock(), called by .join() + # Normal case: C code at the end of the thread's life + # (release_sentinel in _threadmodule.c) releases ._tstate_lock, and + # that's detected by our ._wait_for_tstate_lock(), called by .join() # and .is_alive(). Any number of threads _may_ call ._stop() # simultaneously (for example, if multiple threads are blocked in # .join() calls), and they're not serialized. That's harmless - # they'll just make redundant rebindings of ._is_stopped and - # ._running_lock. Obscure: we rebind ._running_lock last so that the - # "assert self._is_stopped" in ._wait_for_running_lock() always works - # (the assert is executed only if ._running_lock is None). + # ._tstate_lock. Obscure: we rebind ._tstate_lock last so that the + # "assert self._is_stopped" in ._wait_for_tstate_lock() always works + # (the assert is executed only if ._tstate_lock is None). # - # Special case: _main_thread releases ._running_lock via this + # Special case: _main_thread releases ._tstate_lock via this # module's _shutdown() function. - lock = self._running_lock + lock = self._tstate_lock if lock is not None: assert not lock.locked() self._is_stopped = True - self._running_lock = None + self._tstate_lock = None if not self.daemon: with _shutdown_locks_lock: # Remove our lock and other released locks from _shutdown_locks @@ -1137,17 +1123,20 @@ def join(self, timeout=None): raise RuntimeError("cannot join current thread") if timeout is None: - self._wait_for_running_lock() + self._wait_for_tstate_lock() else: # the behavior of a negative timeout isn't documented, but # historically .join(timeout=x) for x<0 has acted as if timeout=0 - self._wait_for_running_lock(timeout=max(timeout, 0)) - - def _wait_for_running_lock(self, block=True, timeout=-1): - # This method passes its arguments to _running_lock.acquire(). - # If the lock is acquired, the python code is done, and self._stop() is - # called. That sets ._is_stopped to True, and ._running_lock to None. - lock = self._running_lock + self._wait_for_tstate_lock(timeout=max(timeout, 0)) + + def _wait_for_tstate_lock(self, block=True, timeout=-1): + # Issue #18808: wait for the thread state to be gone. + # At the end of the thread's life, after all knowledge of the thread + # is removed from C data structures, C code releases our _tstate_lock. + # This method passes its arguments to _tstate_lock.acquire(). + # If the lock is acquired, the C code is done, and self._stop() is + # called. That sets ._is_stopped to True, and ._tstate_lock to None. + lock = self._tstate_lock if lock is None: # already determined that the C code is done assert self._is_stopped @@ -1218,7 +1207,7 @@ def is_alive(self): assert self._initialized, "Thread.__init__() not called" if self._is_stopped or not self._started.is_set(): return False - self._wait_for_running_lock(False) + self._wait_for_tstate_lock(False) return not self._is_stopped @property @@ -1428,7 +1417,7 @@ class _MainThread(Thread): def __init__(self): Thread.__init__(self, name="MainThread", daemon=False) - self._set_running_lock() + self._set_tstate_lock() self._started.set() self._set_ident() if _HAVE_THREAD_NATIVE_ID: @@ -1569,7 +1558,7 @@ def _shutdown(): # dubious, but some code does it. We can't wait for C code to release # the main thread's tstate_lock - that won't happen until the interpreter # is nearly dead. So we release it here. Note that just calling _stop() - # isn't enough: other threads may already be waiting on _running_lock. + # isn't enough: other threads may already be waiting on _tstate_lock. if _main_thread._is_stopped: # _shutdown() was already called return @@ -1584,13 +1573,12 @@ def _shutdown(): # Main thread if _main_thread.ident == get_ident(): - assert _main_thread._tstate_lock is None - running_lock = _main_thread._running_lock - # The main thread isn't finished yet, so its running lock can't + tlock = _main_thread._tstate_lock + # The main thread isn't finished yet, so its thread state lock can't # have been released. - assert running_lock is not None - assert running_lock.locked() - running_lock.release() + assert tlock is not None + assert tlock.locked() + tlock.release() _main_thread._stop() else: # bpo-1596321: _shutdown() must be called in the main thread. From webhook-mailer at python.org Wed May 24 04:25:02 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 24 May 2023 08:25:02 -0000 Subject: [Python-checkins] gh-104797: Allow Protocols to inherit from collections.abc.Buffer (#104827) Message-ID: <mailman.36.1684916703.17421.python-checkins@python.org> https://github.com/python/cpython/commit/c0ab7d401c736c37bf4462eef7c7d69fef8fab93 commit: c0ab7d401c736c37bf4462eef7c7d69fef8fab93 branch: main author: Jelle Zijlstra <jelle.zijlstra at gmail.com> committer: AlexWaygood <Alex.Waygood at Gmail.com> date: 2023-05-24T08:24:53Z summary: gh-104797: Allow Protocols to inherit from collections.abc.Buffer (#104827) files: A Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.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 b4a5a68a2f7e..098933b7cb43 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3546,6 +3546,22 @@ def close(self): self.assertIsSubclass(B, Custom) self.assertNotIsSubclass(A, Custom) + @runtime_checkable + class ReleasableBuffer(collections.abc.Buffer, Protocol): + def __release_buffer__(self, mv: memoryview) -> None: ... + + class C: pass + class D: + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + def __release_buffer__(self, mv: memoryview) -> None: + pass + + self.assertIsSubclass(D, ReleasableBuffer) + self.assertIsInstance(D(), ReleasableBuffer) + self.assertNotIsSubclass(C, ReleasableBuffer) + self.assertNotIsInstance(C(), ReleasableBuffer) + def test_builtin_protocol_allowlist(self): with self.assertRaises(TypeError): class CustomProtocol(TestCase, Protocol): diff --git a/Lib/typing.py b/Lib/typing.py index 95dbc0b85bcd..b32ff0c6ba4e 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1740,7 +1740,7 @@ def _allow_reckless_class_checks(depth=3): _PROTO_ALLOWLIST = { 'collections.abc': [ 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], } diff --git a/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst new file mode 100644 index 000000000000..60c9a0601cdc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst @@ -0,0 +1,2 @@ +Allow :class:`typing.Protocol` classes to inherit from +:class:`collections.abc.Buffer`. Patch by Jelle Zijlstra. From webhook-mailer at python.org Wed May 24 04:29:42 2023 From: webhook-mailer at python.org (vstinner) Date: Wed, 24 May 2023 08:29:42 -0000 Subject: [Python-checkins] Fix test_importlib.test_side_effect_import() (#104840) Message-ID: <mailman.37.1684916983.17421.python-checkins@python.org> https://github.com/python/cpython/commit/426950993f6a39cdf3f6a3333ac8b518833c7e61 commit: 426950993f6a39cdf3f6a3333ac8b518833c7e61 branch: main author: Victor Stinner <vstinner at python.org> committer: vstinner <vstinner at python.org> date: 2023-05-24T10:29:35+02:00 summary: Fix test_importlib.test_side_effect_import() (#104840) Wait until the thread spawn by the import completes to avoid dangling threads. With this fix, the following command no longer fails: ./python -m test --fail-env-changed test_importlib -m test_side_effect_import -F -j20 files: M Lib/test/test_importlib/test_threaded_import.py diff --git a/Lib/test/test_importlib/test_threaded_import.py b/Lib/test/test_importlib/test_threaded_import.py index 85c3032aed53..68de4a66f3c7 100644 --- a/Lib/test/test_importlib/test_threaded_import.py +++ b/Lib/test/test_importlib/test_threaded_import.py @@ -238,7 +238,8 @@ def target(): self.addCleanup(forget, TESTFN) self.addCleanup(rmtree, '__pycache__') importlib.invalidate_caches() - __import__(TESTFN) + with threading_helper.wait_threads_exit(): + __import__(TESTFN) del sys.modules[TESTFN] def test_concurrent_futures_circular_import(self): From webhook-mailer at python.org Wed May 24 04:44:04 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 24 May 2023 08:44:04 -0000 Subject: [Python-checkins] gh-104719: IDLE - test existence of all tokenize references. (#104767) Message-ID: <mailman.38.1684917845.17421.python-checkins@python.org> https://github.com/python/cpython/commit/e561c09975bf67ad8bb67c56a81e30a9165bcc84 commit: e561c09975bf67ad8bb67c56a81e30a9165bcc84 branch: main author: Terry Jan Reedy <tjreedy at udel.edu> committer: terryjreedy <tjreedy at udel.edu> date: 2023-05-24T08:43:56Z summary: gh-104719: IDLE - test existence of all tokenize references. (#104767) Class editor.IndentSearcher contains all editor references to tokenize module. Module io tokenize reference cover those other modules. Co-authored-by: Jelle Zijlstra <jelle.zijlstra at gmail.com> files: A Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst M Lib/idlelib/NEWS.txt M Lib/idlelib/editor.py M Lib/idlelib/idle_test/test_editor.py M Lib/idlelib/idle_test/test_iomenu.py diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index 553b932aa6b6..f258797c6e0f 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -4,6 +4,9 @@ Released on 2023-10-02 ========================= +gh-104719: Remove IDLE's modification of tokenize.tabsize and test +other uses of tokenize data and methods. + gh-104499: Fix completions for Tk Aqua 8.7 (currently blank). gh-104486: Make About print both tcl and tk versions if different, diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index df36be876601..69b27d0683a1 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1571,7 +1571,7 @@ def reindent_to(self, column): # blocks are found). def guess_indent(self): - opener, indented = IndentSearcher(self.text, self.tabwidth).run() + opener, indented = IndentSearcher(self.text).run() if opener and indented: raw, indentsmall = get_line_indent(opener, self.tabwidth) raw, indentlarge = get_line_indent(indented, self.tabwidth) @@ -1609,15 +1609,10 @@ def get_line_indent(line, tabwidth): class IndentSearcher: + "Manage initial indent guess, returned by run method." - # .run() chews over the Text widget, looking for a block opener - # and the stmt following it. Returns a pair, - # (line containing block opener, line containing stmt) - # Either or both may be None. - - def __init__(self, text, tabwidth): + def __init__(self, text): self.text = text - self.tabwidth = tabwidth self.i = self.finished = 0 self.blkopenline = self.indentedline = None @@ -1633,7 +1628,8 @@ def readline(self): def tokeneater(self, type, token, start, end, line, INDENT=tokenize.INDENT, NAME=tokenize.NAME, - OPENERS=('class', 'def', 'for', 'if', 'try', 'while')): + OPENERS=('class', 'def', 'for', 'if', 'match', 'try', + 'while', 'with')): if self.finished: pass elif type == NAME and token in OPENERS: @@ -1643,6 +1639,10 @@ def tokeneater(self, type, token, start, end, line, self.finished = 1 def run(self): + """Return 2 lines containing block opener and and indent. + + Either the indent line or both may be None. + """ try: tokens = tokenize.generate_tokens(self.readline) for token in tokens: @@ -1654,6 +1654,7 @@ def run(self): ### end autoindent code ### + def prepstr(s): """Extract the underscore from a string. diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index fdb47abf43fb..9296a6d235fb 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -1,10 +1,10 @@ -"Test editor, coverage 35%." +"Test editor, coverage 53%." from idlelib import editor import unittest from collections import namedtuple from test.support import requires -from tkinter import Tk +from tkinter import Tk, Text Editor = editor.EditorWindow @@ -31,7 +31,7 @@ def test_init(self): e._close() -class TestGetLineIndent(unittest.TestCase): +class GetLineIndentTest(unittest.TestCase): def test_empty_lines(self): for tabwidth in [1, 2, 4, 6, 8]: for line in ['', '\n']: @@ -181,6 +181,36 @@ def test_indent_and_newline_event(self): eq(get('1.0', 'end'), ' def f1(self, a,\n \n return a + b\n') +class IndentSearcherTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = Tk() + cls.root.withdraw() + cls.text = Text(cls.root) + + @classmethod + def tearDownClass(cls): + cls.root.destroy() + del cls.root + + def test_searcher(self): + text = self.text + searcher = (self.text) + test_info = (# text, (block, indent)) + ("", (None, None)), + ("[1,", (None, None)), # TokenError + ("if 1:\n", ('if 1:\n', None)), + ("if 1:\n 2\n 3\n", ('if 1:\n', ' 2\n')), + ) + for code, expected_pair in test_info: + with self.subTest(code=code): + insert(text, code) + actual_pair = editor.IndentSearcher(text).run() + self.assertEqual(actual_pair, expected_pair) + + class RMenuTest(unittest.TestCase): @classmethod diff --git a/Lib/idlelib/idle_test/test_iomenu.py b/Lib/idlelib/idle_test/test_iomenu.py index 2fb836dba216..e0642cf0cabe 100644 --- a/Lib/idlelib/idle_test/test_iomenu.py +++ b/Lib/idlelib/idle_test/test_iomenu.py @@ -8,6 +8,12 @@ from idlelib import util from idlelib.idle_test.mock_idle import Func +# Fail if either tokenize.open and t.detect_encoding does not exist. +# These are used in loadfile and encode. +# Also used in pyshell.MI.execfile and runscript.tabnanny. +from tokenize import open, detect_encoding +# Remove when we have proper tests that use both. + class IOBindingTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst b/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst new file mode 100644 index 000000000000..3fbe04ba4f68 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2023-05-23-17-19-49.gh-issue-104719.rvYXH-.rst @@ -0,0 +1,2 @@ +Remove IDLE's modification of tokenize.tabsize and test other uses of +tokenize data and methods. From webhook-mailer at python.org Wed May 24 05:05:00 2023 From: webhook-mailer at python.org (vstinner) Date: Wed, 24 May 2023 09:05:00 -0000 Subject: [Python-checkins] gh-104773: PEP 594: Remove cgi and cgitb modules (#104775) Message-ID: <mailman.39.1684919101.17421.python-checkins@python.org> https://github.com/python/cpython/commit/08d592389603500af398d278af4842cff6f22c33 commit: 08d592389603500af398d278af4842cff6f22c33 branch: main author: Victor Stinner <vstinner at python.org> committer: vstinner <vstinner at python.org> date: 2023-05-24T09:04:53Z summary: gh-104773: PEP 594: Remove cgi and cgitb modules (#104775) * Replace "cgi" with "!cgi" in the Sphinx documentation to avoid warnings on broken references. * test_pyclbr no longer tests the cgi module. files: A Misc/NEWS.d/next/Library/2023-05-23-01-47-57.gh-issue-104773.I6MQhb.rst D Doc/library/cgi.rst D Doc/library/cgitb.rst D Lib/cgi.py D Lib/cgitb.py D Lib/test/test_cgi.py D Lib/test/test_cgitb.py M Doc/library/security_warnings.rst M Doc/library/superseded.rst M Doc/whatsnew/2.0.rst M Doc/whatsnew/2.6.rst M Doc/whatsnew/3.10.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.13.rst M Doc/whatsnew/3.4.rst M Doc/whatsnew/3.6.rst M Doc/whatsnew/3.7.rst M Doc/whatsnew/3.8.rst M Doc/whatsnew/3.9.rst M Lib/test/test_pyclbr.py M Misc/NEWS.d/3.9.0a1.rst M Python/stdlib_module_names.h M Tools/wasm/wasm_assets.py diff --git a/Doc/library/cgi.rst b/Doc/library/cgi.rst deleted file mode 100644 index 295a601a7bf1..000000000000 --- a/Doc/library/cgi.rst +++ /dev/null @@ -1,564 +0,0 @@ -:mod:`cgi` --- Common Gateway Interface support -=============================================== - -.. module:: cgi - :synopsis: Helpers for running Python scripts via the Common Gateway Interface. - :deprecated: - -**Source code:** :source:`Lib/cgi.py` - -.. index:: - pair: WWW; server - pair: CGI; protocol - pair: HTTP; protocol - pair: MIME; headers - single: URL - single: Common Gateway Interface - -.. deprecated-removed:: 3.11 3.13 - The :mod:`cgi` module is deprecated - (see :pep:`PEP 594 <594#cgi>` for details and alternatives). - - The :class:`FieldStorage` class can typically be replaced with - :func:`urllib.parse.parse_qsl` for ``GET`` and ``HEAD`` requests, - and the :mod:`email.message` module or - `multipart <https://pypi.org/project/multipart/>`_ for ``POST`` and ``PUT``. - Most :ref:`utility functions <functions-in-cgi-module>` have replacements. - --------------- - -Support module for Common Gateway Interface (CGI) scripts. - -This module defines a number of utilities for use by CGI scripts written in -Python. - -The global variable ``maxlen`` can be set to an integer indicating the maximum -size of a POST request. POST requests larger than this size will result in a -:exc:`ValueError` being raised during parsing. The default value of this -variable is ``0``, meaning the request size is unlimited. - -.. include:: ../includes/wasm-notavail.rst - -Introduction ------------- - -.. _cgi-intro: - -A CGI script is invoked by an HTTP server, usually to process user input -submitted through an HTML ``<FORM>`` or ``<ISINDEX>`` element. - -Most often, CGI scripts live in the server's special :file:`cgi-bin` directory. -The HTTP server places all sorts of information about the request (such as the -client's hostname, the requested URL, the query string, and lots of other -goodies) in the script's shell environment, executes the script, and sends the -script's output back to the client. - -The script's input is connected to the client too, and sometimes the form data -is read this way; at other times the form data is passed via the "query string" -part of the URL. This module is intended to take care of the different cases -and provide a simpler interface to the Python script. It also provides a number -of utilities that help in debugging scripts, and the latest addition is support -for file uploads from a form (if your browser supports it). - -The output of a CGI script should consist of two sections, separated by a blank -line. The first section contains a number of headers, telling the client what -kind of data is following. Python code to generate a minimal header section -looks like this:: - - print("Content-Type: text/html") # HTML is following - print() # blank line, end of headers - -The second section is usually HTML, which allows the client software to display -nicely formatted text with header, in-line images, etc. Here's Python code that -prints a simple piece of HTML:: - - print("<TITLE>CGI script output") - print("

This is my first CGI script

") - print("Hello, world!") - - -.. _using-the-cgi-module: - -Using the cgi module --------------------- - -Begin by writing ``import cgi``. - -When you write a new script, consider adding these lines:: - - import cgitb - cgitb.enable() - -This activates a special exception handler that will display detailed reports in -the web browser if any errors occur. If you'd rather not show the guts of your -program to users of your script, you can have the reports saved to files -instead, with code like this:: - - import cgitb - cgitb.enable(display=0, logdir="/path/to/logdir") - -It's very helpful to use this feature during script development. The reports -produced by :mod:`cgitb` provide information that can save you a lot of time in -tracking down bugs. You can always remove the ``cgitb`` line later when you -have tested your script and are confident that it works correctly. - -To get at submitted form data, use the :class:`FieldStorage` class. If the form -contains non-ASCII characters, use the *encoding* keyword parameter set to the -value of the encoding defined for the document. It is usually contained in the -META tag in the HEAD section of the HTML document or by the -:mailheader:`Content-Type` header. This reads the form contents from the -standard input or the environment (depending on the value of various -environment variables set according to the CGI standard). Since it may consume -standard input, it should be instantiated only once. - -The :class:`FieldStorage` instance can be indexed like a Python dictionary. -It allows membership testing with the :keyword:`in` operator, and also supports -the standard dictionary method :meth:`~dict.keys` and the built-in function -:func:`len`. Form fields containing empty strings are ignored and do not appear -in the dictionary; to keep such values, provide a true value for the optional -*keep_blank_values* keyword parameter when creating the :class:`FieldStorage` -instance. - -For instance, the following code (which assumes that the -:mailheader:`Content-Type` header and blank line have already been printed) -checks that the fields ``name`` and ``addr`` are both set to a non-empty -string:: - - form = cgi.FieldStorage() - if "name" not in form or "addr" not in form: - print("

Error

") - print("Please fill in the name and addr fields.") - return - print("

name:", form["name"].value) - print("

addr:", form["addr"].value) - ...further form processing here... - -Here the fields, accessed through ``form[key]``, are themselves instances of -:class:`FieldStorage` (or :class:`MiniFieldStorage`, depending on the form -encoding). The :attr:`~FieldStorage.value` attribute of the instance yields -the string value of the field. The :meth:`~FieldStorage.getvalue` method -returns this string value directly; it also accepts an optional second argument -as a default to return if the requested key is not present. - -If the submitted form data contains more than one field with the same name, the -object retrieved by ``form[key]`` is not a :class:`FieldStorage` or -:class:`MiniFieldStorage` instance but a list of such instances. Similarly, in -this situation, ``form.getvalue(key)`` would return a list of strings. If you -expect this possibility (when your HTML form contains multiple fields with the -same name), use the :meth:`~FieldStorage.getlist` method, which always returns -a list of values (so that you do not need to special-case the single item -case). For example, this code concatenates any number of username fields, -separated by commas:: - - value = form.getlist("username") - usernames = ",".join(value) - -If a field represents an uploaded file, accessing the value via the -:attr:`~FieldStorage.value` attribute or the :meth:`~FieldStorage.getvalue` -method reads the entire file in memory as bytes. This may not be what you -want. You can test for an uploaded file by testing either the -:attr:`~FieldStorage.filename` attribute or the :attr:`~FieldStorage.file` -attribute. You can then read the data from the :attr:`!file` -attribute before it is automatically closed as part of the garbage collection of -the :class:`FieldStorage` instance -(the :func:`~io.RawIOBase.read` and :func:`~io.IOBase.readline` methods will -return bytes):: - - fileitem = form["userfile"] - if fileitem.file: - # It's an uploaded file; count lines - linecount = 0 - while True: - line = fileitem.file.readline() - if not line: break - linecount = linecount + 1 - -:class:`FieldStorage` objects also support being used in a :keyword:`with` -statement, which will automatically close them when done. - -If an error is encountered when obtaining the contents of an uploaded file -(for example, when the user interrupts the form submission by clicking on -a Back or Cancel button) the :attr:`~FieldStorage.done` attribute of the -object for the field will be set to the value -1. - -The file upload draft standard entertains the possibility of uploading multiple -files from one field (using a recursive :mimetype:`multipart/\*` encoding). -When this occurs, the item will be a dictionary-like :class:`FieldStorage` item. -This can be determined by testing its :attr:`!type` attribute, which should be -:mimetype:`multipart/form-data` (or perhaps another MIME type matching -:mimetype:`multipart/\*`). In this case, it can be iterated over recursively -just like the top-level form object. - -When a form is submitted in the "old" format (as the query string or as a single -data part of type :mimetype:`application/x-www-form-urlencoded`), the items will -actually be instances of the class :class:`MiniFieldStorage`. In this case, the -:attr:`!list`, :attr:`!file`, and :attr:`filename` attributes are always ``None``. - -A form submitted via POST that also has a query string will contain both -:class:`FieldStorage` and :class:`MiniFieldStorage` items. - -.. versionchanged:: 3.4 - The :attr:`~FieldStorage.file` attribute is automatically closed upon the - garbage collection of the creating :class:`FieldStorage` instance. - -.. versionchanged:: 3.5 - Added support for the context management protocol to the - :class:`FieldStorage` class. - - -Higher Level Interface ----------------------- - -The previous section explains how to read CGI form data using the -:class:`FieldStorage` class. This section describes a higher level interface -which was added to this class to allow one to do it in a more readable and -intuitive way. The interface doesn't make the techniques described in previous -sections obsolete --- they are still useful to process file uploads efficiently, -for example. - -.. XXX: Is this true ? - -The interface consists of two simple methods. Using the methods you can process -form data in a generic way, without the need to worry whether only one or more -values were posted under one name. - -In the previous section, you learned to write following code anytime you -expected a user to post more than one value under one name:: - - item = form.getvalue("item") - if isinstance(item, list): - # The user is requesting more than one item. - else: - # The user is requesting only one item. - -This situation is common for example when a form contains a group of multiple -checkboxes with the same name:: - - - - -In most situations, however, there's only one form control with a particular -name in a form and then you expect and need only one value associated with this -name. So you write a script containing for example this code:: - - user = form.getvalue("user").upper() - -The problem with the code is that you should never expect that a client will -provide valid input to your scripts. For example, if a curious user appends -another ``user=foo`` pair to the query string, then the script would crash, -because in this situation the ``getvalue("user")`` method call returns a list -instead of a string. Calling the :meth:`~str.upper` method on a list is not valid -(since lists do not have a method of this name) and results in an -:exc:`AttributeError` exception. - -Therefore, the appropriate way to read form data values was to always use the -code which checks whether the obtained value is a single value or a list of -values. That's annoying and leads to less readable scripts. - -A more convenient approach is to use the methods :meth:`~FieldStorage.getfirst` -and :meth:`~FieldStorage.getlist` provided by this higher level interface. - - -.. method:: FieldStorage.getfirst(name, default=None) - - This method always returns only one value associated with form field *name*. - The method returns only the first value in case that more values were posted - under such name. Please note that the order in which the values are received - may vary from browser to browser and should not be counted on. [#]_ If no such - form field or value exists then the method returns the value specified by the - optional parameter *default*. This parameter defaults to ``None`` if not - specified. - - -.. method:: FieldStorage.getlist(name) - - This method always returns a list of values associated with form field *name*. - The method returns an empty list if no such form field or value exists for - *name*. It returns a list consisting of one item if only one such value exists. - -Using these methods you can write nice compact code:: - - import cgi - form = cgi.FieldStorage() - user = form.getfirst("user", "").upper() # This way it's safe. - for item in form.getlist("item"): - do_something(item) - - -.. _functions-in-cgi-module: - -Functions ---------- - -These are useful if you want more control, or if you want to employ some of the -algorithms implemented in this module in other circumstances. - - -.. function:: parse(fp=None, environ=os.environ, keep_blank_values=False, strict_parsing=False, separator="&") - - Parse a query in the environment or from a file (the file defaults to - ``sys.stdin``). The *keep_blank_values*, *strict_parsing* and *separator* parameters are - passed to :func:`urllib.parse.parse_qs` unchanged. - - .. deprecated-removed:: 3.11 3.13 - This function, like the rest of the :mod:`cgi` module, is deprecated. - It can be replaced by calling :func:`urllib.parse.parse_qs` directly - on the desired query string (except for ``multipart/form-data`` input, - which can be handled as described for :func:`parse_multipart`). - - -.. function:: parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator="&") - - Parse input of type :mimetype:`multipart/form-data` (for file uploads). - Arguments are *fp* for the input file, *pdict* for a dictionary containing - other parameters in the :mailheader:`Content-Type` header, and *encoding*, - the request encoding. - - Returns a dictionary just like :func:`urllib.parse.parse_qs`: keys are the - field names, each value is a list of values for that field. For non-file - fields, the value is a list of strings. - - This is easy to use but not much good if you are expecting megabytes to be - uploaded --- in that case, use the :class:`FieldStorage` class instead - which is much more flexible. - - .. versionchanged:: 3.7 - Added the *encoding* and *errors* parameters. For non-file fields, the - value is now a list of strings, not bytes. - - .. versionchanged:: 3.10 - Added the *separator* parameter. - - .. deprecated-removed:: 3.11 3.13 - This function, like the rest of the :mod:`cgi` module, is deprecated. - It can be replaced with the functionality in the :mod:`email` package - (e.g. :class:`email.message.EmailMessage`/:class:`email.message.Message`) - which implements the same MIME RFCs, or with the - `multipart `__ PyPI project. - - -.. function:: parse_header(string) - - Parse a MIME header (such as :mailheader:`Content-Type`) into a main value and a - dictionary of parameters. - - .. deprecated-removed:: 3.11 3.13 - This function, like the rest of the :mod:`cgi` module, is deprecated. - It can be replaced with the functionality in the :mod:`email` package, - which implements the same MIME RFCs. - - For example, with :class:`email.message.EmailMessage`:: - - from email.message import EmailMessage - msg = EmailMessage() - msg['content-type'] = 'application/json; charset="utf8"' - main, params = msg.get_content_type(), msg['content-type'].params - - -.. function:: test() - - Robust test CGI script, usable as main program. Writes minimal HTTP headers and - formats all information provided to the script in HTML format. - - -.. function:: print_environ() - - Format the shell environment in HTML. - - -.. function:: print_form(form) - - Format a form in HTML. - - -.. function:: print_directory() - - Format the current directory in HTML. - - -.. function:: print_environ_usage() - - Print a list of useful (used by CGI) environment variables in HTML. - - -.. _cgi-security: - -Caring about security ---------------------- - -.. index:: pair: CGI; security - -There's one important rule: if you invoke an external program (via -:func:`os.system`, :func:`os.popen` or other functions with similar -functionality), make very sure you don't pass arbitrary strings received from -the client to the shell. This is a well-known security hole whereby clever -hackers anywhere on the web can exploit a gullible CGI script to invoke -arbitrary shell commands. Even parts of the URL or field names cannot be -trusted, since the request doesn't have to come from your form! - -To be on the safe side, if you must pass a string gotten from a form to a shell -command, you should make sure the string contains only alphanumeric characters, -dashes, underscores, and periods. - - -Installing your CGI script on a Unix system -------------------------------------------- - -Read the documentation for your HTTP server and check with your local system -administrator to find the directory where CGI scripts should be installed; -usually this is in a directory :file:`cgi-bin` in the server tree. - -Make sure that your script is readable and executable by "others"; the Unix file -mode should be ``0o755`` octal (use ``chmod 0755 filename``). Make sure that the -first line of the script contains ``#!`` starting in column 1 followed by the -pathname of the Python interpreter, for instance:: - - #!/usr/local/bin/python - -Make sure the Python interpreter exists and is executable by "others". - -Make sure that any files your script needs to read or write are readable or -writable, respectively, by "others" --- their mode should be ``0o644`` for -readable and ``0o666`` for writable. This is because, for security reasons, the -HTTP server executes your script as user "nobody", without any special -privileges. It can only read (write, execute) files that everybody can read -(write, execute). The current directory at execution time is also different (it -is usually the server's cgi-bin directory) and the set of environment variables -is also different from what you get when you log in. In particular, don't count -on the shell's search path for executables (:envvar:`PATH`) or the Python module -search path (:envvar:`PYTHONPATH`) to be set to anything interesting. - -If you need to load modules from a directory which is not on Python's default -module search path, you can change the path in your script, before importing -other modules. For example:: - - import sys - sys.path.insert(0, "/usr/home/joe/lib/python") - sys.path.insert(0, "/usr/local/lib/python") - -(This way, the directory inserted last will be searched first!) - -Instructions for non-Unix systems will vary; check your HTTP server's -documentation (it will usually have a section on CGI scripts). - - -Testing your CGI script ------------------------ - -Unfortunately, a CGI script will generally not run when you try it from the -command line, and a script that works perfectly from the command line may fail -mysteriously when run from the server. There's one reason why you should still -test your script from the command line: if it contains a syntax error, the -Python interpreter won't execute it at all, and the HTTP server will most likely -send a cryptic error to the client. - -Assuming your script has no syntax errors, yet it does not work, you have no -choice but to read the next section. - - -Debugging CGI scripts ---------------------- - -.. index:: pair: CGI; debugging - -First of all, check for trivial installation errors --- reading the section -above on installing your CGI script carefully can save you a lot of time. If -you wonder whether you have understood the installation procedure correctly, try -installing a copy of this module file (:file:`cgi.py`) as a CGI script. When -invoked as a script, the file will dump its environment and the contents of the -form in HTML format. Give it the right mode etc., and send it a request. If it's -installed in the standard :file:`cgi-bin` directory, it should be possible to -send it a request by entering a URL into your browser of the form: - -.. code-block:: none - - http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home - -If this gives an error of type 404, the server cannot find the script -- perhaps -you need to install it in a different directory. If it gives another error, -there's an installation problem that you should fix before trying to go any -further. If you get a nicely formatted listing of the environment and form -content (in this example, the fields should be listed as "addr" with value "At -Home" and "name" with value "Joe Blow"), the :file:`cgi.py` script has been -installed correctly. If you follow the same procedure for your own script, you -should now be able to debug it. - -The next step could be to call the :mod:`cgi` module's :func:`test` function -from your script: replace its main code with the single statement :: - - cgi.test() - -This should produce the same results as those gotten from installing the -:file:`cgi.py` file itself. - -When an ordinary Python script raises an unhandled exception (for whatever -reason: of a typo in a module name, a file that can't be opened, etc.), the -Python interpreter prints a nice traceback and exits. While the Python -interpreter will still do this when your CGI script raises an exception, most -likely the traceback will end up in one of the HTTP server's log files, or be -discarded altogether. - -Fortunately, once you have managed to get your script to execute *some* code, -you can easily send tracebacks to the web browser using the :mod:`cgitb` module. -If you haven't done so already, just add the lines:: - - import cgitb - cgitb.enable() - -to the top of your script. Then try running it again; when a problem occurs, -you should see a detailed report that will likely make apparent the cause of the -crash. - -If you suspect that there may be a problem in importing the :mod:`cgitb` module, -you can use an even more robust approach (which only uses built-in modules):: - - import sys - sys.stderr = sys.stdout - print("Content-Type: text/plain") - print() - ...your code here... - -This relies on the Python interpreter to print the traceback. The content type -of the output is set to plain text, which disables all HTML processing. If your -script works, the raw HTML will be displayed by your client. If it raises an -exception, most likely after the first two lines have been printed, a traceback -will be displayed. Because no HTML interpretation is going on, the traceback -will be readable. - - -Common problems and solutions ------------------------------ - -* Most HTTP servers buffer the output from CGI scripts until the script is - completed. This means that it is not possible to display a progress report on - the client's display while the script is running. - -* Check the installation instructions above. - -* Check the HTTP server's log files. (``tail -f logfile`` in a separate window - may be useful!) - -* Always check a script for syntax errors first, by doing something like - ``python script.py``. - -* If your script does not have any syntax errors, try adding ``import cgitb; - cgitb.enable()`` to the top of the script. - -* When invoking external programs, make sure they can be found. Usually, this - means using absolute path names --- :envvar:`PATH` is usually not set to a very - useful value in a CGI script. - -* When reading or writing external files, make sure they can be read or written - by the userid under which your CGI script will be running: this is typically the - userid under which the web server is running, or some explicitly specified - userid for a web server's ``suexec`` feature. - -* Don't try to give a CGI script a set-uid mode. This doesn't work on most - systems, and is a security liability as well. - -.. rubric:: Footnotes - -.. [#] Note that some recent versions of the HTML specification do state what - order the field values should be supplied in, but knowing whether a request - was received from a conforming browser, or even from a browser at all, is - tedious and error-prone. diff --git a/Doc/library/cgitb.rst b/Doc/library/cgitb.rst deleted file mode 100644 index 7f00bcd55c1e..000000000000 --- a/Doc/library/cgitb.rst +++ /dev/null @@ -1,89 +0,0 @@ -:mod:`cgitb` --- Traceback manager for CGI scripts -================================================== - -.. module:: cgitb - :synopsis: Configurable traceback handler for CGI scripts. - :deprecated: - -.. moduleauthor:: Ka-Ping Yee -.. sectionauthor:: Fred L. Drake, Jr. - -**Source code:** :source:`Lib/cgitb.py` - -.. index:: - single: CGI; exceptions - single: CGI; tracebacks - single: exceptions; in CGI scripts - single: tracebacks; in CGI scripts - -.. deprecated-removed:: 3.11 3.13 - The :mod:`cgitb` module is deprecated - (see :pep:`PEP 594 <594#cgitb>` for details). - --------------- - -The :mod:`cgitb` module provides a special exception handler for Python scripts. -(Its name is a bit misleading. It was originally designed to display extensive -traceback information in HTML for CGI scripts. It was later generalized to also -display this information in plain text.) After this module is activated, if an -uncaught exception occurs, a detailed, formatted report will be displayed. The -report includes a traceback showing excerpts of the source code for each level, -as well as the values of the arguments and local variables to currently running -functions, to help you debug the problem. Optionally, you can save this -information to a file instead of sending it to the browser. - -To enable this feature, simply add this to the top of your CGI script:: - - import cgitb - cgitb.enable() - -The options to the :func:`enable` function control whether the report is -displayed in the browser and whether the report is logged to a file for later -analysis. - - -.. function:: enable(display=1, logdir=None, context=5, format="html") - - .. index:: single: excepthook() (in module sys) - - This function causes the :mod:`cgitb` module to take over the interpreter's - default handling for exceptions by setting the value of :attr:`sys.excepthook`. - - The optional argument *display* defaults to ``1`` and can be set to ``0`` to - suppress sending the traceback to the browser. If the argument *logdir* is - present, the traceback reports are written to files. The value of *logdir* - should be a directory where these files will be placed. The optional argument - *context* is the number of lines of context to display around the current line - of source code in the traceback; this defaults to ``5``. If the optional - argument *format* is ``"html"``, the output is formatted as HTML. Any other - value forces plain text output. The default value is ``"html"``. - - -.. function:: text(info, context=5) - - This function handles the exception described by *info* (a 3-tuple containing - the result of :func:`sys.exc_info`), formatting its traceback as text and - returning the result as a string. The optional argument *context* is the - number of lines of context to display around the current line of source code - in the traceback; this defaults to ``5``. - - -.. function:: html(info, context=5) - - This function handles the exception described by *info* (a 3-tuple containing - the result of :func:`sys.exc_info`), formatting its traceback as HTML and - returning the result as a string. The optional argument *context* is the - number of lines of context to display around the current line of source code - in the traceback; this defaults to ``5``. - - -.. function:: handler(info=None) - - This function handles an exception using the default settings (that is, show a - report in the browser, but don't log to a file). This can be used when you've - caught an exception and want to report it using :mod:`cgitb`. The optional - *info* argument should be a 3-tuple containing an exception type, exception - value, and traceback object, exactly like the tuple returned by - :func:`sys.exc_info`. If the *info* argument is not supplied, the current - exception is obtained from :func:`sys.exc_info`. - diff --git a/Doc/library/security_warnings.rst b/Doc/library/security_warnings.rst index 284f36583206..a573c98f73eb 100644 --- a/Doc/library/security_warnings.rst +++ b/Doc/library/security_warnings.rst @@ -9,7 +9,6 @@ The following modules have specific security considerations: * :mod:`base64`: :ref:`base64 security considerations ` in :rfc:`4648` -* :mod:`cgi`: :ref:`CGI security considerations ` * :mod:`hashlib`: :ref:`all constructors take a "usedforsecurity" keyword-only argument disabling known insecure and blocked algorithms ` diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index e4a473f71284..a96d042f8374 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -12,8 +12,6 @@ backwards compatibility. They have been superseded by other modules. aifc.rst audioop.rst - cgi.rst - cgitb.rst chunk.rst crypt.rst imghdr.rst diff --git a/Doc/whatsnew/2.0.rst b/Doc/whatsnew/2.0.rst index 0eefefd863a6..76094d4df98f 100644 --- a/Doc/whatsnew/2.0.rst +++ b/Doc/whatsnew/2.0.rst @@ -1030,7 +1030,7 @@ Module changes Lots of improvements and bugfixes were made to Python's extensive standard library; some of the affected modules include :mod:`readline`, -:mod:`ConfigParser`, :mod:`cgi`, :mod:`calendar`, :mod:`posix`, :mod:`readline`, +:mod:`ConfigParser`, :mod:`!cgi`, :mod:`calendar`, :mod:`posix`, :mod:`readline`, :mod:`xmllib`, :mod:`aifc`, :mod:`chunk, wave`, :mod:`random`, :mod:`shelve`, and :mod:`nntplib`. Consult the CVS logs for the exact patch-by-patch details. diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 7236e1cad7c8..0a8bad4e5317 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1805,15 +1805,15 @@ changes, or look through the Subversion logs for all the details. available, instead of restricting itself to protocol 1. (Contributed by W. Barnes.) -* The :mod:`cgi` module will now read variables from the query string +* The :mod:`!cgi` module will now read variables from the query string of an HTTP POST request. This makes it possible to use form actions with URLs that include query strings such as "/cgi-bin/add.py?category=1". (Contributed by Alexandre Fiori and Nubis; :issue:`1817`.) The :func:`parse_qs` and :func:`parse_qsl` functions have been - relocated from the :mod:`cgi` module to the :mod:`urlparse` module. - The versions still available in the :mod:`cgi` module will + relocated from the :mod:`!cgi` module to the :mod:`urlparse` module. + The versions still available in the :mod:`!cgi` module will trigger :exc:`PendingDeprecationWarning` messages in 2.6 (:issue:`600362`). diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 661eeaedbfc0..ab030db5b3ff 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1508,7 +1508,7 @@ query parameter separators in :func:`urllib.parse.parse_qs` and :func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with newer W3C recommendations, this has been changed to allow only a single separator key, with ``&`` as the default. This change also affects -:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +:func:`!cgi.parse` and :func:`!cgi.parse_multipart` as they use the affected functions internally. For more details, please see their respective documentation. (Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 8aadc2a0a581..d024b85059a8 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1735,9 +1735,9 @@ Modules +---------------------+---------------------+---------------------+---------------------+---------------------+ | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`sndhdr` | :mod:`uu` | +---------------------+---------------------+---------------------+---------------------+---------------------+ - | :mod:`cgi` | :mod:`imghdr` | :mod:`nntplib` | :mod:`spwd` | :mod:`xdrlib` | + | :mod:`!cgi` | :mod:`imghdr` | :mod:`nntplib` | :mod:`spwd` | :mod:`xdrlib` | +---------------------+---------------------+---------------------+---------------------+---------------------+ - | :mod:`cgitb` | :mod:`mailcap` | :mod:`ossaudiodev` | :mod:`sunau` | | + | :mod:`!cgitb` | :mod:`mailcap` | :mod:`ossaudiodev` | :mod:`sunau` | | +---------------------+---------------------+---------------------+---------------------+---------------------+ (Contributed by Brett Cannon in :issue:`47061` and Victor Stinner in diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 5e07a4caeb9e..417da22ee045 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -805,8 +805,8 @@ Modules (see :pep:`594`): * :mod:`aifc` * :mod:`audioop` -* :mod:`cgi` -* :mod:`cgitb` +* :mod:`!cgi` +* :mod:`!cgitb` * :mod:`chunk` * :mod:`crypt` * :mod:`imghdr` diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 309f26ea27db..4bd9a73e7aa7 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -118,6 +118,36 @@ Removed * Remove support for using :class:`pathlib.Path` objects as context managers. This functionality was deprecated and made a no-op in Python 3.9. +* :pep:`594`: Remove the :mod:`!cgi`` and :mod:`!cgitb` modules, + deprecated in Python 3.11. + + * ``cgi.FieldStorage`` can typically be replaced with + :func:`urllib.parse.parse_qsl` for ``GET`` and ``HEAD`` requests, and the + :mod:`email.message` module or `multipart + `__ PyPI project for ``POST`` and + ``PUT``. + + * ``cgi.parse()`` can be replaced by calling :func:`urllib.parse.parse_qs` + directly on the desired query string, except for ``multipart/form-data`` + input, which can be handled as described for ``cgi.parse_multipart()``. + + * ``cgi.parse_multipart()`` can be replaced with the functionality in the + :mod:`email` package (e.g. :class:`email.message.EmailMessage` and + :class:`email.message.Message`) which implements the same MIME RFCs, or + with the `multipart `__ PyPI project. + + * ``cgi.parse_header()`` can be replaced with the functionality in the + :mod:`email` package, which implements the same MIME RFCs. For example, + with :class:`email.message.EmailMessage`:: + + from email.message import EmailMessage + msg = EmailMessage() + msg['content-type'] = 'application/json; charset="utf8"' + main, params = msg.get_content_type(), msg['content-type'].params + + (Contributed by Victor Stinner in :gh:`104773`.) + + Porting to Python 3.13 ====================== diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 45bb91833a35..d4ed8abe772a 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2371,11 +2371,11 @@ Changes in the Python API 3.3.3. * The :attr:`~cgi.FieldStorage.file` attribute is now automatically closed when - the creating :class:`cgi.FieldStorage` instance is garbage collected. If you - were pulling the file object out separately from the :class:`cgi.FieldStorage` + the creating :class:`!cgi.FieldStorage` instance is garbage collected. If you + were pulling the file object out separately from the :class:`!cgi.FieldStorage` instance and not keeping the instance alive, then you should either store the - entire :class:`cgi.FieldStorage` instance or read the contents of the file - before the :class:`cgi.FieldStorage` instance is garbage collected. + entire :class:`!cgi.FieldStorage` instance or read the contents of the file + before the :class:`!cgi.FieldStorage` instance is garbage collected. * Calling ``read`` or ``write`` on a closed SSL socket now raises an informative :exc:`ValueError` rather than the previous more mysterious diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 1cd33dfb6042..3d8f9322f927 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2185,7 +2185,7 @@ Changes in the Python API * The following modules have had missing APIs added to their :attr:`__all__` attributes to match the documented APIs: - :mod:`calendar`, :mod:`cgi`, :mod:`csv`, + :mod:`calendar`, :mod:`!cgi`, :mod:`csv`, :mod:`~xml.etree.ElementTree`, :mod:`enum`, :mod:`fileinput`, :mod:`ftplib`, :mod:`logging`, :mod:`mailbox`, :mod:`mimetypes`, :mod:`optparse`, :mod:`plistlib`, :mod:`smtpd`, @@ -2455,7 +2455,7 @@ query parameter separators in :func:`urllib.parse.parse_qs` and :func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with newer W3C recommendations, this has been changed to allow only a single separator key, with ``&`` as the default. This change also affects -:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +:func:`!cgi.parse` and :func:`!cgi.parse_multipart` as they use the affected functions internally. For more details, please see their respective documentation. (Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 28f22836d8d0..41d7e08f2b39 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -2567,7 +2567,7 @@ query parameter separators in :func:`urllib.parse.parse_qs` and :func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with newer W3C recommendations, this has been changed to allow only a single separator key, with ``&`` as the default. This change also affects -:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +:func:`!cgi.parse` and :func:`!cgi.parse_multipart` as they use the affected functions internally. For more details, please see their respective documentation. (Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 85e088b64acb..16762817ab82 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1774,7 +1774,7 @@ The following features and APIs have been removed from Python 3.8: to help eliminate confusion as to what Python interpreter the ``pyvenv`` script is tied to. (Contributed by Brett Cannon in :issue:`25427`.) -* ``parse_qs``, ``parse_qsl``, and ``escape`` are removed from the :mod:`cgi` +* ``parse_qs``, ``parse_qsl``, and ``escape`` are removed from the :mod:`!cgi` module. They are deprecated in Python 3.2 or older. They should be imported from the ``urllib.parse`` and ``html`` modules instead. @@ -2251,7 +2251,7 @@ query parameter separators in :func:`urllib.parse.parse_qs` and :func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with newer W3C recommendations, this has been changed to allow only a single separator key, with ``&`` as the default. This change also affects -:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +:func:`!cgi.parse` and :func:`!cgi.parse_multipart` as they use the affected functions internally. For more details, please see their respective documentation. (Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 532cabdd7a75..54f5662dad90 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -1559,7 +1559,7 @@ query parameter separators in :func:`urllib.parse.parse_qs` and :func:`urllib.parse.parse_qsl`. Due to security concerns, and to conform with newer W3C recommendations, this has been changed to allow only a single separator key, with ``&`` as the default. This change also affects -:func:`cgi.parse` and :func:`cgi.parse_multipart` as they use the affected +:func:`!cgi.parse` and :func:`!cgi.parse_multipart` as they use the affected functions internally. For more details, please see their respective documentation. (Contributed by Adam Goldschmidt, Senthil Kumaran and Ken Jin in :issue:`42967`.) diff --git a/Lib/cgi.py b/Lib/cgi.py deleted file mode 100755 index 8787567be7c0..000000000000 --- a/Lib/cgi.py +++ /dev/null @@ -1,1012 +0,0 @@ -#! /usr/local/bin/python - -# NOTE: the above "/usr/local/bin/python" is NOT a mistake. It is -# intentionally NOT "/usr/bin/env python". On many systems -# (e.g. Solaris), /usr/local/bin is not in $PATH as passed to CGI -# scripts, and /usr/local/bin is the default directory where Python is -# installed, so /usr/bin/env would be unable to find python. Granted, -# binary installations by Linux vendors often install Python in -# /usr/bin. So let those vendors patch cgi.py to match their choice -# of installation. - -"""Support module for CGI (Common Gateway Interface) scripts. - -This module defines a number of utilities for use by CGI scripts -written in Python. - -The global variable maxlen can be set to an integer indicating the maximum size -of a POST request. POST requests larger than this size will result in a -ValueError being raised during parsing. The default value of this variable is 0, -meaning the request size is unlimited. -""" - -# History -# ------- -# -# Michael McLay started this module. Steve Majewski changed the -# interface to SvFormContentDict and FormContentDict. The multipart -# parsing was inspired by code submitted by Andreas Paepcke. Guido van -# Rossum rewrote, reformatted and documented the module and is currently -# responsible for its maintenance. -# - -__version__ = "2.6" - - -# Imports -# ======= - -from io import StringIO, BytesIO, TextIOWrapper -from collections.abc import Mapping -import sys -import os -import urllib.parse -from email.parser import FeedParser -from email.message import Message -import html -import locale -import tempfile -import warnings - -__all__ = ["MiniFieldStorage", "FieldStorage", "parse", "parse_multipart", - "parse_header", "test", "print_exception", "print_environ", - "print_form", "print_directory", "print_arguments", - "print_environ_usage"] - - -warnings._deprecated(__name__, remove=(3,13)) - -# Logging support -# =============== - -logfile = "" # Filename to log to, if not empty -logfp = None # File object to log to, if not None - -def initlog(*allargs): - """Write a log message, if there is a log file. - - Even though this function is called initlog(), you should always - use log(); log is a variable that is set either to initlog - (initially), to dolog (once the log file has been opened), or to - nolog (when logging is disabled). - - The first argument is a format string; the remaining arguments (if - any) are arguments to the % operator, so e.g. - log("%s: %s", "a", "b") - will write "a: b" to the log file, followed by a newline. - - If the global logfp is not None, it should be a file object to - which log data is written. - - If the global logfp is None, the global logfile may be a string - giving a filename to open, in append mode. This file should be - world writable!!! If the file can't be opened, logging is - silently disabled (since there is no safe place where we could - send an error message). - - """ - global log, logfile, logfp - warnings.warn("cgi.log() is deprecated as of 3.10. Use logging instead", - DeprecationWarning, stacklevel=2) - if logfile and not logfp: - try: - logfp = open(logfile, "a", encoding="locale") - except OSError: - pass - if not logfp: - log = nolog - else: - log = dolog - log(*allargs) - -def dolog(fmt, *args): - """Write a log message to the log file. See initlog() for docs.""" - logfp.write(fmt%args + "\n") - -def nolog(*allargs): - """Dummy function, assigned to log when logging is disabled.""" - pass - -def closelog(): - """Close the log file.""" - global log, logfile, logfp - logfile = '' - if logfp: - logfp.close() - logfp = None - log = initlog - -log = initlog # The current logging function - - -# Parsing functions -# ================= - -# Maximum input we will accept when REQUEST_METHOD is POST -# 0 ==> unlimited input -maxlen = 0 - -def parse(fp=None, environ=os.environ, keep_blank_values=0, - strict_parsing=0, separator='&'): - """Parse a query in the environment or from a file (default stdin) - - Arguments, all optional: - - fp : file pointer; default: sys.stdin.buffer - - environ : environment dictionary; default: os.environ - - keep_blank_values: flag indicating whether blank values in - percent-encoded forms should be treated as blank strings. - A true value indicates that blanks should be retained as - blank strings. The default false value indicates that - blank values are to be ignored and treated as if they were - not included. - - strict_parsing: flag indicating what to do with parsing errors. - If false (the default), errors are silently ignored. - If true, errors raise a ValueError exception. - - separator: str. The symbol to use for separating the query arguments. - Defaults to &. - """ - if fp is None: - fp = sys.stdin - - # field keys and values (except for files) are returned as strings - # an encoding is required to decode the bytes read from self.fp - if hasattr(fp,'encoding'): - encoding = fp.encoding - else: - encoding = 'latin-1' - - # fp.read() must return bytes - if isinstance(fp, TextIOWrapper): - fp = fp.buffer - - if not 'REQUEST_METHOD' in environ: - environ['REQUEST_METHOD'] = 'GET' # For testing stand-alone - if environ['REQUEST_METHOD'] == 'POST': - ctype, pdict = parse_header(environ['CONTENT_TYPE']) - if ctype == 'multipart/form-data': - return parse_multipart(fp, pdict, separator=separator) - elif ctype == 'application/x-www-form-urlencoded': - clength = int(environ['CONTENT_LENGTH']) - if maxlen and clength > maxlen: - raise ValueError('Maximum content length exceeded') - qs = fp.read(clength).decode(encoding) - else: - qs = '' # Unknown content-type - if 'QUERY_STRING' in environ: - if qs: qs = qs + '&' - qs = qs + environ['QUERY_STRING'] - elif sys.argv[1:]: - if qs: qs = qs + '&' - qs = qs + sys.argv[1] - environ['QUERY_STRING'] = qs # XXX Shouldn't, really - elif 'QUERY_STRING' in environ: - qs = environ['QUERY_STRING'] - else: - if sys.argv[1:]: - qs = sys.argv[1] - else: - qs = "" - environ['QUERY_STRING'] = qs # XXX Shouldn't, really - return urllib.parse.parse_qs(qs, keep_blank_values, strict_parsing, - encoding=encoding, separator=separator) - - -def parse_multipart(fp, pdict, encoding="utf-8", errors="replace", separator='&'): - """Parse multipart input. - - Arguments: - fp : input file - pdict: dictionary containing other parameters of content-type header - encoding, errors: request encoding and error handler, passed to - FieldStorage - - Returns a dictionary just like parse_qs(): keys are the field names, each - value is a list of values for that field. For non-file fields, the value - is a list of strings. - """ - # RFC 2046, Section 5.1 : The "multipart" boundary delimiters are always - # represented as 7bit US-ASCII. - boundary = pdict['boundary'].decode('ascii') - ctype = "multipart/form-data; boundary={}".format(boundary) - headers = Message() - headers.set_type(ctype) - try: - headers['Content-Length'] = pdict['CONTENT-LENGTH'] - except KeyError: - pass - fs = FieldStorage(fp, headers=headers, encoding=encoding, errors=errors, - environ={'REQUEST_METHOD': 'POST'}, separator=separator) - return {k: fs.getlist(k) for k in fs} - -def _parseparam(s): - while s[:1] == ';': - s = s[1:] - end = s.find(';') - while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: - end = s.find(';', end + 1) - if end < 0: - end = len(s) - f = s[:end] - yield f.strip() - s = s[end:] - -def parse_header(line): - """Parse a Content-type like header. - - Return the main content-type and a dictionary of options. - - """ - parts = _parseparam(';' + line) - key = parts.__next__() - pdict = {} - for p in parts: - i = p.find('=') - if i >= 0: - name = p[:i].strip().lower() - value = p[i+1:].strip() - if len(value) >= 2 and value[0] == value[-1] == '"': - value = value[1:-1] - value = value.replace('\\\\', '\\').replace('\\"', '"') - pdict[name] = value - return key, pdict - - -# Classes for field storage -# ========================= - -class MiniFieldStorage: - - """Like FieldStorage, for use when no file uploads are possible.""" - - # Dummy attributes - filename = None - list = None - type = None - file = None - type_options = {} - disposition = None - disposition_options = {} - headers = {} - - def __init__(self, name, value): - """Constructor from field name and value.""" - self.name = name - self.value = value - # self.file = StringIO(value) - - def __repr__(self): - """Return printable representation.""" - return "MiniFieldStorage(%r, %r)" % (self.name, self.value) - - -class FieldStorage: - - """Store a sequence of fields, reading multipart/form-data. - - This class provides naming, typing, files stored on disk, and - more. At the top level, it is accessible like a dictionary, whose - keys are the field names. (Note: None can occur as a field name.) - The items are either a Python list (if there's multiple values) or - another FieldStorage or MiniFieldStorage object. If it's a single - object, it has the following attributes: - - name: the field name, if specified; otherwise None - - filename: the filename, if specified; otherwise None; this is the - client side filename, *not* the file name on which it is - stored (that's a temporary file you don't deal with) - - value: the value as a *string*; for file uploads, this - transparently reads the file every time you request the value - and returns *bytes* - - file: the file(-like) object from which you can read the data *as - bytes* ; None if the data is stored a simple string - - type: the content-type, or None if not specified - - type_options: dictionary of options specified on the content-type - line - - disposition: content-disposition, or None if not specified - - disposition_options: dictionary of corresponding options - - headers: a dictionary(-like) object (sometimes email.message.Message or a - subclass thereof) containing *all* headers - - The class is subclassable, mostly for the purpose of overriding - the make_file() method, which is called internally to come up with - a file open for reading and writing. This makes it possible to - override the default choice of storing all files in a temporary - directory and unlinking them as soon as they have been opened. - - """ - def __init__(self, fp=None, headers=None, outerboundary=b'', - environ=os.environ, keep_blank_values=0, strict_parsing=0, - limit=None, encoding='utf-8', errors='replace', - max_num_fields=None, separator='&'): - """Constructor. Read multipart/* until last part. - - Arguments, all optional: - - fp : file pointer; default: sys.stdin.buffer - (not used when the request method is GET) - Can be : - 1. a TextIOWrapper object - 2. an object whose read() and readline() methods return bytes - - headers : header dictionary-like object; default: - taken from environ as per CGI spec - - outerboundary : terminating multipart boundary - (for internal use only) - - environ : environment dictionary; default: os.environ - - keep_blank_values: flag indicating whether blank values in - percent-encoded forms should be treated as blank strings. - A true value indicates that blanks should be retained as - blank strings. The default false value indicates that - blank values are to be ignored and treated as if they were - not included. - - strict_parsing: flag indicating what to do with parsing errors. - If false (the default), errors are silently ignored. - If true, errors raise a ValueError exception. - - limit : used internally to read parts of multipart/form-data forms, - to exit from the reading loop when reached. It is the difference - between the form content-length and the number of bytes already - read - - encoding, errors : the encoding and error handler used to decode the - binary stream to strings. Must be the same as the charset defined - for the page sending the form (content-type : meta http-equiv or - header) - - max_num_fields: int. If set, then __init__ throws a ValueError - if there are more than n fields read by parse_qsl(). - - """ - method = 'GET' - self.keep_blank_values = keep_blank_values - self.strict_parsing = strict_parsing - self.max_num_fields = max_num_fields - self.separator = separator - if 'REQUEST_METHOD' in environ: - method = environ['REQUEST_METHOD'].upper() - self.qs_on_post = None - if method == 'GET' or method == 'HEAD': - if 'QUERY_STRING' in environ: - qs = environ['QUERY_STRING'] - elif sys.argv[1:]: - qs = sys.argv[1] - else: - qs = "" - qs = qs.encode(locale.getpreferredencoding(), 'surrogateescape') - fp = BytesIO(qs) - if headers is None: - headers = {'content-type': - "application/x-www-form-urlencoded"} - if headers is None: - headers = {} - if method == 'POST': - # Set default content-type for POST to what's traditional - headers['content-type'] = "application/x-www-form-urlencoded" - if 'CONTENT_TYPE' in environ: - headers['content-type'] = environ['CONTENT_TYPE'] - if 'QUERY_STRING' in environ: - self.qs_on_post = environ['QUERY_STRING'] - if 'CONTENT_LENGTH' in environ: - headers['content-length'] = environ['CONTENT_LENGTH'] - else: - if not (isinstance(headers, (Mapping, Message))): - raise TypeError("headers must be mapping or an instance of " - "email.message.Message") - self.headers = headers - if fp is None: - self.fp = sys.stdin.buffer - # self.fp.read() must return bytes - elif isinstance(fp, TextIOWrapper): - self.fp = fp.buffer - else: - if not (hasattr(fp, 'read') and hasattr(fp, 'readline')): - raise TypeError("fp must be file pointer") - self.fp = fp - - self.encoding = encoding - self.errors = errors - - if not isinstance(outerboundary, bytes): - raise TypeError('outerboundary must be bytes, not %s' - % type(outerboundary).__name__) - self.outerboundary = outerboundary - - self.bytes_read = 0 - self.limit = limit - - # Process content-disposition header - cdisp, pdict = "", {} - if 'content-disposition' in self.headers: - cdisp, pdict = parse_header(self.headers['content-disposition']) - self.disposition = cdisp - self.disposition_options = pdict - self.name = None - if 'name' in pdict: - self.name = pdict['name'] - self.filename = None - if 'filename' in pdict: - self.filename = pdict['filename'] - self._binary_file = self.filename is not None - - # Process content-type header - # - # Honor any existing content-type header. But if there is no - # content-type header, use some sensible defaults. Assume - # outerboundary is "" at the outer level, but something non-false - # inside a multi-part. The default for an inner part is text/plain, - # but for an outer part it should be urlencoded. This should catch - # bogus clients which erroneously forget to include a content-type - # header. - # - # See below for what we do if there does exist a content-type header, - # but it happens to be something we don't understand. - if 'content-type' in self.headers: - ctype, pdict = parse_header(self.headers['content-type']) - elif self.outerboundary or method != 'POST': - ctype, pdict = "text/plain", {} - else: - ctype, pdict = 'application/x-www-form-urlencoded', {} - self.type = ctype - self.type_options = pdict - if 'boundary' in pdict: - self.innerboundary = pdict['boundary'].encode(self.encoding, - self.errors) - else: - self.innerboundary = b"" - - clen = -1 - if 'content-length' in self.headers: - try: - clen = int(self.headers['content-length']) - except ValueError: - pass - if maxlen and clen > maxlen: - raise ValueError('Maximum content length exceeded') - self.length = clen - if self.limit is None and clen >= 0: - self.limit = clen - - self.list = self.file = None - self.done = 0 - if ctype == 'application/x-www-form-urlencoded': - self.read_urlencoded() - elif ctype[:10] == 'multipart/': - self.read_multi(environ, keep_blank_values, strict_parsing) - else: - self.read_single() - - def __del__(self): - try: - self.file.close() - except AttributeError: - pass - - def __enter__(self): - return self - - def __exit__(self, *args): - self.file.close() - - def __repr__(self): - """Return a printable representation.""" - return "FieldStorage(%r, %r, %r)" % ( - self.name, self.filename, self.value) - - def __iter__(self): - return iter(self.keys()) - - def __getattr__(self, name): - if name != 'value': - raise AttributeError(name) - if self.file: - self.file.seek(0) - value = self.file.read() - self.file.seek(0) - elif self.list is not None: - value = self.list - else: - value = None - return value - - def __getitem__(self, key): - """Dictionary style indexing.""" - if self.list is None: - raise TypeError("not indexable") - found = [] - for item in self.list: - if item.name == key: found.append(item) - if not found: - raise KeyError(key) - if len(found) == 1: - return found[0] - else: - return found - - def getvalue(self, key, default=None): - """Dictionary style get() method, including 'value' lookup.""" - if key in self: - value = self[key] - if isinstance(value, list): - return [x.value for x in value] - else: - return value.value - else: - return default - - def getfirst(self, key, default=None): - """ Return the first value received.""" - if key in self: - value = self[key] - if isinstance(value, list): - return value[0].value - else: - return value.value - else: - return default - - def getlist(self, key): - """ Return list of received values.""" - if key in self: - value = self[key] - if isinstance(value, list): - return [x.value for x in value] - else: - return [value.value] - else: - return [] - - def keys(self): - """Dictionary style keys() method.""" - if self.list is None: - raise TypeError("not indexable") - return list(set(item.name for item in self.list)) - - def __contains__(self, key): - """Dictionary style __contains__ method.""" - if self.list is None: - raise TypeError("not indexable") - return any(item.name == key for item in self.list) - - def __len__(self): - """Dictionary style len(x) support.""" - return len(self.keys()) - - def __bool__(self): - if self.list is None: - raise TypeError("Cannot be converted to bool.") - return bool(self.list) - - def read_urlencoded(self): - """Internal: read data in query string format.""" - qs = self.fp.read(self.length) - if not isinstance(qs, bytes): - raise ValueError("%s should return bytes, got %s" \ - % (self.fp, type(qs).__name__)) - qs = qs.decode(self.encoding, self.errors) - if self.qs_on_post: - qs += '&' + self.qs_on_post - query = urllib.parse.parse_qsl( - qs, self.keep_blank_values, self.strict_parsing, - encoding=self.encoding, errors=self.errors, - max_num_fields=self.max_num_fields, separator=self.separator) - self.list = [MiniFieldStorage(key, value) for key, value in query] - self.skip_lines() - - FieldStorageClass = None - - def read_multi(self, environ, keep_blank_values, strict_parsing): - """Internal: read a part that is itself multipart.""" - ib = self.innerboundary - if not valid_boundary(ib): - raise ValueError('Invalid boundary in multipart form: %r' % (ib,)) - self.list = [] - if self.qs_on_post: - query = urllib.parse.parse_qsl( - self.qs_on_post, self.keep_blank_values, self.strict_parsing, - encoding=self.encoding, errors=self.errors, - max_num_fields=self.max_num_fields, separator=self.separator) - self.list.extend(MiniFieldStorage(key, value) for key, value in query) - - klass = self.FieldStorageClass or self.__class__ - first_line = self.fp.readline() # bytes - if not isinstance(first_line, bytes): - raise ValueError("%s should return bytes, got %s" \ - % (self.fp, type(first_line).__name__)) - self.bytes_read += len(first_line) - - # Ensure that we consume the file until we've hit our inner boundary - while (first_line.strip() != (b"--" + self.innerboundary) and - first_line): - first_line = self.fp.readline() - self.bytes_read += len(first_line) - - # Propagate max_num_fields into the sub class appropriately - max_num_fields = self.max_num_fields - if max_num_fields is not None: - max_num_fields -= len(self.list) - - while True: - parser = FeedParser() - hdr_text = b"" - while True: - data = self.fp.readline() - hdr_text += data - if not data.strip(): - break - if not hdr_text: - break - # parser takes strings, not bytes - self.bytes_read += len(hdr_text) - parser.feed(hdr_text.decode(self.encoding, self.errors)) - headers = parser.close() - - # Some clients add Content-Length for part headers, ignore them - if 'content-length' in headers: - del headers['content-length'] - - limit = None if self.limit is None \ - else self.limit - self.bytes_read - part = klass(self.fp, headers, ib, environ, keep_blank_values, - strict_parsing, limit, - self.encoding, self.errors, max_num_fields, self.separator) - - if max_num_fields is not None: - max_num_fields -= 1 - if part.list: - max_num_fields -= len(part.list) - if max_num_fields < 0: - raise ValueError('Max number of fields exceeded') - - self.bytes_read += part.bytes_read - self.list.append(part) - if part.done or self.bytes_read >= self.length > 0: - break - self.skip_lines() - - def read_single(self): - """Internal: read an atomic part.""" - if self.length >= 0: - self.read_binary() - self.skip_lines() - else: - self.read_lines() - self.file.seek(0) - - bufsize = 8*1024 # I/O buffering size for copy to file - - def read_binary(self): - """Internal: read binary data.""" - self.file = self.make_file() - todo = self.length - if todo >= 0: - while todo > 0: - data = self.fp.read(min(todo, self.bufsize)) # bytes - if not isinstance(data, bytes): - raise ValueError("%s should return bytes, got %s" - % (self.fp, type(data).__name__)) - self.bytes_read += len(data) - if not data: - self.done = -1 - break - self.file.write(data) - todo = todo - len(data) - - def read_lines(self): - """Internal: read lines until EOF or outerboundary.""" - if self._binary_file: - self.file = self.__file = BytesIO() # store data as bytes for files - else: - self.file = self.__file = StringIO() # as strings for other fields - if self.outerboundary: - self.read_lines_to_outerboundary() - else: - self.read_lines_to_eof() - - def __write(self, line): - """line is always bytes, not string""" - if self.__file is not None: - if self.__file.tell() + len(line) > 1000: - self.file = self.make_file() - data = self.__file.getvalue() - self.file.write(data) - self.__file = None - if self._binary_file: - # keep bytes - self.file.write(line) - else: - # decode to string - self.file.write(line.decode(self.encoding, self.errors)) - - def read_lines_to_eof(self): - """Internal: read lines until EOF.""" - while 1: - line = self.fp.readline(1<<16) # bytes - self.bytes_read += len(line) - if not line: - self.done = -1 - break - self.__write(line) - - def read_lines_to_outerboundary(self): - """Internal: read lines until outerboundary. - Data is read as bytes: boundaries and line ends must be converted - to bytes for comparisons. - """ - next_boundary = b"--" + self.outerboundary - last_boundary = next_boundary + b"--" - delim = b"" - last_line_lfend = True - _read = 0 - while 1: - - if self.limit is not None and 0 <= self.limit <= _read: - break - line = self.fp.readline(1<<16) # bytes - self.bytes_read += len(line) - _read += len(line) - if not line: - self.done = -1 - break - if delim == b"\r": - line = delim + line - delim = b"" - if line.startswith(b"--") and last_line_lfend: - strippedline = line.rstrip() - if strippedline == next_boundary: - break - if strippedline == last_boundary: - self.done = 1 - break - odelim = delim - if line.endswith(b"\r\n"): - delim = b"\r\n" - line = line[:-2] - last_line_lfend = True - elif line.endswith(b"\n"): - delim = b"\n" - line = line[:-1] - last_line_lfend = True - elif line.endswith(b"\r"): - # We may interrupt \r\n sequences if they span the 2**16 - # byte boundary - delim = b"\r" - line = line[:-1] - last_line_lfend = False - else: - delim = b"" - last_line_lfend = False - self.__write(odelim + line) - - def skip_lines(self): - """Internal: skip lines until outer boundary if defined.""" - if not self.outerboundary or self.done: - return - next_boundary = b"--" + self.outerboundary - last_boundary = next_boundary + b"--" - last_line_lfend = True - while True: - line = self.fp.readline(1<<16) - self.bytes_read += len(line) - if not line: - self.done = -1 - break - if line.endswith(b"--") and last_line_lfend: - strippedline = line.strip() - if strippedline == next_boundary: - break - if strippedline == last_boundary: - self.done = 1 - break - last_line_lfend = line.endswith(b'\n') - - def make_file(self): - """Overridable: return a readable & writable file. - - The file will be used as follows: - - data is written to it - - seek(0) - - data is read from it - - The file is opened in binary mode for files, in text mode - for other fields - - This version opens a temporary file for reading and writing, - and immediately deletes (unlinks) it. The trick (on Unix!) is - that the file can still be used, but it can't be opened by - another process, and it will automatically be deleted when it - is closed or when the current process terminates. - - If you want a more permanent file, you derive a class which - overrides this method. If you want a visible temporary file - that is nevertheless automatically deleted when the script - terminates, try defining a __del__ method in a derived class - which unlinks the temporary files you have created. - - """ - if self._binary_file: - return tempfile.TemporaryFile("wb+") - else: - return tempfile.TemporaryFile("w+", - encoding=self.encoding, newline = '\n') - - -# Test/debug code -# =============== - -def test(environ=os.environ): - """Robust test CGI script, usable as main program. - - Write minimal HTTP headers and dump all information provided to - the script in HTML form. - - """ - print("Content-type: text/html") - print() - sys.stderr = sys.stdout - try: - form = FieldStorage() # Replace with other classes to test those - print_directory() - print_arguments() - print_form(form) - print_environ(environ) - print_environ_usage() - def f(): - exec("testing print_exception() -- italics?") - def g(f=f): - f() - print("

What follows is a test, not an actual exception:

") - g() - except: - print_exception() - - print("

Second try with a small maxlen...

") - - global maxlen - maxlen = 50 - try: - form = FieldStorage() # Replace with other classes to test those - print_directory() - print_arguments() - print_form(form) - print_environ(environ) - except: - print_exception() - -def print_exception(type=None, value=None, tb=None, limit=None): - if type is None: - type, value, tb = sys.exc_info() - import traceback - print() - print("

Traceback (most recent call last):

") - list = traceback.format_tb(tb, limit) + \ - traceback.format_exception_only(type, value) - print("
%s%s
" % ( - html.escape("".join(list[:-1])), - html.escape(list[-1]), - )) - del tb - -def print_environ(environ=os.environ): - """Dump the shell environment as HTML.""" - keys = sorted(environ.keys()) - print() - print("

Shell Environment:

") - print("
") - for key in keys: - print("
", html.escape(key), "
", html.escape(environ[key])) - print("
") - print() - -def print_form(form): - """Dump the contents of a form as HTML.""" - keys = sorted(form.keys()) - print() - print("

Form Contents:

") - if not keys: - print("

No form fields.") - print("

") - for key in keys: - print("
" + html.escape(key) + ":", end=' ') - value = form[key] - print("" + html.escape(repr(type(value))) + "") - print("
" + html.escape(repr(value))) - print("
") - print() - -def print_directory(): - """Dump the current directory as HTML.""" - print() - print("

Current Working Directory:

") - try: - pwd = os.getcwd() - except OSError as msg: - print("OSError:", html.escape(str(msg))) - else: - print(html.escape(pwd)) - print() - -def print_arguments(): - print() - print("

Command Line Arguments:

") - print() - print(sys.argv) - print() - -def print_environ_usage(): - """Dump a list of environment variables used by CGI as HTML.""" - print(""" -

These environment variables could have been set:

-
    -
  • AUTH_TYPE -
  • CONTENT_LENGTH -
  • CONTENT_TYPE -
  • DATE_GMT -
  • DATE_LOCAL -
  • DOCUMENT_NAME -
  • DOCUMENT_ROOT -
  • DOCUMENT_URI -
  • GATEWAY_INTERFACE -
  • LAST_MODIFIED -
  • PATH -
  • PATH_INFO -
  • PATH_TRANSLATED -
  • QUERY_STRING -
  • REMOTE_ADDR -
  • REMOTE_HOST -
  • REMOTE_IDENT -
  • REMOTE_USER -
  • REQUEST_METHOD -
  • SCRIPT_NAME -
  • SERVER_NAME -
  • SERVER_PORT -
  • SERVER_PROTOCOL -
  • SERVER_ROOT -
  • SERVER_SOFTWARE -
-In addition, HTTP headers sent by the server may be passed in the -environment as well. Here are some common variable names: -
    -
  • HTTP_ACCEPT -
  • HTTP_CONNECTION -
  • HTTP_HOST -
  • HTTP_PRAGMA -
  • HTTP_REFERER -
  • HTTP_USER_AGENT -
-""") - - -# Utilities -# ========= - -def valid_boundary(s): - import re - if isinstance(s, bytes): - _vb_pattern = b"^[ -~]{0,200}[!-~]$" - else: - _vb_pattern = "^[ -~]{0,200}[!-~]$" - return re.match(_vb_pattern, s) - -# Invoke mainline -# =============== - -# Call test() when this file is run as a script (not imported as a module) -if __name__ == '__main__': - test() diff --git a/Lib/cgitb.py b/Lib/cgitb.py deleted file mode 100644 index f6b97f25c59d..000000000000 --- a/Lib/cgitb.py +++ /dev/null @@ -1,332 +0,0 @@ -"""More comprehensive traceback formatting for Python scripts. - -To enable this module, do: - - import cgitb; cgitb.enable() - -at the top of your script. The optional arguments to enable() are: - - display - if true, tracebacks are displayed in the web browser - logdir - if set, tracebacks are written to files in this directory - context - number of lines of source code to show for each stack frame - format - 'text' or 'html' controls the output format - -By default, tracebacks are displayed but not saved, the context is 5 lines -and the output format is 'html' (for backwards compatibility with the -original use of this module) - -Alternatively, if you have caught an exception and want cgitb to display it -for you, call cgitb.handler(). The optional argument to handler() is a -3-item tuple (etype, evalue, etb) just like the value of sys.exc_info(). -The default handler displays output as HTML. - -""" -import inspect -import keyword -import linecache -import os -import pydoc -import sys -import tempfile -import time -import tokenize -import traceback -import warnings -from html import escape as html_escape - -warnings._deprecated(__name__, remove=(3, 13)) - - -def reset(): - """Return a string that resets the CGI and browser to a known state.""" - return ''' - --> --> - - ''' - -__UNDEF__ = [] # a special sentinel object -def small(text): - if text: - return '' + text + '' - else: - return '' - -def strong(text): - if text: - return '' + text + '' - else: - return '' - -def grey(text): - if text: - return '' + text + '' - else: - return '' - -def lookup(name, frame, locals): - """Find the value for a given name in the given environment.""" - if name in locals: - return 'local', locals[name] - if name in frame.f_globals: - return 'global', frame.f_globals[name] - if '__builtins__' in frame.f_globals: - builtins = frame.f_globals['__builtins__'] - if isinstance(builtins, dict): - if name in builtins: - return 'builtin', builtins[name] - else: - if hasattr(builtins, name): - return 'builtin', getattr(builtins, name) - return None, __UNDEF__ - -def scanvars(reader, frame, locals): - """Scan one logical line of Python and look up values of variables used.""" - vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__ - for ttype, token, start, end, line in tokenize.generate_tokens(reader): - if ttype == tokenize.NEWLINE: break - if ttype == tokenize.NAME and token not in keyword.kwlist: - if lasttoken == '.': - if parent is not __UNDEF__: - value = getattr(parent, token, __UNDEF__) - vars.append((prefix + token, prefix, value)) - else: - where, value = lookup(token, frame, locals) - vars.append((token, where, value)) - elif token == '.': - prefix += lasttoken + '.' - parent = value - else: - parent, prefix = None, '' - lasttoken = token - return vars - -def html(einfo, context=5): - """Return a nice HTML document describing a given traceback.""" - etype, evalue, etb = einfo - if isinstance(etype, type): - etype = etype.__name__ - pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable - date = time.ctime(time.time()) - head = f''' - - - - - -
 
- 
-{html_escape(str(etype))}
-{pyver}
{date}
-

A problem occurred in a Python script. Here is the sequence of -function calls leading up to the error, in the order they occurred.

''' - - indent = '' + small(' ' * 5) + ' ' - frames = [] - records = inspect.getinnerframes(etb, context) - for frame, file, lnum, func, lines, index in records: - if file: - file = os.path.abspath(file) - link = '%s' % (file, pydoc.html.escape(file)) - else: - file = link = '?' - args, varargs, varkw, locals = inspect.getargvalues(frame) - call = '' - if func != '?': - call = 'in ' + strong(pydoc.html.escape(func)) - if func != "": - call += inspect.formatargvalues(args, varargs, varkw, locals, - formatvalue=lambda value: '=' + pydoc.html.repr(value)) - - highlight = {} - def reader(lnum=[lnum]): - highlight[lnum[0]] = 1 - try: return linecache.getline(file, lnum[0]) - finally: lnum[0] += 1 - vars = scanvars(reader, frame, locals) - - rows = ['%s%s %s' % - (' ', link, call)] - if index is not None: - i = lnum - index - for line in lines: - num = small(' ' * (5-len(str(i))) + str(i)) + ' ' - if i in highlight: - line = '=>%s%s' % (num, pydoc.html.preformat(line)) - rows.append('%s' % line) - else: - line = '  %s%s' % (num, pydoc.html.preformat(line)) - rows.append('%s' % grey(line)) - i += 1 - - done, dump = {}, [] - for name, where, value in vars: - if name in done: continue - done[name] = 1 - if value is not __UNDEF__: - if where in ('global', 'builtin'): - name = ('%s ' % where) + strong(name) - elif where == 'local': - name = strong(name) - else: - name = where + strong(name.split('.')[-1]) - dump.append('%s = %s' % (name, pydoc.html.repr(value))) - else: - dump.append(name + ' undefined') - - rows.append('%s' % small(grey(', '.join(dump)))) - frames.append(''' - -%s
''' % '\n'.join(rows)) - - exception = ['

%s: %s' % (strong(pydoc.html.escape(str(etype))), - pydoc.html.escape(str(evalue)))] - for name in dir(evalue): - if name[:1] == '_': continue - value = pydoc.html.repr(getattr(evalue, name)) - exception.append('\n
%s%s =\n%s' % (indent, name, value)) - - return head + ''.join(frames) + ''.join(exception) + ''' - - - -''' % pydoc.html.escape( - ''.join(traceback.format_exception(etype, evalue, etb))) - -def text(einfo, context=5): - """Return a plain text document describing a given traceback.""" - etype, evalue, etb = einfo - if isinstance(etype, type): - etype = etype.__name__ - pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable - date = time.ctime(time.time()) - head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + ''' -A problem occurred in a Python script. Here is the sequence of -function calls leading up to the error, in the order they occurred. -''' - - frames = [] - records = inspect.getinnerframes(etb, context) - for frame, file, lnum, func, lines, index in records: - file = file and os.path.abspath(file) or '?' - args, varargs, varkw, locals = inspect.getargvalues(frame) - call = '' - if func != '?': - call = 'in ' + func - if func != "": - call += inspect.formatargvalues(args, varargs, varkw, locals, - formatvalue=lambda value: '=' + pydoc.text.repr(value)) - - highlight = {} - def reader(lnum=[lnum]): - highlight[lnum[0]] = 1 - try: return linecache.getline(file, lnum[0]) - finally: lnum[0] += 1 - vars = scanvars(reader, frame, locals) - - rows = [' %s %s' % (file, call)] - if index is not None: - i = lnum - index - for line in lines: - num = '%5d ' % i - rows.append(num+line.rstrip()) - i += 1 - - done, dump = {}, [] - for name, where, value in vars: - if name in done: continue - done[name] = 1 - if value is not __UNDEF__: - if where == 'global': name = 'global ' + name - elif where != 'local': name = where + name.split('.')[-1] - dump.append('%s = %s' % (name, pydoc.text.repr(value))) - else: - dump.append(name + ' undefined') - - rows.append('\n'.join(dump)) - frames.append('\n%s\n' % '\n'.join(rows)) - - exception = ['%s: %s' % (str(etype), str(evalue))] - for name in dir(evalue): - value = pydoc.text.repr(getattr(evalue, name)) - exception.append('\n%s%s = %s' % (" "*4, name, value)) - - return head + ''.join(frames) + ''.join(exception) + ''' - -The above is a description of an error in a Python program. Here is -the original traceback: - -%s -''' % ''.join(traceback.format_exception(etype, evalue, etb)) - -class Hook: - """A hook to replace sys.excepthook that shows tracebacks in HTML.""" - - def __init__(self, display=1, logdir=None, context=5, file=None, - format="html"): - self.display = display # send tracebacks to browser if true - self.logdir = logdir # log tracebacks to files if not None - self.context = context # number of source code lines per frame - self.file = file or sys.stdout # place to send the output - self.format = format - - def __call__(self, etype, evalue, etb): - self.handle((etype, evalue, etb)) - - def handle(self, info=None): - info = info or sys.exc_info() - if self.format == "html": - self.file.write(reset()) - - formatter = (self.format=="html") and html or text - plain = False - try: - doc = formatter(info, self.context) - except: # just in case something goes wrong - doc = ''.join(traceback.format_exception(*info)) - plain = True - - if self.display: - if plain: - doc = pydoc.html.escape(doc) - self.file.write('

' + doc + '
\n') - else: - self.file.write(doc + '\n') - else: - self.file.write('

A problem occurred in a Python script.\n') - - if self.logdir is not None: - suffix = ['.txt', '.html'][self.format=="html"] - (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir) - - try: - with os.fdopen(fd, 'w') as file: - file.write(doc) - msg = '%s contains the description of this error.' % path - except: - msg = 'Tried to save traceback to %s, but failed.' % path - - if self.format == 'html': - self.file.write('

%s

\n' % msg) - else: - self.file.write(msg + '\n') - try: - self.file.flush() - except: pass - -handler = Hook().handle -def enable(display=1, logdir=None, context=5, format="html"): - """Install an exception handler that formats tracebacks as HTML. - - The optional argument 'display' can be set to 0 to suppress sending the - traceback to the browser, and 'logdir' can be set to a directory to cause - tracebacks to be written to files there.""" - sys.excepthook = Hook(display=display, logdir=logdir, - context=context, format=format) diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py deleted file mode 100644 index 24486e4d95a7..000000000000 --- a/Lib/test/test_cgi.py +++ /dev/null @@ -1,641 +0,0 @@ -import os -import sys -import tempfile -import unittest -from collections import namedtuple -from io import StringIO, BytesIO -from test import support -from test.support import warnings_helper - -cgi = warnings_helper.import_deprecated("cgi") - - -class HackedSysModule: - # The regression test will have real values in sys.argv, which - # will completely confuse the test of the cgi module - argv = [] - stdin = sys.stdin - -cgi.sys = HackedSysModule() - -class ComparableException: - def __init__(self, err): - self.err = err - - def __str__(self): - return str(self.err) - - def __eq__(self, anExc): - if not isinstance(anExc, Exception): - return NotImplemented - return (self.err.__class__ == anExc.__class__ and - self.err.args == anExc.args) - - def __getattr__(self, attr): - return getattr(self.err, attr) - -def do_test(buf, method): - env = {} - if method == "GET": - fp = None - env['REQUEST_METHOD'] = 'GET' - env['QUERY_STRING'] = buf - elif method == "POST": - fp = BytesIO(buf.encode('latin-1')) # FieldStorage expects bytes - env['REQUEST_METHOD'] = 'POST' - env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' - env['CONTENT_LENGTH'] = str(len(buf)) - else: - raise ValueError("unknown method: %s" % method) - try: - return cgi.parse(fp, env, strict_parsing=1) - except Exception as err: - return ComparableException(err) - -parse_strict_test_cases = [ - ("", {}), - ("&", ValueError("bad query field: ''")), - ("&&", ValueError("bad query field: ''")), - # Should the next few really be valid? - ("=", {}), - ("=&=", {}), - # This rest seem to make sense - ("=a", {'': ['a']}), - ("&=a", ValueError("bad query field: ''")), - ("=a&", ValueError("bad query field: ''")), - ("=&a", ValueError("bad query field: 'a'")), - ("b=a", {'b': ['a']}), - ("b+=a", {'b ': ['a']}), - ("a=b=a", {'a': ['b=a']}), - ("a=+b=a", {'a': [' b=a']}), - ("&b=a", ValueError("bad query field: ''")), - ("b&=a", ValueError("bad query field: 'b'")), - ("a=a+b&b=b+c", {'a': ['a b'], 'b': ['b c']}), - ("a=a+b&a=b+a", {'a': ['a b', 'b a']}), - ("x=1&y=2.0&z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), - ("Hbc5161168c542333633315dee1182227:key_store_seqid=400006&cuyer=r&view=bustomer&order_id=0bb2e248638833d48cb7fed300000f1b&expire=964546263&lobale=en-US&kid=130003.300038&ss=env", - {'Hbc5161168c542333633315dee1182227:key_store_seqid': ['400006'], - 'cuyer': ['r'], - 'expire': ['964546263'], - 'kid': ['130003.300038'], - 'lobale': ['en-US'], - 'order_id': ['0bb2e248638833d48cb7fed300000f1b'], - 'ss': ['env'], - 'view': ['bustomer'], - }), - - ("group_id=5470&set=custom&_assigned_to=31392&_status=1&_category=100&SUBMIT=Browse", - {'SUBMIT': ['Browse'], - '_assigned_to': ['31392'], - '_category': ['100'], - '_status': ['1'], - 'group_id': ['5470'], - 'set': ['custom'], - }) - ] - -def norm(seq): - return sorted(seq, key=repr) - -def first_elts(list): - return [p[0] for p in list] - -def first_second_elts(list): - return [(p[0], p[1][0]) for p in list] - -def gen_result(data, environ): - encoding = 'latin-1' - fake_stdin = BytesIO(data.encode(encoding)) - fake_stdin.seek(0) - form = cgi.FieldStorage(fp=fake_stdin, environ=environ, encoding=encoding) - - result = {} - for k, v in dict(form).items(): - result[k] = isinstance(v, list) and form.getlist(k) or v.value - - return result - -class CgiTests(unittest.TestCase): - - def test_parse_multipart(self): - fp = BytesIO(POSTDATA.encode('latin1')) - env = {'boundary': BOUNDARY.encode('latin1'), - 'CONTENT-LENGTH': '558'} - result = cgi.parse_multipart(fp, env) - expected = {'submit': [' Add '], 'id': ['1234'], - 'file': [b'Testing 123.\n'], 'title': ['']} - self.assertEqual(result, expected) - - def test_parse_multipart_without_content_length(self): - POSTDATA = '''--JfISa01 -Content-Disposition: form-data; name="submit-name" - -just a string - ---JfISa01-- -''' - fp = BytesIO(POSTDATA.encode('latin1')) - env = {'boundary': 'JfISa01'.encode('latin1')} - result = cgi.parse_multipart(fp, env) - expected = {'submit-name': ['just a string\n']} - self.assertEqual(result, expected) - - def test_parse_multipart_invalid_encoding(self): - BOUNDARY = "JfISa01" - POSTDATA = """--JfISa01 -Content-Disposition: form-data; name="submit-name" -Content-Length: 3 - -\u2603 ---JfISa01""" - fp = BytesIO(POSTDATA.encode('utf8')) - env = {'boundary': BOUNDARY.encode('latin1'), - 'CONTENT-LENGTH': str(len(POSTDATA.encode('utf8')))} - result = cgi.parse_multipart(fp, env, encoding="ascii", - errors="surrogateescape") - expected = {'submit-name': ["\udce2\udc98\udc83"]} - self.assertEqual(result, expected) - self.assertEqual("\u2603".encode('utf8'), - result["submit-name"][0].encode('utf8', 'surrogateescape')) - - def test_fieldstorage_properties(self): - fs = cgi.FieldStorage() - self.assertFalse(fs) - self.assertIn("FieldStorage", repr(fs)) - self.assertEqual(list(fs), list(fs.keys())) - fs.list.append(namedtuple('MockFieldStorage', 'name')('fieldvalue')) - self.assertTrue(fs) - - def test_fieldstorage_invalid(self): - self.assertRaises(TypeError, cgi.FieldStorage, "not-a-file-obj", - environ={"REQUEST_METHOD":"PUT"}) - self.assertRaises(TypeError, cgi.FieldStorage, "foo", "bar") - fs = cgi.FieldStorage(headers={'content-type':'text/plain'}) - self.assertRaises(TypeError, bool, fs) - - def test_strict(self): - for orig, expect in parse_strict_test_cases: - # Test basic parsing - d = do_test(orig, "GET") - self.assertEqual(d, expect, "Error parsing %s method GET" % repr(orig)) - d = do_test(orig, "POST") - self.assertEqual(d, expect, "Error parsing %s method POST" % repr(orig)) - - env = {'QUERY_STRING': orig} - fs = cgi.FieldStorage(environ=env) - if isinstance(expect, dict): - # test dict interface - self.assertEqual(len(expect), len(fs)) - self.assertCountEqual(expect.keys(), fs.keys()) - ##self.assertEqual(norm(expect.values()), norm(fs.values())) - ##self.assertEqual(norm(expect.items()), norm(fs.items())) - self.assertEqual(fs.getvalue("nonexistent field", "default"), "default") - # test individual fields - for key in expect.keys(): - expect_val = expect[key] - self.assertIn(key, fs) - if len(expect_val) > 1: - self.assertEqual(fs.getvalue(key), expect_val) - else: - self.assertEqual(fs.getvalue(key), expect_val[0]) - - def test_separator(self): - parse_semicolon = [ - ("x=1;y=2.0", {'x': ['1'], 'y': ['2.0']}), - ("x=1;y=2.0;z=2-3.%2b0", {'x': ['1'], 'y': ['2.0'], 'z': ['2-3.+0']}), - (";", ValueError("bad query field: ''")), - (";;", ValueError("bad query field: ''")), - ("=;a", ValueError("bad query field: 'a'")), - (";b=a", ValueError("bad query field: ''")), - ("b;=a", ValueError("bad query field: 'b'")), - ("a=a+b;b=b+c", {'a': ['a b'], 'b': ['b c']}), - ("a=a+b;a=b+a", {'a': ['a b', 'b a']}), - ] - for orig, expect in parse_semicolon: - env = {'QUERY_STRING': orig} - fs = cgi.FieldStorage(separator=';', environ=env) - if isinstance(expect, dict): - for key in expect.keys(): - expect_val = expect[key] - self.assertIn(key, fs) - if len(expect_val) > 1: - self.assertEqual(fs.getvalue(key), expect_val) - else: - self.assertEqual(fs.getvalue(key), expect_val[0]) - - @warnings_helper.ignore_warnings(category=DeprecationWarning) - def test_log(self): - cgi.log("Testing") - - cgi.logfp = StringIO() - cgi.initlog("%s", "Testing initlog 1") - cgi.log("%s", "Testing log 2") - self.assertEqual(cgi.logfp.getvalue(), "Testing initlog 1\nTesting log 2\n") - if os.path.exists(os.devnull): - cgi.logfp = None - cgi.logfile = os.devnull - cgi.initlog("%s", "Testing log 3") - self.addCleanup(cgi.closelog) - cgi.log("Testing log 4") - - def test_fieldstorage_readline(self): - # FieldStorage uses readline, which has the capacity to read all - # contents of the input file into memory; we use readline's size argument - # to prevent that for files that do not contain any newlines in - # non-GET/HEAD requests - class TestReadlineFile: - def __init__(self, file): - self.file = file - self.numcalls = 0 - - def readline(self, size=None): - self.numcalls += 1 - if size: - return self.file.readline(size) - else: - return self.file.readline() - - def __getattr__(self, name): - file = self.__dict__['file'] - a = getattr(file, name) - if not isinstance(a, int): - setattr(self, name, a) - return a - - f = TestReadlineFile(tempfile.TemporaryFile("wb+")) - self.addCleanup(f.close) - f.write(b'x' * 256 * 1024) - f.seek(0) - env = {'REQUEST_METHOD':'PUT'} - fs = cgi.FieldStorage(fp=f, environ=env) - self.addCleanup(fs.file.close) - # if we're not chunking properly, readline is only called twice - # (by read_binary); if we are chunking properly, it will be called 5 times - # as long as the chunksize is 1 << 16. - self.assertGreater(f.numcalls, 2) - f.close() - - def test_fieldstorage_multipart(self): - #Test basic FieldStorage multipart parsing - env = { - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY), - 'CONTENT_LENGTH': '558'} - fp = BytesIO(POSTDATA.encode('latin-1')) - fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") - self.assertEqual(len(fs.list), 4) - expect = [{'name':'id', 'filename':None, 'value':'1234'}, - {'name':'title', 'filename':None, 'value':''}, - {'name':'file', 'filename':'test.txt', 'value':b'Testing 123.\n'}, - {'name':'submit', 'filename':None, 'value':' Add '}] - for x in range(len(fs.list)): - for k, exp in expect[x].items(): - got = getattr(fs.list[x], k) - self.assertEqual(got, exp) - - def test_fieldstorage_multipart_leading_whitespace(self): - env = { - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY), - 'CONTENT_LENGTH': '560'} - # Add some leading whitespace to our post data that will cause the - # first line to not be the innerboundary. - fp = BytesIO(b"\r\n" + POSTDATA.encode('latin-1')) - fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") - self.assertEqual(len(fs.list), 4) - expect = [{'name':'id', 'filename':None, 'value':'1234'}, - {'name':'title', 'filename':None, 'value':''}, - {'name':'file', 'filename':'test.txt', 'value':b'Testing 123.\n'}, - {'name':'submit', 'filename':None, 'value':' Add '}] - for x in range(len(fs.list)): - for k, exp in expect[x].items(): - got = getattr(fs.list[x], k) - self.assertEqual(got, exp) - - def test_fieldstorage_multipart_non_ascii(self): - #Test basic FieldStorage multipart parsing - env = {'REQUEST_METHOD':'POST', - 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY), - 'CONTENT_LENGTH':'558'} - for encoding in ['iso-8859-1','utf-8']: - fp = BytesIO(POSTDATA_NON_ASCII.encode(encoding)) - fs = cgi.FieldStorage(fp, environ=env,encoding=encoding) - self.assertEqual(len(fs.list), 1) - expect = [{'name':'id', 'filename':None, 'value':'\xe7\xf1\x80'}] - for x in range(len(fs.list)): - for k, exp in expect[x].items(): - got = getattr(fs.list[x], k) - self.assertEqual(got, exp) - - def test_fieldstorage_multipart_maxline(self): - # Issue #18167 - maxline = 1 << 16 - self.maxDiff = None - def check(content): - data = """---123 -Content-Disposition: form-data; name="upload"; filename="fake.txt" -Content-Type: text/plain - -%s ----123-- -""".replace('\n', '\r\n') % content - environ = { - 'CONTENT_LENGTH': str(len(data)), - 'CONTENT_TYPE': 'multipart/form-data; boundary=-123', - 'REQUEST_METHOD': 'POST', - } - self.assertEqual(gen_result(data, environ), - {'upload': content.encode('latin1')}) - check('x' * (maxline - 1)) - check('x' * (maxline - 1) + '\r') - check('x' * (maxline - 1) + '\r' + 'y' * (maxline - 1)) - - def test_fieldstorage_multipart_w3c(self): - # Test basic FieldStorage multipart parsing (W3C sample) - env = { - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY_W3), - 'CONTENT_LENGTH': str(len(POSTDATA_W3))} - fp = BytesIO(POSTDATA_W3.encode('latin-1')) - fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") - self.assertEqual(len(fs.list), 2) - self.assertEqual(fs.list[0].name, 'submit-name') - self.assertEqual(fs.list[0].value, 'Larry') - self.assertEqual(fs.list[1].name, 'files') - files = fs.list[1].value - self.assertEqual(len(files), 2) - expect = [{'name': None, 'filename': 'file1.txt', 'value': b'... contents of file1.txt ...'}, - {'name': None, 'filename': 'file2.gif', 'value': b'...contents of file2.gif...'}] - for x in range(len(files)): - for k, exp in expect[x].items(): - got = getattr(files[x], k) - self.assertEqual(got, exp) - - def test_fieldstorage_part_content_length(self): - BOUNDARY = "JfISa01" - POSTDATA = """--JfISa01 -Content-Disposition: form-data; name="submit-name" -Content-Length: 5 - -Larry ---JfISa01""" - env = { - 'REQUEST_METHOD': 'POST', - 'CONTENT_TYPE': 'multipart/form-data; boundary={}'.format(BOUNDARY), - 'CONTENT_LENGTH': str(len(POSTDATA))} - fp = BytesIO(POSTDATA.encode('latin-1')) - fs = cgi.FieldStorage(fp, environ=env, encoding="latin-1") - self.assertEqual(len(fs.list), 1) - self.assertEqual(fs.list[0].name, 'submit-name') - self.assertEqual(fs.list[0].value, 'Larry') - - def test_field_storage_multipart_no_content_length(self): - fp = BytesIO(b"""--MyBoundary -Content-Disposition: form-data; name="my-arg"; filename="foo" - -Test - ---MyBoundary-- -""") - env = { - "REQUEST_METHOD": "POST", - "CONTENT_TYPE": "multipart/form-data; boundary=MyBoundary", - "wsgi.input": fp, - } - fields = cgi.FieldStorage(fp, environ=env) - - self.assertEqual(len(fields["my-arg"].file.read()), 5) - - def test_fieldstorage_as_context_manager(self): - fp = BytesIO(b'x' * 10) - env = {'REQUEST_METHOD': 'PUT'} - with cgi.FieldStorage(fp=fp, environ=env) as fs: - content = fs.file.read() - self.assertFalse(fs.file.closed) - self.assertTrue(fs.file.closed) - self.assertEqual(content, 'x' * 10) - with self.assertRaisesRegex(ValueError, 'I/O operation on closed file'): - fs.file.read() - - _qs_result = { - 'key1': 'value1', - 'key2': ['value2x', 'value2y'], - 'key3': 'value3', - 'key4': 'value4' - } - def testQSAndUrlEncode(self): - data = "key2=value2x&key3=value3&key4=value4" - environ = { - 'CONTENT_LENGTH': str(len(data)), - 'CONTENT_TYPE': 'application/x-www-form-urlencoded', - 'QUERY_STRING': 'key1=value1&key2=value2y', - 'REQUEST_METHOD': 'POST', - } - v = gen_result(data, environ) - self.assertEqual(self._qs_result, v) - - def test_max_num_fields(self): - # For application/x-www-form-urlencoded - data = '&'.join(['a=a']*11) - environ = { - 'CONTENT_LENGTH': str(len(data)), - 'CONTENT_TYPE': 'application/x-www-form-urlencoded', - 'REQUEST_METHOD': 'POST', - } - - with self.assertRaises(ValueError): - cgi.FieldStorage( - fp=BytesIO(data.encode()), - environ=environ, - max_num_fields=10, - ) - - # For multipart/form-data - data = """---123 -Content-Disposition: form-data; name="a" - -3 ----123 -Content-Type: application/x-www-form-urlencoded - -a=4 ----123 -Content-Type: application/x-www-form-urlencoded - -a=5 ----123-- -""" - environ = { - 'CONTENT_LENGTH': str(len(data)), - 'CONTENT_TYPE': 'multipart/form-data; boundary=-123', - 'QUERY_STRING': 'a=1&a=2', - 'REQUEST_METHOD': 'POST', - } - - # 2 GET entities - # 1 top level POST entities - # 1 entity within the second POST entity - # 1 entity within the third POST entity - with self.assertRaises(ValueError): - cgi.FieldStorage( - fp=BytesIO(data.encode()), - environ=environ, - max_num_fields=4, - ) - cgi.FieldStorage( - fp=BytesIO(data.encode()), - environ=environ, - max_num_fields=5, - ) - - def testQSAndFormData(self): - data = """---123 -Content-Disposition: form-data; name="key2" - -value2y ----123 -Content-Disposition: form-data; name="key3" - -value3 ----123 -Content-Disposition: form-data; name="key4" - -value4 ----123-- -""" - environ = { - 'CONTENT_LENGTH': str(len(data)), - 'CONTENT_TYPE': 'multipart/form-data; boundary=-123', - 'QUERY_STRING': 'key1=value1&key2=value2x', - 'REQUEST_METHOD': 'POST', - } - v = gen_result(data, environ) - self.assertEqual(self._qs_result, v) - - def testQSAndFormDataFile(self): - data = """---123 -Content-Disposition: form-data; name="key2" - -value2y ----123 -Content-Disposition: form-data; name="key3" - -value3 ----123 -Content-Disposition: form-data; name="key4" - -value4 ----123 -Content-Disposition: form-data; name="upload"; filename="fake.txt" -Content-Type: text/plain - -this is the content of the fake file - ----123-- -""" - environ = { - 'CONTENT_LENGTH': str(len(data)), - 'CONTENT_TYPE': 'multipart/form-data; boundary=-123', - 'QUERY_STRING': 'key1=value1&key2=value2x', - 'REQUEST_METHOD': 'POST', - } - result = self._qs_result.copy() - result.update({ - 'upload': b'this is the content of the fake file\n' - }) - v = gen_result(data, environ) - self.assertEqual(result, v) - - def test_parse_header(self): - self.assertEqual( - cgi.parse_header("text/plain"), - ("text/plain", {})) - self.assertEqual( - cgi.parse_header("text/vnd.just.made.this.up ; "), - ("text/vnd.just.made.this.up", {})) - self.assertEqual( - cgi.parse_header("text/plain;charset=us-ascii"), - ("text/plain", {"charset": "us-ascii"})) - self.assertEqual( - cgi.parse_header('text/plain ; charset="us-ascii"'), - ("text/plain", {"charset": "us-ascii"})) - self.assertEqual( - cgi.parse_header('text/plain ; charset="us-ascii"; another=opt'), - ("text/plain", {"charset": "us-ascii", "another": "opt"})) - self.assertEqual( - cgi.parse_header('attachment; filename="silly.txt"'), - ("attachment", {"filename": "silly.txt"})) - self.assertEqual( - cgi.parse_header('attachment; filename="strange;name"'), - ("attachment", {"filename": "strange;name"})) - self.assertEqual( - cgi.parse_header('attachment; filename="strange;name";size=123;'), - ("attachment", {"filename": "strange;name", "size": "123"})) - self.assertEqual( - cgi.parse_header('form-data; name="files"; filename="fo\\"o;bar"'), - ("form-data", {"name": "files", "filename": 'fo"o;bar'})) - - def test_all(self): - not_exported = { - "logfile", "logfp", "initlog", "dolog", "nolog", "closelog", "log", - "maxlen", "valid_boundary"} - support.check__all__(self, cgi, not_exported=not_exported) - - -BOUNDARY = "---------------------------721837373350705526688164684" - -POSTDATA = """-----------------------------721837373350705526688164684 -Content-Disposition: form-data; name="id" - -1234 ------------------------------721837373350705526688164684 -Content-Disposition: form-data; name="title" - - ------------------------------721837373350705526688164684 -Content-Disposition: form-data; name="file"; filename="test.txt" -Content-Type: text/plain - -Testing 123. - ------------------------------721837373350705526688164684 -Content-Disposition: form-data; name="submit" - - Add\x20 ------------------------------721837373350705526688164684-- -""" - -POSTDATA_NON_ASCII = """-----------------------------721837373350705526688164684 -Content-Disposition: form-data; name="id" - -\xe7\xf1\x80 ------------------------------721837373350705526688164684 -""" - -# http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 -BOUNDARY_W3 = "AaB03x" -POSTDATA_W3 = """--AaB03x -Content-Disposition: form-data; name="submit-name" - -Larry ---AaB03x -Content-Disposition: form-data; name="files" -Content-Type: multipart/mixed; boundary=BbC04y - ---BbC04y -Content-Disposition: file; filename="file1.txt" -Content-Type: text/plain - -... contents of file1.txt ... ---BbC04y -Content-Disposition: file; filename="file2.gif" -Content-Type: image/gif -Content-Transfer-Encoding: binary - -...contents of file2.gif... ---BbC04y-- ---AaB03x-- -""" - -if __name__ == '__main__': - unittest.main() diff --git a/Lib/test/test_cgitb.py b/Lib/test/test_cgitb.py deleted file mode 100644 index 501c7fcce28e..000000000000 --- a/Lib/test/test_cgitb.py +++ /dev/null @@ -1,71 +0,0 @@ -from test.support.os_helper import temp_dir -from test.support.script_helper import assert_python_failure -from test.support.warnings_helper import import_deprecated -import unittest -import sys -cgitb = import_deprecated("cgitb") - -class TestCgitb(unittest.TestCase): - - def test_fonts(self): - text = "Hello Robbie!" - self.assertEqual(cgitb.small(text), "{}".format(text)) - self.assertEqual(cgitb.strong(text), "{}".format(text)) - self.assertEqual(cgitb.grey(text), - '{}'.format(text)) - - def test_blanks(self): - self.assertEqual(cgitb.small(""), "") - self.assertEqual(cgitb.strong(""), "") - self.assertEqual(cgitb.grey(""), "") - - def test_html(self): - try: - raise ValueError("Hello World") - except ValueError as err: - # If the html was templated we could do a bit more here. - # At least check that we get details on what we just raised. - html = cgitb.html(sys.exc_info()) - self.assertIn("ValueError", html) - self.assertIn(str(err), html) - - def test_text(self): - try: - raise ValueError("Hello World") - except ValueError: - text = cgitb.text(sys.exc_info()) - self.assertIn("ValueError", text) - self.assertIn("Hello World", text) - - def test_syshook_no_logdir_default_format(self): - with temp_dir() as tracedir: - rc, out, err = assert_python_failure( - '-c', - ('import cgitb; cgitb.enable(logdir=%s); ' - 'raise ValueError("Hello World")') % repr(tracedir), - PYTHONIOENCODING='utf-8') - out = out.decode() - self.assertIn("ValueError", out) - self.assertIn("Hello World", out) - self.assertIn("<module>", out) - # By default we emit HTML markup. - self.assertIn('

', out) - self.assertIn('

', out) - - def test_syshook_no_logdir_text_format(self): - # Issue 12890: we were emitting the

tag in text mode. - with temp_dir() as tracedir: - rc, out, err = assert_python_failure( - '-c', - ('import cgitb; cgitb.enable(format="text", logdir=%s); ' - 'raise ValueError("Hello World")') % repr(tracedir), - PYTHONIOENCODING='utf-8') - out = out.decode() - self.assertIn("ValueError", out) - self.assertIn("Hello World", out) - self.assertNotIn('

', out) - self.assertNotIn('

', out) - - -if __name__ == "__main__": - unittest.main() diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py index 23453e340159..c7c5419ffe3e 100644 --- a/Lib/test/test_pyclbr.py +++ b/Lib/test/test_pyclbr.py @@ -219,9 +219,6 @@ def test_others(self): # These were once some of the longest modules. cm('random', ignore=('Random',)) # from _random import Random as CoreGenerator - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - cm('cgi', ignore=('log',)) # set with = in module cm('pickle', ignore=('partial', 'PickleBuffer')) with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst index 7da438597318..94c3a37de8ee 100644 --- a/Misc/NEWS.d/3.9.0a1.rst +++ b/Misc/NEWS.d/3.9.0a1.rst @@ -3457,7 +3457,7 @@ Patch contributed by R?mi Lapeyre. .. nonce: kG0ub5 .. section: Library -Fixes a bug in :mod:`cgi` module when a multipart/form-data request has no +Fixes a bug in :mod:`!cgi` module when a multipart/form-data request has no `Content-Length` header. .. diff --git a/Misc/NEWS.d/next/Library/2023-05-23-01-47-57.gh-issue-104773.I6MQhb.rst b/Misc/NEWS.d/next/Library/2023-05-23-01-47-57.gh-issue-104773.I6MQhb.rst new file mode 100644 index 000000000000..42f7a5286867 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-01-47-57.gh-issue-104773.I6MQhb.rst @@ -0,0 +1,2 @@ +:pep:`594`: Remove the :mod:`!cgi`` and :mod:`!cgitb` modules, deprecated in +Python 3.11. Patch by Victor Stinner. diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index b926caf4a579..f5defe8923b2 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -107,8 +107,6 @@ static const char* _Py_stdlib_module_names[] = { "bz2", "cProfile", "calendar", -"cgi", -"cgitb", "chunk", "cmath", "cmd", diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py index fcd99405ee0d..a2ec54ec9867 100755 --- a/Tools/wasm/wasm_assets.py +++ b/Tools/wasm/wasm_assets.py @@ -64,8 +64,6 @@ # socket.create_connection() raises an exception: # "BlockingIOError: [Errno 26] Operation in progress". OMIT_NETWORKING_FILES = ( - "cgi.py", - "cgitb.py", "email/", "ftplib.py", "http/", From webhook-mailer at python.org Wed May 24 05:05:41 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 24 May 2023 09:05:41 -0000 Subject: [Python-checkins] [3.12] gh-104797: Allow Protocols to inherit from collections.abc.Buffer (GH-104827) (#104841) Message-ID: https://github.com/python/cpython/commit/d10d1e3b10737a8426f92221e2788e40ad05b4e0 commit: d10d1e3b10737a8426f92221e2788e40ad05b4e0 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2023-05-24T09:05:34Z summary: [3.12] gh-104797: Allow Protocols to inherit from collections.abc.Buffer (GH-104827) (#104841) gh-104797: Allow Protocols to inherit from collections.abc.Buffer (GH-104827) (cherry picked from commit c0ab7d401c736c37bf4462eef7c7d69fef8fab93) Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.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 9a3e64289ee8..a3fad6f35e71 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3546,6 +3546,22 @@ def close(self): self.assertIsSubclass(B, Custom) self.assertNotIsSubclass(A, Custom) + @runtime_checkable + class ReleasableBuffer(collections.abc.Buffer, Protocol): + def __release_buffer__(self, mv: memoryview) -> None: ... + + class C: pass + class D: + def __buffer__(self, flags: int) -> memoryview: + return memoryview(b'') + def __release_buffer__(self, mv: memoryview) -> None: + pass + + self.assertIsSubclass(D, ReleasableBuffer) + self.assertIsInstance(D(), ReleasableBuffer) + self.assertNotIsSubclass(C, ReleasableBuffer) + self.assertNotIsInstance(C(), ReleasableBuffer) + def test_builtin_protocol_allowlist(self): with self.assertRaises(TypeError): class CustomProtocol(TestCase, Protocol): diff --git a/Lib/typing.py b/Lib/typing.py index 96393d6a0281..88837db4b744 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1745,7 +1745,7 @@ def _allow_reckless_class_checks(depth=3): _PROTO_ALLOWLIST = { 'collections.abc': [ 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], } diff --git a/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst new file mode 100644 index 000000000000..60c9a0601cdc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-17-43-52.gh-issue-104797.NR7KzF.rst @@ -0,0 +1,2 @@ +Allow :class:`typing.Protocol` classes to inherit from +:class:`collections.abc.Buffer`. Patch by Jelle Zijlstra. From webhook-mailer at python.org Wed May 24 05:32:26 2023 From: webhook-mailer at python.org (vstinner) Date: Wed, 24 May 2023 09:32:26 -0000 Subject: [Python-checkins] gh-104773: PEP 594: Remove the sndhdr module (#104774) Message-ID: https://github.com/python/cpython/commit/7b00940f69ab26212ea375860a1956e157dd2c30 commit: 7b00940f69ab26212ea375860a1956e157dd2c30 branch: main author: Victor Stinner committer: vstinner date: 2023-05-24T09:32:18Z summary: gh-104773: PEP 594: Remove the sndhdr module (#104774) Remove the Lib/test/sndhdrdata/ directory. files: A Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst D Doc/library/sndhdr.rst D Lib/sndhdr.py D Lib/test/sndhdrdata/README D Lib/test/sndhdrdata/sndhdr.8svx D Lib/test/sndhdrdata/sndhdr.aifc D Lib/test/sndhdrdata/sndhdr.aiff D Lib/test/sndhdrdata/sndhdr.au D Lib/test/sndhdrdata/sndhdr.hcom D Lib/test/sndhdrdata/sndhdr.sndt D Lib/test/sndhdrdata/sndhdr.voc D Lib/test/sndhdrdata/sndhdr.wav D Lib/test/test_sndhdr.py M .gitattributes M Doc/library/superseded.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.13.rst M Makefile.pre.in M Python/stdlib_module_names.h diff --git a/.gitattributes b/.gitattributes index 4ed95069442f..bab1ef0d0104 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18,7 +18,6 @@ *.zip binary # Specific binary files -Lib/test/sndhdrdata/sndhdr.* binary PC/classicAppCompat.* binary # Text files that should not be subject to eol conversion diff --git a/Doc/library/sndhdr.rst b/Doc/library/sndhdr.rst deleted file mode 100644 index fa9323e18dc3..000000000000 --- a/Doc/library/sndhdr.rst +++ /dev/null @@ -1,104 +0,0 @@ -:mod:`sndhdr` --- Determine type of sound file -============================================== - -.. module:: sndhdr - :synopsis: Determine type of a sound file. - :deprecated: - -.. sectionauthor:: Fred L. Drake, Jr. -.. Based on comments in the module source file. - -**Source code:** :source:`Lib/sndhdr.py` - -.. index:: - single: A-LAW - single: u-LAW - -.. deprecated-removed:: 3.11 3.13 - The :mod:`sndhdr` module is deprecated - (see :pep:`PEP 594 <594#sndhdr>` for details and alternatives). - --------------- - -The :mod:`sndhdr` provides utility functions which attempt to determine the type -of sound data which is in a file. When these functions are able to determine -what type of sound data is stored in a file, they return a -:func:`~collections.namedtuple`, containing five attributes: (``filetype``, -``framerate``, ``nchannels``, ``nframes``, ``sampwidth``). The value for *type* -indicates the data type and will be one of the strings ``'aifc'``, ``'aiff'``, -``'au'``, ``'hcom'``, ``'sndr'``, ``'sndt'``, ``'voc'``, ``'wav'``, ``'8svx'``, -``'sb'``, ``'ub'``, or ``'ul'``. The *sampling_rate* will be either the actual -value or ``0`` if unknown or difficult to decode. Similarly, *channels* will be -either the number of channels or ``0`` if it cannot be determined or if the -value is difficult to decode. The value for *frames* will be either the number -of frames or ``-1``. The last item in the tuple, *bits_per_sample*, will either -be the sample size in bits or ``'A'`` for A-LAW or ``'U'`` for u-LAW. - - -.. function:: what(filename) - - Determines the type of sound data stored in the file *filename* using - :func:`whathdr`. If it succeeds, returns a namedtuple as described above, otherwise - ``None`` is returned. - - .. versionchanged:: 3.5 - Result changed from a tuple to a namedtuple. - - -.. function:: whathdr(filename) - - Determines the type of sound data stored in a file based on the file header. - The name of the file is given by *filename*. This function returns a namedtuple as - described above on success, or ``None``. - - .. versionchanged:: 3.5 - Result changed from a tuple to a namedtuple. - -The following sound header types are recognized, as listed below with the return value -from :func:`whathdr`: and :func:`what`: - -+------------+------------------------------------+ -| Value | Sound header format | -+============+====================================+ -| ``'aifc'`` | Compressed Audio Interchange Files | -+------------+------------------------------------+ -| ``'aiff'`` | Audio Interchange Files | -+------------+------------------------------------+ -| ``'au'`` | Au Files | -+------------+------------------------------------+ -| ``'hcom'`` | HCOM Files | -+------------+------------------------------------+ -| ``'sndt'`` | Sndtool Sound Files | -+------------+------------------------------------+ -| ``'voc'`` | Creative Labs Audio Files | -+------------+------------------------------------+ -| ``'wav'`` | Waveform Audio File Format Files | -+------------+------------------------------------+ -| ``'8svx'`` | 8-Bit Sampled Voice Files | -+------------+------------------------------------+ -| ``'sb'`` | Signed Byte Audio Data Files | -+------------+------------------------------------+ -| ``'ub'`` | UB Files | -+------------+------------------------------------+ -| ``'ul'`` | uLAW Audio Files | -+------------+------------------------------------+ - -.. data:: tests - - A list of functions performing the individual tests. Each function takes two - arguments: the byte-stream and an open file-like object. When :func:`what` is - called with a byte-stream, the file-like object will be ``None``. - - The test function should return a string describing the image type if the test - succeeded, or ``None`` if it failed. - -Example: - -.. code-block:: pycon - - >>> import sndhdr - >>> imghdr.what('bass.wav') - 'wav' - >>> imghdr.whathdr('bass.wav') - 'wav' - diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index a96d042f8374..cad4e9c50b69 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -22,7 +22,6 @@ backwards compatibility. They have been superseded by other modules. optparse.rst ossaudiodev.rst pipes.rst - sndhdr.rst spwd.rst sunau.rst uu.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index d024b85059a8..4ad68463e0b5 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1733,7 +1733,7 @@ Modules +---------------------+---------------------+---------------------+---------------------+---------------------+ | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`!telnetlib` | +---------------------+---------------------+---------------------+---------------------+---------------------+ - | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`sndhdr` | :mod:`uu` | + | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`!sndhdr` | :mod:`uu` | +---------------------+---------------------+---------------------+---------------------+---------------------+ | :mod:`!cgi` | :mod:`imghdr` | :mod:`nntplib` | :mod:`spwd` | :mod:`xdrlib` | +---------------------+---------------------+---------------------+---------------------+---------------------+ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 417da22ee045..50e758327b28 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -816,7 +816,7 @@ Modules (see :pep:`594`): * :mod:`nntplib` * :mod:`ossaudiodev` * :mod:`pipes` -* :mod:`sndhdr` +* :mod:`!sndhdr` * :mod:`spwd` * :mod:`sunau` * :mod:`!telnetlib` diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 4bd9a73e7aa7..1d4a4ca9614c 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -147,6 +147,12 @@ Removed (Contributed by Victor Stinner in :gh:`104773`.) +* :pep:`594`: Remove the :mod:`!sndhdr` module, deprecated in Python 3.11: use + the projects `filetype `_, `puremagic + `_, or `python-magic + `_ instead. + (Contributed by Victor Stinner in :gh:`104773`.) + Porting to Python 3.13 ====================== diff --git a/Lib/sndhdr.py b/Lib/sndhdr.py deleted file mode 100644 index 45def9ad16d3..000000000000 --- a/Lib/sndhdr.py +++ /dev/null @@ -1,271 +0,0 @@ -"""Routines to help recognizing sound files. - -Function whathdr() recognizes various types of sound file headers. -It understands almost all headers that SOX can decode. - -The return tuple contains the following items, in this order: -- file type (as SOX understands it) -- sampling rate (0 if unknown or hard to decode) -- number of channels (0 if unknown or hard to decode) -- number of frames in the file (-1 if unknown or hard to decode) -- number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW - -If the file doesn't have a recognizable type, it returns None. -If the file can't be opened, OSError is raised. - -To compute the total time, divide the number of frames by the -sampling rate (a frame contains a sample for each channel). - -Function what() calls whathdr(). (It used to also use some -heuristics for raw data, but this doesn't work very well.) - -Finally, the function test() is a simple main program that calls -what() for all files mentioned on the argument list. For directory -arguments it calls what() for all files in that directory. Default -argument is "." (testing all files in the current directory). The -option -r tells it to recurse down directories found inside -explicitly given directories. -""" - -import warnings - -warnings._deprecated(__name__, remove=(3, 13)) - -# The file structure is top-down except that the test program and its -# subroutine come last. - -__all__ = ['what', 'whathdr'] - -from collections import namedtuple - -SndHeaders = namedtuple('SndHeaders', - 'filetype framerate nchannels nframes sampwidth') - -SndHeaders.filetype.__doc__ = ("""The value for type indicates the data type -and will be one of the strings 'aifc', 'aiff', 'au','hcom', -'sndr', 'sndt', 'voc', 'wav', '8svx', 'sb', 'ub', or 'ul'.""") -SndHeaders.framerate.__doc__ = ("""The sampling_rate will be either the actual -value or 0 if unknown or difficult to decode.""") -SndHeaders.nchannels.__doc__ = ("""The number of channels or 0 if it cannot be -determined or if the value is difficult to decode.""") -SndHeaders.nframes.__doc__ = ("""The value for frames will be either the number -of frames or -1.""") -SndHeaders.sampwidth.__doc__ = ("""Either the sample size in bits or -'A' for A-LAW or 'U' for u-LAW.""") - -def what(filename): - """Guess the type of a sound file.""" - res = whathdr(filename) - return res - - -def whathdr(filename): - """Recognize sound headers.""" - with open(filename, 'rb') as f: - h = f.read(512) - for tf in tests: - res = tf(h, f) - if res: - return SndHeaders(*res) - return None - - -#-----------------------------------# -# Subroutines per sound header type # -#-----------------------------------# - -tests = [] - -def test_aifc(h, f): - """AIFC and AIFF files""" - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import aifc - if not h.startswith(b'FORM'): - return None - if h[8:12] == b'AIFC': - fmt = 'aifc' - elif h[8:12] == b'AIFF': - fmt = 'aiff' - else: - return None - f.seek(0) - try: - a = aifc.open(f, 'r') - except (EOFError, aifc.Error): - return None - return (fmt, a.getframerate(), a.getnchannels(), - a.getnframes(), 8 * a.getsampwidth()) - -tests.append(test_aifc) - - -def test_au(h, f): - """AU and SND files""" - if h.startswith(b'.snd'): - func = get_long_be - elif h[:4] in (b'\0ds.', b'dns.'): - func = get_long_le - else: - return None - filetype = 'au' - hdr_size = func(h[4:8]) - data_size = func(h[8:12]) - encoding = func(h[12:16]) - rate = func(h[16:20]) - nchannels = func(h[20:24]) - sample_size = 1 # default - if encoding == 1: - sample_bits = 'U' - elif encoding == 2: - sample_bits = 8 - elif encoding == 3: - sample_bits = 16 - sample_size = 2 - else: - sample_bits = '?' - frame_size = sample_size * nchannels - if frame_size: - nframe = data_size / frame_size - else: - nframe = -1 - return filetype, rate, nchannels, nframe, sample_bits - -tests.append(test_au) - - -def test_hcom(h, f): - """HCOM file""" - if h[65:69] != b'FSSD' or h[128:132] != b'HCOM': - return None - divisor = get_long_be(h[144:148]) - if divisor: - rate = 22050 / divisor - else: - rate = 0 - return 'hcom', rate, 1, -1, 8 - -tests.append(test_hcom) - - -def test_voc(h, f): - """VOC file""" - if not h.startswith(b'Creative Voice File\032'): - return None - sbseek = get_short_le(h[20:22]) - rate = 0 - if 0 <= sbseek < 500 and h[sbseek] == 1: - ratecode = 256 - h[sbseek+4] - if ratecode: - rate = int(1000000.0 / ratecode) - return 'voc', rate, 1, -1, 8 - -tests.append(test_voc) - - -def test_wav(h, f): - """WAV file""" - import wave - # 'RIFF' 'WAVE' 'fmt ' - if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ': - return None - f.seek(0) - try: - w = wave.open(f, 'r') - except (EOFError, wave.Error): - return None - return ('wav', w.getframerate(), w.getnchannels(), - w.getnframes(), 8*w.getsampwidth()) - -tests.append(test_wav) - - -def test_8svx(h, f): - """8SVX file""" - if not h.startswith(b'FORM') or h[8:12] != b'8SVX': - return None - # Should decode it to get #channels -- assume always 1 - return '8svx', 0, 1, 0, 8 - -tests.append(test_8svx) - - -def test_sndt(h, f): - """SNDT file""" - if h.startswith(b'SOUND'): - nsamples = get_long_le(h[8:12]) - rate = get_short_le(h[20:22]) - return 'sndt', rate, 1, nsamples, 8 - -tests.append(test_sndt) - - -def test_sndr(h, f): - """SNDR file""" - if h.startswith(b'\0\0'): - rate = get_short_le(h[2:4]) - if 4000 <= rate <= 25000: - return 'sndr', rate, 1, -1, 8 - -tests.append(test_sndr) - - -#-------------------------------------------# -# Subroutines to extract numbers from bytes # -#-------------------------------------------# - -def get_long_be(b): - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3] - -def get_long_le(b): - return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0] - -def get_short_be(b): - return (b[0] << 8) | b[1] - -def get_short_le(b): - return (b[1] << 8) | b[0] - - -#--------------------# -# Small test program # -#--------------------# - -def test(): - import sys - recursive = 0 - if sys.argv[1:] and sys.argv[1] == '-r': - del sys.argv[1:2] - recursive = 1 - try: - if sys.argv[1:]: - testall(sys.argv[1:], recursive, 1) - else: - testall(['.'], recursive, 1) - except KeyboardInterrupt: - sys.stderr.write('\n[Interrupted]\n') - sys.exit(1) - -def testall(list, recursive, toplevel): - import sys - import os - for filename in list: - if os.path.isdir(filename): - print(filename + '/:', end=' ') - if recursive or toplevel: - print('recursing down:') - import glob - names = glob.glob(os.path.join(glob.escape(filename), '*')) - testall(names, recursive, 0) - else: - print('*** directory (use -r) ***') - else: - print(filename + ':', end=' ') - sys.stdout.flush() - try: - print(what(filename)) - except OSError: - print('*** not found ***') - -if __name__ == '__main__': - test() diff --git a/Lib/test/sndhdrdata/README b/Lib/test/sndhdrdata/README deleted file mode 100644 index b2cb664615b9..000000000000 --- a/Lib/test/sndhdrdata/README +++ /dev/null @@ -1,5 +0,0 @@ -Sound file samples used by Lib/test/test_sndhdr.py and generated using the -following commands: - - dd if=/dev/zero of=sndhdr.raw bs=20 count=1 - sox -s -2 -c 2 -r 44100 sndhdr.raw sndhdr. diff --git a/Lib/test/sndhdrdata/sndhdr.8svx b/Lib/test/sndhdrdata/sndhdr.8svx deleted file mode 100644 index 8cd6cde5e09f..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.8svx and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.aifc b/Lib/test/sndhdrdata/sndhdr.aifc deleted file mode 100644 index 8aae4e730bda..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.aifc and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.aiff b/Lib/test/sndhdrdata/sndhdr.aiff deleted file mode 100644 index 8c279a762f1c..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.aiff and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.au b/Lib/test/sndhdrdata/sndhdr.au deleted file mode 100644 index 67c9e8fdd995..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.au and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.hcom b/Lib/test/sndhdrdata/sndhdr.hcom deleted file mode 100644 index debb02d9dd93..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.hcom and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.sndt b/Lib/test/sndhdrdata/sndhdr.sndt deleted file mode 100644 index e1ca9cb185d1..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.sndt and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.voc b/Lib/test/sndhdrdata/sndhdr.voc deleted file mode 100644 index 53a91fd1eae3..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.voc and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.wav b/Lib/test/sndhdrdata/sndhdr.wav deleted file mode 100644 index 0dca36739cde..000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.wav and /dev/null differ diff --git a/Lib/test/test_sndhdr.py b/Lib/test/test_sndhdr.py deleted file mode 100644 index 4d97437f9072..000000000000 --- a/Lib/test/test_sndhdr.py +++ /dev/null @@ -1,40 +0,0 @@ -import pickle -import unittest -from test.support import findfile -from test.support import warnings_helper - -sndhdr = warnings_helper.import_deprecated("sndhdr") - - -class TestFormats(unittest.TestCase): - def test_data(self): - for filename, expected in ( - ('sndhdr.8svx', ('8svx', 0, 1, 0, 8)), - ('sndhdr.aifc', ('aifc', 44100, 2, 5, 16)), - ('sndhdr.aiff', ('aiff', 44100, 2, 5, 16)), - ('sndhdr.au', ('au', 44100, 2, 5.0, 16)), - ('sndhdr.hcom', ('hcom', 22050.0, 1, -1, 8)), - ('sndhdr.sndt', ('sndt', 44100, 1, 5, 8)), - ('sndhdr.voc', ('voc', 0, 1, -1, 8)), - ('sndhdr.wav', ('wav', 44100, 2, 5, 16)), - ): - filename = findfile(filename, subdir="sndhdrdata") - what = sndhdr.what(filename) - self.assertNotEqual(what, None, filename) - self.assertSequenceEqual(what, expected) - self.assertEqual(what.filetype, expected[0]) - self.assertEqual(what.framerate, expected[1]) - self.assertEqual(what.nchannels, expected[2]) - self.assertEqual(what.nframes, expected[3]) - self.assertEqual(what.sampwidth, expected[4]) - - def test_pickleable(self): - filename = findfile('sndhdr.aifc', subdir="sndhdrdata") - what = sndhdr.what(filename) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - dump = pickle.dumps(what, proto) - self.assertEqual(pickle.loads(dump), what) - - -if __name__ == '__main__': - unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index 091df3e4c0b8..033fdf98f1f7 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2119,7 +2119,6 @@ TESTSUBDIRS= idlelib/idle_test \ test/imghdrdata \ test/leakers \ test/libregrtest \ - test/sndhdrdata \ test/subprocessdata \ test/support \ test/support/_hypothesis_stubs \ diff --git a/Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst b/Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst new file mode 100644 index 000000000000..228916158534 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst @@ -0,0 +1,2 @@ +:pep:`594`: Remove the :mod:`!sndhdr` module, deprecated in Python 3.11. +Patch by Victor Stinner. diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index f5defe8923b2..245c3a1645f3 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -236,7 +236,6 @@ static const char* _Py_stdlib_module_names[] = { "signal", "site", "smtplib", -"sndhdr", "socket", "socketserver", "spwd", From webhook-mailer at python.org Wed May 24 05:36:57 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 24 May 2023 09:36:57 -0000 Subject: [Python-checkins] gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (#104824) Message-ID: https://github.com/python/cpython/commit/c45701e9ef004a523ebb28f3be902b3cf2cf7a9b commit: c45701e9ef004a523ebb28f3be902b3cf2cf7a9b branch: main author: Marta G?mez Mac?as committer: pablogsal date: 2023-05-24T10:36:50+01:00 summary: gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (#104824) Co-authored-by: Pablo Galindo Salgado Co-authored-by: Jelle Zijlstra files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 50e758327b28..b410fb242098 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -66,6 +66,10 @@ Summary -- Release highlights .. PEP-sized items next. +New grammar features: + +* :pep:`701`: Syntactic formalization of f-strings + New typing features: * :pep:`688`: Making the buffer protocol accessible in Python @@ -136,22 +140,70 @@ Improved Error Messages New Features ============ -* Add :ref:`perf_profiling` through the new - environment variable :envvar:`PYTHONPERFSUPPORT`, - the new command-line option :option:`-X perf <-X>`, - as well as the new :func:`sys.activate_stack_trampoline`, - :func:`sys.deactivate_stack_trampoline`, - and :func:`sys.is_stack_trampoline_active` APIs. - (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes - with contributions from Gregory P. Smith [Google] and Mark Shannon - in :gh:`96123`.) -* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, - have a new a *filter* argument that allows limiting tar features than may be - surprising or dangerous, such as creating files outside the destination - directory. - See :ref:`tarfile-extraction-filter` for details. - In Python 3.14, the default will switch to ``'data'``. - (Contributed by Petr Viktorin in :pep:`706`.) +.. _whatsnew312-pep701: + +PEP 701: Syntactic formalization of f-strings +--------------------------------------------- + +:pep:`701` lifts some restrictions on the usage of f-strings. Expression components +inside f-strings can now be any valid Python expression including backslashes, +unicode escaped sequences, multi-line expressions, comments and strings reusing the +same quote as the containing f-string. Let's cover these in detail: + +* Quote reuse: in Python 3.11, reusing the same quotes as the containing f-string + raises a :exc:`SyntaxError`, forcing the user to either use other available + quotes (like using double quotes or triple quotes if the f-string uses single + quotes). In Python 3.12, you can now do things like this: + + >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism'] + >>> f"This is the playlist: {", ".join(songs)}" + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism + + Note that before this change there was no explicit limit in how f-strings can + be nested, but the fact that string quotes cannot be reused inside the + expression component of f-strings made it impossible to nest f-strings + arbitrarily. In fact, this is the most nested f-string that could be written: + + >>> f"""{f'''{f'{f"{1+1}"}'}'''}""" + '2' + + As now f-strings can contain any valid Python expression inside expression + components, it is now possible to nest f-strings arbitrarily: + + >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" + '2' + +* Multi-line expressions and comments: In Python 3.11, f-strings expressions + must be defined in a single line even if outside f-strings expressions could + span multiple lines (like literal lists being defined over multiple lines), + making them harder to read. In Python 3.12 you can now define expressions + spaning multiple lines and include comments on them: + + >>> f"This is the playlist: {", ".join([ + ... 'Take me back to Eden', # My, my, those eyes like fire + ... 'Alkaline', # Not acid nor alkaline + ... 'Ascensionism' # Take to the broken skies at last + ... ])}" + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' + +* Backslashes and unicode characters: before Python 3.12 f-string expressions + couldn't contain any ``\`` character. This also affected unicode escaped + sequences (such as ``\N{snowman}``) as these contain the ``\N`` part that + previously could not be part of expression components of f-strings. Now, you + can define expressions like this: + + >>> print(f"This is the playlist: {"\n".join(songs)}") + This is the playlist: Take me back to Eden + Alkaline + Ascensionism + >>> print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}") + This is the playlist: Take me back to Eden?Alkaline?Ascensionism + +See :pep:`701` for more details. + +(Contributed by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou, Cristi?n +Maureira-Fredes and Marta G?mez in :gh:`102856`. PEP written by Pablo Galindo, +Batuhan Taskaya, Lysandros Nikolaou and Marta G?mez). .. _whatsnew312-pep709: @@ -223,6 +275,24 @@ See :pep:`692` for more details. Other Language Changes ====================== +* Add :ref:`perf_profiling` through the new + environment variable :envvar:`PYTHONPERFSUPPORT`, + the new command-line option :option:`-X perf <-X>`, + as well as the new :func:`sys.activate_stack_trampoline`, + :func:`sys.deactivate_stack_trampoline`, + and :func:`sys.is_stack_trampoline_active` APIs. + (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile-extraction-filter` for details. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) + * :class:`types.MappingProxyType` instances are now hashable if the underlying mapping is hashable. (Contributed by Serhiy Storchaka in :gh:`87995`.) @@ -543,6 +613,14 @@ tkinter like ``create_*()`` methods. (Contributed by Serhiy Storchaka in :gh:`94473`.) +tokenize +-------- + +* The :mod:`tokenize` module includes the changes introduced in :pep:`701`. ( + Contributed by Marta G?mez Mac?as and Pablo Galindo in :gh:`102856`.) + See :ref:`whatsnew312-porting-to-python312` for more information on the + changes to the :mod:`tokenize` module. + types ----- @@ -687,6 +765,11 @@ Optimizations * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting. (Contributed by Itamar O in :gh:`103793`.) +* The :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` functions are + up to 64% faster as a side effect of the changes required to cover :pep:`701` in + the :mod:`tokenize` module. (Contributed by Marta G?mez Mac?as and Pablo Galindo + in :gh:`102856`.) + CPython bytecode changes ======================== @@ -1130,6 +1213,8 @@ Removed Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). +.. _whatsnew312-porting-to-python312: + Porting to Python 3.12 ====================== @@ -1201,6 +1286,40 @@ Changes in the Python API that may be surprising or dangerous. See :ref:`tarfile-extraction-filter` for details. +* The output of the :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` + functions is now changed due to the changes introduced in :pep:`701`. This + means that ``STRING`` tokens are not emitted any more for f-strings and the + tokens described in :pep:`701` are now produced instead: ``FSTRING_START``, + ``FSRING_MIDDLE`` and ``FSTRING_END`` are now emitted for f-string "string" + parts in addition to the appropriate tokens for the tokenization in the + expression components. For example for the f-string ``f"start {1+1} end"`` + the old version of the tokenizer emitted:: + + 1,0-1,18: STRING 'f"start {1+1} end"' + + while the new version emits:: + + 1,0-1,2: FSTRING_START 'f"' + 1,2-1,8: FSTRING_MIDDLE 'start ' + 1,8-1,9: OP '{' + 1,9-1,10: NUMBER '1' + 1,10-1,11: OP '+' + 1,11-1,12: NUMBER '1' + 1,12-1,13: OP '}' + 1,13-1,17: FSTRING_MIDDLE ' end' + 1,17-1,18: FSTRING_END '"' + + Aditionally, there may be some minor behavioral changes as a consecuence of the + changes required to support :pep:`701`. Some of these changes include: + + * Some final ``DEDENT`` tokens are now emitted within the bounds of the + input. This means that for a file containing 3 lines, the old version of the + tokenizer returned a ``DEDENT`` token in line 4 whilst the new version returns + the token in line 3. + + * The ``type`` attribute of the tokens emitted when tokenizing some invalid Python + characters such as ``!`` has changed from ``ERRORTOKEN`` to ``OP``. + Build Changes ============= From webhook-mailer at python.org Wed May 24 05:59:25 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 24 May 2023 09:59:25 -0000 Subject: [Python-checkins] gh-104825: Remove implicit newline in the line attribute in tokens emitted in the tokenize module (#104846) Message-ID: https://github.com/python/cpython/commit/c8cf9b42eb2bfbd4c3e708ec28d32430248a1d7a commit: c8cf9b42eb2bfbd4c3e708ec28d32430248a1d7a branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2023-05-24T09:59:18Z summary: gh-104825: Remove implicit newline in the line attribute in tokens emitted in the tokenize module (#104846) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst M Lib/idlelib/idle_test/test_editor.py M Lib/test/test_tabnanny.py M Lib/test/test_tokenize.py M Python/Python-tokenize.c diff --git a/Lib/idlelib/idle_test/test_editor.py b/Lib/idlelib/idle_test/test_editor.py index 9296a6d235fb..ba59c40dc6dd 100644 --- a/Lib/idlelib/idle_test/test_editor.py +++ b/Lib/idlelib/idle_test/test_editor.py @@ -201,8 +201,8 @@ def test_searcher(self): test_info = (# text, (block, indent)) ("", (None, None)), ("[1,", (None, None)), # TokenError - ("if 1:\n", ('if 1:\n', None)), - ("if 1:\n 2\n 3\n", ('if 1:\n', ' 2\n')), + ("if 1:\n", ('if 1:', None)), + ("if 1:\n 2\n 3\n", ('if 1:', ' 2')), ) for code, expected_pair in test_info: with self.subTest(code=code): diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index aa700118f735..cc122cafc798 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -222,7 +222,7 @@ def test_when_nannynag_error_verbose(self): """ with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: out = f"{file_path!r}: *** Line 3: trouble in tab city! ***\n" - out += "offending line: '\\tprint(\"world\")\\n'\n" + out += "offending line: '\\tprint(\"world\")'\n" out += "inconsistent use of tabs and spaces in indentation\n" tabnanny.verbose = 1 @@ -231,7 +231,7 @@ def test_when_nannynag_error_verbose(self): def test_when_nannynag_error(self): """A python source code file eligible for raising `tabnanny.NannyNag`.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: - out = f"{file_path} 3 '\\tprint(\"world\")\\n'\n" + out = f"{file_path} 3 '\\tprint(\"world\")'\n" self.verify_tabnanny_check(file_path, out=out) def test_when_no_file(self): @@ -341,7 +341,7 @@ def test_verbose_mode(self): """Should display more error information if verbose mode is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" + "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-v", path, stdout=stdout, partial=True) @@ -349,6 +349,6 @@ def test_double_verbose_mode(self): """Should display detailed error information if double verbose is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" + "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-vv", path, stdout=stdout, partial=True) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 8e7ab3d4b7b5..fd9c919ce6a0 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -103,7 +103,7 @@ def k(x): e.exception.msg, 'unindent does not match any outer indentation level') self.assertEqual(e.exception.offset, 9) - self.assertEqual(e.exception.text, ' x += 5\n') + self.assertEqual(e.exception.text, ' x += 5') def test_int(self): # Ordinary integers and binary operators @@ -1157,7 +1157,7 @@ def readline(): # skip the initial encoding token and the end tokens tokens = list(_tokenize(readline(), encoding='utf-8'))[:-2] - expected_tokens = [TokenInfo(3, '"?????"', (1, 0), (1, 7), '"?????"\n')] + expected_tokens = [TokenInfo(3, '"?????"', (1, 0), (1, 7), '"?????"')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst new file mode 100644 index 000000000000..caf5d3527085 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst @@ -0,0 +1,2 @@ +Tokens emitted by the :mod:`tokenize` module do not include an implicit +``\n`` character in the ``line`` attribute anymore. Patch by Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index f7e32d3af9a9..0023e303b96e 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -123,6 +123,8 @@ _tokenizer_error(struct tok_state *tok) int result = 0; Py_ssize_t size = tok->inp - tok->buf; + assert(tok->buf[size-1] == '\n'); + size -= 1; // Remove the newline character from the end of the line error_line = PyUnicode_DecodeUTF8(tok->buf, size, "replace"); if (!error_line) { result = -1; @@ -193,6 +195,8 @@ tokenizeriter_next(tokenizeriterobject *it) } Py_ssize_t size = it->tok->inp - it->tok->buf; + assert(it->tok->buf[size-1] == '\n'); + size -= 1; // Remove the newline character from the end of the line PyObject *line = PyUnicode_DecodeUTF8(it->tok->buf, size, "replace"); if (line == NULL) { Py_DECREF(str); From webhook-mailer at python.org Wed May 24 06:00:41 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 24 May 2023 10:00:41 -0000 Subject: [Python-checkins] [3.12] gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (GH-104824) (#104847) Message-ID: https://github.com/python/cpython/commit/a5c0ef87a1c7b08d9c7407a705b3751d9e0b3638 commit: a5c0ef87a1c7b08d9c7407a705b3751d9e0b3638 branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: pablogsal date: 2023-05-24T11:00:34+01:00 summary: [3.12] gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (GH-104824) (#104847) gh-102856: Add changes related to PEP 701 in 3.12 What's New docs (GH-104824) (cherry picked from commit c45701e9ef004a523ebb28f3be902b3cf2cf7a9b) Co-authored-by: Marta G?mez Mac?as Co-authored-by: Pablo Galindo Salgado Co-authored-by: Jelle Zijlstra files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 4ff90664bb79..27fbb21c3342 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -66,6 +66,10 @@ Summary -- Release highlights .. PEP-sized items next. +New grammar features: + +* :pep:`701`: Syntactic formalization of f-strings + New typing features: * :pep:`688`: Making the buffer protocol accessible in Python @@ -136,22 +140,70 @@ Improved Error Messages New Features ============ -* Add :ref:`perf_profiling` through the new - environment variable :envvar:`PYTHONPERFSUPPORT`, - the new command-line option :option:`-X perf <-X>`, - as well as the new :func:`sys.activate_stack_trampoline`, - :func:`sys.deactivate_stack_trampoline`, - and :func:`sys.is_stack_trampoline_active` APIs. - (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes - with contributions from Gregory P. Smith [Google] and Mark Shannon - in :gh:`96123`.) -* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, - have a new a *filter* argument that allows limiting tar features than may be - surprising or dangerous, such as creating files outside the destination - directory. - See :ref:`tarfile-extraction-filter` for details. - In Python 3.14, the default will switch to ``'data'``. - (Contributed by Petr Viktorin in :pep:`706`.) +.. _whatsnew312-pep701: + +PEP 701: Syntactic formalization of f-strings +--------------------------------------------- + +:pep:`701` lifts some restrictions on the usage of f-strings. Expression components +inside f-strings can now be any valid Python expression including backslashes, +unicode escaped sequences, multi-line expressions, comments and strings reusing the +same quote as the containing f-string. Let's cover these in detail: + +* Quote reuse: in Python 3.11, reusing the same quotes as the containing f-string + raises a :exc:`SyntaxError`, forcing the user to either use other available + quotes (like using double quotes or triple quotes if the f-string uses single + quotes). In Python 3.12, you can now do things like this: + + >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism'] + >>> f"This is the playlist: {", ".join(songs)}" + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism + + Note that before this change there was no explicit limit in how f-strings can + be nested, but the fact that string quotes cannot be reused inside the + expression component of f-strings made it impossible to nest f-strings + arbitrarily. In fact, this is the most nested f-string that could be written: + + >>> f"""{f'''{f'{f"{1+1}"}'}'''}""" + '2' + + As now f-strings can contain any valid Python expression inside expression + components, it is now possible to nest f-strings arbitrarily: + + >>> f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}" + '2' + +* Multi-line expressions and comments: In Python 3.11, f-strings expressions + must be defined in a single line even if outside f-strings expressions could + span multiple lines (like literal lists being defined over multiple lines), + making them harder to read. In Python 3.12 you can now define expressions + spaning multiple lines and include comments on them: + + >>> f"This is the playlist: {", ".join([ + ... 'Take me back to Eden', # My, my, those eyes like fire + ... 'Alkaline', # Not acid nor alkaline + ... 'Ascensionism' # Take to the broken skies at last + ... ])}" + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' + +* Backslashes and unicode characters: before Python 3.12 f-string expressions + couldn't contain any ``\`` character. This also affected unicode escaped + sequences (such as ``\N{snowman}``) as these contain the ``\N`` part that + previously could not be part of expression components of f-strings. Now, you + can define expressions like this: + + >>> print(f"This is the playlist: {"\n".join(songs)}") + This is the playlist: Take me back to Eden + Alkaline + Ascensionism + >>> print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}") + This is the playlist: Take me back to Eden?Alkaline?Ascensionism + +See :pep:`701` for more details. + +(Contributed by Pablo Galindo, Batuhan Taskaya, Lysandros Nikolaou, Cristi?n +Maureira-Fredes and Marta G?mez in :gh:`102856`. PEP written by Pablo Galindo, +Batuhan Taskaya, Lysandros Nikolaou and Marta G?mez). .. _whatsnew312-pep709: @@ -223,6 +275,24 @@ See :pep:`692` for more details. Other Language Changes ====================== +* Add :ref:`perf_profiling` through the new + environment variable :envvar:`PYTHONPERFSUPPORT`, + the new command-line option :option:`-X perf <-X>`, + as well as the new :func:`sys.activate_stack_trampoline`, + :func:`sys.deactivate_stack_trampoline`, + and :func:`sys.is_stack_trampoline_active` APIs. + (Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes + with contributions from Gregory P. Smith [Google] and Mark Shannon + in :gh:`96123`.) + +* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`, + have a new a *filter* argument that allows limiting tar features than may be + surprising or dangerous, such as creating files outside the destination + directory. + See :ref:`tarfile-extraction-filter` for details. + In Python 3.14, the default will switch to ``'data'``. + (Contributed by Petr Viktorin in :pep:`706`.) + * :class:`types.MappingProxyType` instances are now hashable if the underlying mapping is hashable. (Contributed by Serhiy Storchaka in :gh:`87995`.) @@ -543,6 +613,14 @@ tkinter like ``create_*()`` methods. (Contributed by Serhiy Storchaka in :gh:`94473`.) +tokenize +-------- + +* The :mod:`tokenize` module includes the changes introduced in :pep:`701`. ( + Contributed by Marta G?mez Mac?as and Pablo Galindo in :gh:`102856`.) + See :ref:`whatsnew312-porting-to-python312` for more information on the + changes to the :mod:`tokenize` module. + types ----- @@ -687,6 +765,11 @@ Optimizations * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting. (Contributed by Itamar O in :gh:`103793`.) +* The :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` functions are + up to 64% faster as a side effect of the changes required to cover :pep:`701` in + the :mod:`tokenize` module. (Contributed by Marta G?mez Mac?as and Pablo Galindo + in :gh:`102856`.) + CPython bytecode changes ======================== @@ -1130,6 +1213,8 @@ Removed Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). +.. _whatsnew312-porting-to-python312: + Porting to Python 3.12 ====================== @@ -1201,6 +1286,40 @@ Changes in the Python API that may be surprising or dangerous. See :ref:`tarfile-extraction-filter` for details. +* The output of the :func:`tokenize.tokenize` and :func:`tokenize.generate_tokens` + functions is now changed due to the changes introduced in :pep:`701`. This + means that ``STRING`` tokens are not emitted any more for f-strings and the + tokens described in :pep:`701` are now produced instead: ``FSTRING_START``, + ``FSRING_MIDDLE`` and ``FSTRING_END`` are now emitted for f-string "string" + parts in addition to the appropriate tokens for the tokenization in the + expression components. For example for the f-string ``f"start {1+1} end"`` + the old version of the tokenizer emitted:: + + 1,0-1,18: STRING 'f"start {1+1} end"' + + while the new version emits:: + + 1,0-1,2: FSTRING_START 'f"' + 1,2-1,8: FSTRING_MIDDLE 'start ' + 1,8-1,9: OP '{' + 1,9-1,10: NUMBER '1' + 1,10-1,11: OP '+' + 1,11-1,12: NUMBER '1' + 1,12-1,13: OP '}' + 1,13-1,17: FSTRING_MIDDLE ' end' + 1,17-1,18: FSTRING_END '"' + + Aditionally, there may be some minor behavioral changes as a consecuence of the + changes required to support :pep:`701`. Some of these changes include: + + * Some final ``DEDENT`` tokens are now emitted within the bounds of the + input. This means that for a file containing 3 lines, the old version of the + tokenizer returned a ``DEDENT`` token in line 4 whilst the new version returns + the token in line 3. + + * The ``type`` attribute of the tokens emitted when tokenizing some invalid Python + characters such as ``!`` has changed from ``ERRORTOKEN`` to ``OP``. + Build Changes ============= From webhook-mailer at python.org Wed May 24 06:10:54 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 24 May 2023 10:10:54 -0000 Subject: [Python-checkins] gh-101282: Enclose BOLT_APPLY_FLAGS value in double quotes (gh-104752) Message-ID: https://github.com/python/cpython/commit/c43785192c97698a0217a680b30baae22106ed3e commit: c43785192c97698a0217a680b30baae22106ed3e branch: main author: Dong-hee Na committer: corona10 date: 2023-05-24T19:10:46+09:00 summary: gh-101282: Enclose BOLT_APPLY_FLAGS value in double quotes (gh-104752) files: M configure M configure.ac diff --git a/configure b/configure index bcf2a5c7c7f7..a295b5e992b5 100755 --- a/configure +++ b/configure @@ -8398,8 +8398,7 @@ $as_echo "$BOLT_INSTRUMENT_FLAGS" >&6; } $as_echo_n "checking BOLT_APPLY_FLAGS... " >&6; } if test -z "${BOLT_APPLY_FLAGS}" then - BOLT_APPLY_FLAGS=-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 - + BOLT_APPLY_FLAGS=" -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 " fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 diff --git a/configure.ac b/configure.ac index d5cb822ae8cb..44b2ced0e658 100644 --- a/configure.ac +++ b/configure.ac @@ -2087,23 +2087,23 @@ if test -z "${BOLT_APPLY_FLAGS}" then AS_VAR_SET( [BOLT_APPLY_FLAGS], - [m4_join([ ], - [-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] - )] + [m4_normalize(" + -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 + ")] ) fi AC_MSG_RESULT([$BOLT_APPLY_FLAGS]) From webhook-mailer at python.org Wed May 24 06:21:28 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 24 May 2023 10:21:28 -0000 Subject: [Python-checkins] gh-102856: Add missing quote to fix doctest (#104852) Message-ID: https://github.com/python/cpython/commit/3e97c001711ab68e3d54d65e264cb5c37fefbec0 commit: 3e97c001711ab68e3d54d65e264cb5c37fefbec0 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-05-24T13:21:15+03:00 summary: gh-102856: Add missing quote to fix doctest (#104852) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b410fb242098..9cf10196dcfc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -157,7 +157,7 @@ same quote as the containing f-string. Let's cover these in detail: >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism'] >>> f"This is the playlist: {", ".join(songs)}" - 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' Note that before this change there was no explicit limit in how f-strings can be nested, but the fact that string quotes cannot be reused inside the From webhook-mailer at python.org Wed May 24 06:22:06 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 24 May 2023 10:22:06 -0000 Subject: [Python-checkins] [3.12] gh-102856: Add missing quote to fix doctest (GH-104852) (#104854) Message-ID: https://github.com/python/cpython/commit/2d685eca8a6ef25963609246d18097032358881c commit: 2d685eca8a6ef25963609246d18097032358881c branch: 3.12 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: hugovk date: 2023-05-24T10:21:59Z summary: [3.12] gh-102856: Add missing quote to fix doctest (GH-104852) (#104854) Co-authored-by: Hugo van Kemenade files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 27fbb21c3342..265c9f84e8fc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -157,7 +157,7 @@ same quote as the containing f-string. Let's cover these in detail: >>> songs = ['Take me back to Eden', 'Alkaline', 'Ascensionism'] >>> f"This is the playlist: {", ".join(songs)}" - 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism + 'This is the playlist: Take me back to Eden, Alkaline, Ascensionism' Note that before this change there was no explicit limit in how f-strings can be nested, but the fact that string quotes cannot be reused inside the From webhook-mailer at python.org Wed May 24 06:41:35 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 24 May 2023 10:41:35 -0000 Subject: [Python-checkins] [3.12] gh-104825: Remove implicit newline in the line attribute in tokens emitted in the tokenize module (GH-104846). (#104850) Message-ID: https://github.com/python/cpython/commit/3d2ed8991f9f0f4bbefe4c6f5c8bbbb92259bac6 commit: 3d2ed8991f9f0f4bbefe4c6f5c8bbbb92259bac6 branch: 3.12 author: Pablo Galindo Salgado committer: pablogsal date: 2023-05-24T10:40:51Z summary: [3.12] gh-104825: Remove implicit newline in the line attribute in tokens emitted in the tokenize module (GH-104846). (#104850) (cherry picked from commit c8cf9b42eb2bfbd4c3e708ec28d32430248a1d7a) files: A Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst M Lib/test/test_tabnanny.py M Lib/test/test_tokenize.py M Python/Python-tokenize.c diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index aa700118f735..cc122cafc798 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -222,7 +222,7 @@ def test_when_nannynag_error_verbose(self): """ with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: out = f"{file_path!r}: *** Line 3: trouble in tab city! ***\n" - out += "offending line: '\\tprint(\"world\")\\n'\n" + out += "offending line: '\\tprint(\"world\")'\n" out += "inconsistent use of tabs and spaces in indentation\n" tabnanny.verbose = 1 @@ -231,7 +231,7 @@ def test_when_nannynag_error_verbose(self): def test_when_nannynag_error(self): """A python source code file eligible for raising `tabnanny.NannyNag`.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as file_path: - out = f"{file_path} 3 '\\tprint(\"world\")\\n'\n" + out = f"{file_path} 3 '\\tprint(\"world\")'\n" self.verify_tabnanny_check(file_path, out=out) def test_when_no_file(self): @@ -341,7 +341,7 @@ def test_verbose_mode(self): """Should display more error information if verbose mode is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" + "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-v", path, stdout=stdout, partial=True) @@ -349,6 +349,6 @@ def test_double_verbose_mode(self): """Should display detailed error information if double verbose is on.""" with TemporaryPyFile(SOURCE_CODES["nannynag_errored"]) as path: stdout = textwrap.dedent( - "offending line: '\\tprint(\"world\")\\n'" + "offending line: '\\tprint(\"world\")'" ).strip() self.validate_cmd("-vv", path, stdout=stdout, partial=True) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 8e7ab3d4b7b5..fd9c919ce6a0 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -103,7 +103,7 @@ def k(x): e.exception.msg, 'unindent does not match any outer indentation level') self.assertEqual(e.exception.offset, 9) - self.assertEqual(e.exception.text, ' x += 5\n') + self.assertEqual(e.exception.text, ' x += 5') def test_int(self): # Ordinary integers and binary operators @@ -1157,7 +1157,7 @@ def readline(): # skip the initial encoding token and the end tokens tokens = list(_tokenize(readline(), encoding='utf-8'))[:-2] - expected_tokens = [TokenInfo(3, '"?????"', (1, 0), (1, 7), '"?????"\n')] + expected_tokens = [TokenInfo(3, '"?????"', (1, 0), (1, 7), '"?????"')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst new file mode 100644 index 000000000000..caf5d3527085 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-24-09-59-56.gh-issue-104825.mQesie.rst @@ -0,0 +1,2 @@ +Tokens emitted by the :mod:`tokenize` module do not include an implicit +``\n`` character in the ``line`` attribute anymore. Patch by Pablo Galindo diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index f7e32d3af9a9..0023e303b96e 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -123,6 +123,8 @@ _tokenizer_error(struct tok_state *tok) int result = 0; Py_ssize_t size = tok->inp - tok->buf; + assert(tok->buf[size-1] == '\n'); + size -= 1; // Remove the newline character from the end of the line error_line = PyUnicode_DecodeUTF8(tok->buf, size, "replace"); if (!error_line) { result = -1; @@ -193,6 +195,8 @@ tokenizeriter_next(tokenizeriterobject *it) } Py_ssize_t size = it->tok->inp - it->tok->buf; + assert(it->tok->buf[size-1] == '\n'); + size -= 1; // Remove the newline character from the end of the line PyObject *line = PyUnicode_DecodeUTF8(it->tok->buf, size, "replace"); if (line == NULL) { Py_DECREF(str); From webhook-mailer at python.org Wed May 24 06:47:14 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 24 May 2023 10:47:14 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E12=5D_gh-101282=3A_Enclose_BO?= =?utf-8?q?LT=5FAPPLY=5FFLAGS_value_in_double_quotes_=28gh=E2=80=A6_=28gh-?= =?utf-8?q?104853=29?= Message-ID: https://github.com/python/cpython/commit/b151660883864392c0e37972efde232b46a36589 commit: b151660883864392c0e37972efde232b46a36589 branch: 3.12 author: Dong-hee Na committer: corona10 date: 2023-05-24T10:47:07Z summary: [3.12] gh-101282: Enclose BOLT_APPLY_FLAGS value in double quotes (gh? (gh-104853) [3.12] gh-101282: Enclose BOLT_APPLY_FLAGS value in double quotes (gh-104752) (cherry picked from commit c43785192c97698a0217a680b30baae22106ed3e) files: M configure M configure.ac diff --git a/configure b/configure index 2b863be108be..21a3af145c13 100755 --- a/configure +++ b/configure @@ -8398,8 +8398,7 @@ $as_echo "$BOLT_INSTRUMENT_FLAGS" >&6; } $as_echo_n "checking BOLT_APPLY_FLAGS... " >&6; } if test -z "${BOLT_APPLY_FLAGS}" then - BOLT_APPLY_FLAGS=-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 - + BOLT_APPLY_FLAGS=" -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 " fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOLT_APPLY_FLAGS" >&5 diff --git a/configure.ac b/configure.ac index 786d3414eb0e..c5a79af1a2e2 100644 --- a/configure.ac +++ b/configure.ac @@ -2087,23 +2087,23 @@ if test -z "${BOLT_APPLY_FLAGS}" then AS_VAR_SET( [BOLT_APPLY_FLAGS], - [m4_join([ ], - [-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] - )] + [m4_normalize(" + -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 + ")] ) fi AC_MSG_RESULT([$BOLT_APPLY_FLAGS]) From webhook-mailer at python.org Wed May 24 07:11:37 2023 From: webhook-mailer at python.org (vstinner) Date: Wed, 24 May 2023 11:11:37 -0000 Subject: [Python-checkins] gh-104773: PEP 594: Remove the pipes module (#104848) Message-ID: https://github.com/python/cpython/commit/a4b7e9d1f812f2598ac9637d95e986c830bd451b commit: a4b7e9d1f812f2598ac9637d95e986c830bd451b branch: main author: Victor Stinner committer: vstinner date: 2023-05-24T13:11:29+02:00 summary: gh-104773: PEP 594: Remove the pipes module (#104848) files: A Misc/NEWS.d/next/Library/2023-05-24-11-45-22.gh-issue-104773.R0Br4-.rst D Doc/library/pipes.rst D Lib/pipes.py D Lib/test/test_pipes.py M Doc/library/superseded.rst M Doc/whatsnew/3.11.rst M Doc/whatsnew/3.12.rst M Doc/whatsnew/3.13.rst M Doc/whatsnew/3.3.rst M Python/stdlib_module_names.h diff --git a/Doc/library/pipes.rst b/Doc/library/pipes.rst deleted file mode 100644 index 471ae0dbc976..000000000000 --- a/Doc/library/pipes.rst +++ /dev/null @@ -1,103 +0,0 @@ -:mod:`pipes` --- Interface to shell pipelines -============================================= - -.. module:: pipes - :platform: Unix - :synopsis: A Python interface to Unix shell pipelines. - :deprecated: - -.. sectionauthor:: Moshe Zadka - -**Source code:** :source:`Lib/pipes.py` - -.. deprecated-removed:: 3.11 3.13 - The :mod:`pipes` module is deprecated - (see :pep:`PEP 594 <594#pipes>` for details). - Please use the :mod:`subprocess` module instead. - --------------- - -The :mod:`pipes` module defines a class to abstract the concept of a *pipeline* ---- a sequence of converters from one file to another. - -Because the module uses :program:`/bin/sh` command lines, a POSIX or compatible -shell for :func:`os.system` and :func:`os.popen` is required. - -.. availability:: Unix, not VxWorks. - -The :mod:`pipes` module defines the following class: - - -.. class:: Template() - - An abstraction of a pipeline. - -Example:: - - >>> import pipes - >>> t = pipes.Template() - >>> t.append('tr a-z A-Z', '--') - >>> f = t.open('pipefile', 'w') - >>> f.write('hello world') - >>> f.close() - >>> open('pipefile').read() - 'HELLO WORLD' - - -.. _template-objects: - -Template Objects ----------------- - -Template objects following methods: - - -.. method:: Template.reset() - - Restore a pipeline template to its initial state. - - -.. method:: Template.clone() - - Return a new, equivalent, pipeline template. - - -.. method:: Template.debug(flag) - - If *flag* is true, turn debugging on. Otherwise, turn debugging off. When - debugging is on, commands to be executed are printed, and the shell is given - ``set -x`` command to be more verbose. - - -.. method:: Template.append(cmd, kind) - - Append a new action at the end. The *cmd* variable must be a valid bourne shell - command. The *kind* variable consists of two letters. - - The first letter can be either of ``'-'`` (which means the command reads its - standard input), ``'f'`` (which means the commands reads a given file on the - command line) or ``'.'`` (which means the commands reads no input, and hence - must be first.) - - Similarly, the second letter can be either of ``'-'`` (which means the command - writes to standard output), ``'f'`` (which means the command writes a file on - the command line) or ``'.'`` (which means the command does not write anything, - and hence must be last.) - - -.. method:: Template.prepend(cmd, kind) - - Add a new action at the beginning. See :meth:`append` for explanations of the - arguments. - - -.. method:: Template.open(file, mode) - - Return a file-like object, open to *file*, but read from or written to by the - pipeline. Note that only one of ``'r'``, ``'w'`` may be given. - - -.. method:: Template.copy(infile, outfile) - - Copy *infile* to *outfile* through the pipe. - diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index cad4e9c50b69..0153b4550558 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -21,7 +21,6 @@ backwards compatibility. They have been superseded by other modules. nntplib.rst optparse.rst ossaudiodev.rst - pipes.rst spwd.rst sunau.rst uu.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 4ad68463e0b5..778ab28419ce 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1731,7 +1731,7 @@ Modules slated for removal in Python 3.13: +---------------------+---------------------+---------------------+---------------------+---------------------+ - | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`pipes` | :mod:`!telnetlib` | + | :mod:`aifc` | :mod:`chunk` | :mod:`msilib` | :mod:`!pipes` | :mod:`!telnetlib` | +---------------------+---------------------+---------------------+---------------------+---------------------+ | :mod:`audioop` | :mod:`crypt` | :mod:`nis` | :mod:`!sndhdr` | :mod:`uu` | +---------------------+---------------------+---------------------+---------------------+---------------------+ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9cf10196dcfc..62050aa01461 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -898,7 +898,7 @@ Modules (see :pep:`594`): * :mod:`nis` * :mod:`nntplib` * :mod:`ossaudiodev` -* :mod:`pipes` +* :mod:`!pipes` * :mod:`!sndhdr` * :mod:`spwd` * :mod:`sunau` diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 1d4a4ca9614c..a5549f4470d2 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -153,6 +153,10 @@ Removed `_ instead. (Contributed by Victor Stinner in :gh:`104773`.) +* :pep:`594`: Remove the :mod:`!pipes` module, deprecated in Python 3.11: + use the :mod:`subprocess` module instead. + (Contributed by Victor Stinner in :gh:`104773`.) + Porting to Python 3.13 ====================== diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index f121652ba51c..c05b8e5ef753 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -1778,7 +1778,7 @@ shlex ----- The previously undocumented helper function ``quote`` from the -:mod:`pipes` modules has been moved to the :mod:`shlex` module and +:mod:`!pipes` modules has been moved to the :mod:`shlex` module and documented. :func:`~shlex.quote` properly escapes all characters in a string that might be otherwise given special meaning by the shell. diff --git a/Lib/pipes.py b/Lib/pipes.py deleted file mode 100644 index 61d63b48d3e4..000000000000 --- a/Lib/pipes.py +++ /dev/null @@ -1,250 +0,0 @@ -"""Conversion pipeline templates. - -The problem: ------------- - -Suppose you have some data that you want to convert to another format, -such as from GIF image format to PPM image format. Maybe the -conversion involves several steps (e.g. piping it through compress or -uuencode). Some of the conversion steps may require that their input -is a disk file, others may be able to read standard input; similar for -their output. The input to the entire conversion may also be read -from a disk file or from an open file, and similar for its output. - -The module lets you construct a pipeline template by sticking one or -more conversion steps together. It will take care of creating and -removing temporary files if they are necessary to hold intermediate -data. You can then use the template to do conversions from many -different sources to many different destinations. The temporary -file names used are different each time the template is used. - -The templates are objects so you can create templates for many -different conversion steps and store them in a dictionary, for -instance. - - -Directions: ------------ - -To create a template: - t = Template() - -To add a conversion step to a template: - t.append(command, kind) -where kind is a string of two characters: the first is '-' if the -command reads its standard input or 'f' if it requires a file; the -second likewise for the output. The command must be valid /bin/sh -syntax. If input or output files are required, they are passed as -$IN and $OUT; otherwise, it must be possible to use the command in -a pipeline. - -To add a conversion step at the beginning: - t.prepend(command, kind) - -To convert a file to another file using a template: - sts = t.copy(infile, outfile) -If infile or outfile are the empty string, standard input is read or -standard output is written, respectively. The return value is the -exit status of the conversion pipeline. - -To open a file for reading or writing through a conversion pipeline: - fp = t.open(file, mode) -where mode is 'r' to read the file, or 'w' to write it -- just like -for the built-in function open() or for os.popen(). - -To create a new template object initialized to a given one: - t2 = t.clone() -""" # ' - - -import re -import os -import tempfile -import warnings -# we import the quote function rather than the module for backward compat -# (quote used to be an undocumented but used function in pipes) -from shlex import quote - -warnings._deprecated(__name__, remove=(3, 13)) - -__all__ = ["Template"] - -# Conversion step kinds - -FILEIN_FILEOUT = 'ff' # Must read & write real files -STDIN_FILEOUT = '-f' # Must write a real file -FILEIN_STDOUT = 'f-' # Must read a real file -STDIN_STDOUT = '--' # Normal pipeline element -SOURCE = '.-' # Must be first, writes stdout -SINK = '-.' # Must be last, reads stdin - -stepkinds = [FILEIN_FILEOUT, STDIN_FILEOUT, FILEIN_STDOUT, STDIN_STDOUT, \ - SOURCE, SINK] - - -class Template: - """Class representing a pipeline template.""" - - def __init__(self): - """Template() returns a fresh pipeline template.""" - self.debugging = 0 - self.reset() - - def __repr__(self): - """t.__repr__() implements repr(t).""" - return '